ntl-6.2.1/000755 000765 000024 00000000000 12377144456 012633 5ustar00shoupstaff000000 000000 ntl-6.2.1/README000644 000765 000024 00000001166 12377144456 013517 0ustar00shoupstaff000000 000000 NTL -- a library for doing numbery theory -- version 6.2.1 Release date: 2014.08.26 Author: Victor Shoup (victor@shoup.net) NTL is open-source software distributed under the terms of the GNU General Public License. See the file doc/copying.txt for complete details on the licensing of NTL. Documentation is available in the file doc/tour.html, which can be viewed with a web browser. For a detailed guide to installation, please see the appropriate documentation: * doc/tour-unix.html for unix systems * doc/tour-win.html for Windows and other systems The latest version of NTL is available at http://www.shoup.net. ntl-6.2.1/doc/000755 000765 000024 00000000000 12377144460 013373 5ustar00shoupstaff000000 000000 ntl-6.2.1/include/000755 000765 000024 00000000000 12377144456 014256 5ustar00shoupstaff000000 000000 ntl-6.2.1/src/000755 000765 000024 00000000000 12377144457 013423 5ustar00shoupstaff000000 000000 ntl-6.2.1/src/BerlekampTest.c000644 000765 000024 00000002360 12377144457 016332 0ustar00shoupstaff000000 000000 #include NTL_CLIENT long compare(const ZZ_pX& a, const ZZ_pX& b) { if (deg(a) < deg(b)) return 0; if (deg(a) > deg(b)) return 1; long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (rep(a.rep[i]) < rep(b.rep[i])) return 0; if (rep(a.rep[i]) > rep(b.rep[i])) return 1; } return 0; } void sort(vec_pair_ZZ_pX_long& v) { long n = v.length(); long i, j; for (i = 0; i < n-1; i++) for (j = 0; j < n-1-i; j++) if (compare(v[j].a, v[j+1].a)) { swap(v[j].a, v[j+1].a); swap(v[j].b, v[j+1].b); } } int main() { ZZ p; cin >> p; ZZ_p::init(p); ZZ_pX f; cin >> f; vec_pair_ZZ_pX_long factors; double t = GetTime(); berlekamp(factors, f, 1); t = GetTime()-t; cerr << "total time: " << t << "\n"; ZZ_pX ff; mul(ff, factors); if (f != ff) Error("Incorrect factorization!!"); sort(factors); cerr << "factorization pattern:"; long i; for (i = 0; i < factors.length(); i++) { cerr << " "; long k = factors[i].b; if (k > 1) cerr << k << "*"; cerr << deg(factors[i].a); } cerr << "\n"; cout << factors << "\n"; return 0; } ntl-6.2.1/src/BerlekampTestIn000644 000765 000024 00000011443 12377144457 016402 0ustar00shoupstaff000000 000000 267257146016241686964920093290467696047 [49837358131570447864817515087439013768 217790630152030295509630390043323452418 183007752636725657346015922031780246753 262113896575279912339769331241278344279 177558407200939953451023246629148421281 136929296553865076504681539657670073560 192415039389210093994081842103350165598 182557741530928548483637113503078591939 152312715846007778517225522567912229374 61070310616310966143036616435945529275 56882351798282916540663346247514573657 158686522480779859534523214608362876609 85210334586722150186842848782331419132 198362138483259282290069664523891695478 105962174491644106720737449885846770737 249033261315062656917484949663089856785 139280737583202876936726498752829998312 96203889545184151489078136782695324160 208694243930290456762944377328869542824 251198129775817736537493636046342370518 32491172002557837695014870030709955365 157057260026057739908648668261127013585 32158111277873531187646273497929686990 58023085641078573288671168992626772711 203352616803671819759251328642179414361 176832214306605225027954988995962853393 197751743759386172324631466360221889957 250675485398129152936547054273008945084 89802180792752320286820790825168446402 221927328217203245795479583872431482139 181867644367245155189096649430804155534 196573951588049184839338282394294640421 126494998583021765272120647086463689743 174657163006615797502644605616894054311 234672242556809736618320732618464101882 205348109319692361504021855702077801974 201480844443360756410435617763952548343 170821441145829211070253605577359112378 187298115367502536593622759425713052026 201353915199638771306766167529913744292 110056325175807519097151055510442724504 84674679789619373292653213867492283966 168108975031341360548972497299114799167 188785266690312084670451157982206333021 6919124922283999072938889546284835561 95172401022443537916304700401182513359 242656351122617045586289402040975850488 258917690731498966483992090617969273135 255172357998710172667686768952981848252 118175616249074875462815777656446629825 209369380640707258048170718089924020429 216746678547888281943927295868928862244 63169707116329105567261084639495637564 202333112949022656860592608187835800947 80435337513539361770944989701279792581 28559403271199376081807425371890436795 256861001114471080744832531110449193687 38657959213601984487225303100688777103 264329692965823772141881317913001435480 218475193420063453264724104126186468822 55233548185953383662963228863699064965 142847894615807036044593258566061501298 40776137890228920841990607606744773281 207391812963267976992797930441533817374 131427136606359893450088207506169771951 82054365866591169413120690376061966303 254634913083682101845032880368012778683 113001824664061224418685032691163656798 117833438072061069588705088985207648396 198178618302450682247100216569460586289 198381479150163198990715018490680028045 40108560518858431892450501419935817741 249439423887278332139791602557219952471 221966937421423130761062580294130357251 27490538843743647962500092623737267888 199032039511054771408483525115006232955 153374408545054543308974562742599189798 204441596188139879934847569435872573583 72511171850979613061537038035887332270 188055003891843700481760891626319067311 246942866306387063440530450313249487213 154432671448051407822509238106814497392 10269235724501453720265397111909271779 148857768429934113454368585111610769515 108297143766697999083231078069833743328 220532835954576708526395590637539965227 47023132625007027307413233669814369642 84333086497358423101905076861010297068 109923194851260709892302191788390844119 145532132551656120297402397944248638204 213830252095553517168726834522180278894 102749312273606281835206463742368919982 84543296032499431865178411848912028082 255842553711064592614706368471411701728 92792788881700092973313938762496041466 226246741492184645916217086335680308632 47398189106172181220565717959082348717 534841639268407919453412423169225929 227881612330362332482913814220965533258 20468583267376817360819899952174792253 144516395639654137625068920238408162625 23063430578963026866276768667282988723 78622647090193125396541826334521992292 264903205883946296353652606189457860631 73321233545830123884053316326108652224 224457856516455546437636685796583263125 89690091316250629374456315479480007830 187208222107636159370431203716381339929 171228087913280313688978034913595496145 65181480163363913025022929713156523521 260386206624679247021239706748428416618 233532508524755687017145839207222247623 104495928340502321945045270235830859361 142404893002257456916371093923595763470 70547706665310794838360176214164641180 250155930626141180499692089763382633396 173703133121986101552083136940445186732 101381348611023590273882716679386824878 52369949231407573392363550023930927779 164846348231869333212354656533341858054 167611977406913990206167373536253863095 44127887745906175987802 210066388901 458330 677 26 5 2 1] ntl-6.2.1/src/BerlekampTestOut000644 000765 000024 00000011743 12377144457 016606 0ustar00shoupstaff000000 000000 [[[72398276494209883607569001664095082443 117364489934900288813772748912639262763 1] 1] [[194885164668670801306433413055322420208 46460887933725801021646400328802766319 1] 1] [[265214480819444708594123279944559159830 135555755881205794630508718609541287286 44692727376424019667265698780467837920 105348873456947058075098215336964742926 200420383267665008124992677631949344009 175037957226154573788077864523554954164 198784363762937430133582236807030005417 189197625224350476857712002941357479808 123176502074239231605912049355403842408 173219197680757673164794465537096242604 82502246015727196418180291241544180842 252148878141517772614419588889223095499 222861768237293427164610320331139899060 145279042477655847402483626711031219727 87910557872715526777045607382277034643 142072596850302561207634759593757462627 71205756108575268517401216273026274651 12651078513331907405242158198817330707 160266113454553114847517104170780094187 195464879027759626684158522704705329638 176940293918687704807235877854468104601 256684763930845904420213250872082486979 190679352948270926135966349300610845388 180925218261056184334641860647804951138 69890985699528053281337128635751875924 249647620923101369642976296912944075845 105942913538075089762334334130653298694 3898562296566255216819318123346284574 96036249681148056555888770829972641770 116954586547181158405632648906791331155 156714696811280091319378172855548989363 20102049324529059757649901773837738504 242046209169075775000997868731143868307 153110660874477601229072252534180746483 262645300558512784314570152020176734087 170644937290658478142860569172821089079 236324059282643408066541233152180268668 91420241446920934270222801792817823163 221895909267925472012615501139074144107 65585860673582603802310418767748147371 175284970274766593398967509698077212527 264577434882178626916502171362966809724 248619213343209942390691463132907556843 48694357302037897882508173061369838915 7590271812997530261785510569226703355 41579865942640367934632794995077059110 25903764683100553843924000316062727206 208277694495623391365783965784035058862 20574104178269334275866063132729651833 32390265141750340906945023778238315879 48391540618880119406049654232187869232 68678876632229582296123624388982684769 50350996346028914093248748742495458871 104801543658718378265450948780789553345 170541167825831826486226694019149131735 191712035005915681570453205945152435115 171132197785251136981628932361511268322 94274910720002633503096975918879251922 131705134092713179690105683659114095235 39198110458547272415690420119622383324 46934920344877609024617702381518055784 23165921134083299943549996062416170591 28459767746923491203355891737619983167 259003325998562294815931954475285084505 132573405345042766236588923626423134760 125044589325274435507575739483784144221 143842666056873673875855062404427652880 77045649566194835393229740528339656886 230721416549574802093826739521838241759 136984872197606244217262196765704845330 179963548013928826293965633036986606846 81093794490723279885994296550509929282 175340915677491500317276597749413950329 57047311937998596889239670071739911078 78345967891418982524389386889543351652 93400063263712556706184675445068663367 180200784179611435611501496080960686407 135119048356203726778728767376260501672 10486454602716462586191022987435392902 266180484471226163583776411401032555923 177922567296382887995292645607281764774 147354638941110748901071777613832077504 11386236491379506830728620963094661745 42647393401281707520209780845057964211 560012345672962108635101650391927614 135105021891377379180374693260873457591 224760786679278206405412871787773939009 73961499887977539989001000821829880530 201511135175463460025181871183378346942 115951205938373310071143721922524848428 200405446663062724609631010980787818513 4084499686464546462830526469012407101 152724466051124045433884928207554220950 126901627861321624285024729051799564271 242367754280050045324139831677280684141 213094306936169441482299557482247052572 85651902354263777822663401884585899399 107061500515903509923074464269206283499 221594000868361748687063067883562138255 23369088685973206706623693970501448229 225855286644190676337782370996698625468 80297213561030314459788121000041822216 104375640259389070400243588809323828300 189446580253479282905484486251777171917 13339974796188630005869457676998089978 241064276410560038338723364620921385192 76395515368032998743463293241788398517 188914664855694160488405094145717027307 29475305348626328925169323294949894329 118126738456573750249388337944191859619 221689202784680185314494482532119456449 94812282609491148726311465288993793033 152692588155831901280608072033125732355 225123885569700674110694161715400402535 116499445366526195693200909257658932928 62753483122144112754233240781236179858 15444805687749127948434404171151371996 14095553723150444214265207378160628689 47449972008672602110053765929544594603 222342338045680629345204692875855824856 213944253857122075734729482547141604817 37079316985276538985773977257059183254 256448445640796358952644860664830285753 103431768147615597129500944049025666967 1] 1]] ntl-6.2.1/src/BitMatTest.c000644 000765 000024 00000002762 12377144457 015616 0ustar00shoupstaff000000 000000 #include #include NTL_CLIENT void random(mat_zz_p& X, long n, long m) { X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) random(X[i][j]); } void random(vec_zz_p& X, long n) { X.SetLength(n); long i; for (i = 0; i < n; i++) random(X[i]); } void cvt(mat_GF2& x, const mat_zz_p& a) { long n = a.NumRows(); long m = a.NumCols(); x.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) x.put(i, j, rep(a[i][j])); } void cvt(vec_GF2& x, const vec_zz_p& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) x.put(i, rep(a[i])); } int main() { zz_p::init(2); long i; vec_GF2 v; v.SetLength(5); v[1] = 1; v[0] = v[1]; if (v[0] != v[1]) Error("BitMatTest not OK!!"); for (i=0; i < 8; i++) { mat_zz_p a, x; mat_GF2 A, X, X1; long n = RandomBnd(500) + 1; long m = RandomBnd(500) + 1; cerr << n << " " << m << "\n"; double t; random(a, n, m); t = GetTime(); kernel(x, a); t = GetTime() - t; cerr << t << "\n"; cvt(A, a); t = GetTime(); kernel(X, A); t = GetTime() - t; cerr << t << "\n"; cerr << x.NumRows() << "\n"; cvt(X1, x); if (X1 != X) Error("BitMatTest NOT OK!!"); if (!IsZero(X*A)) Error("BitMatTest NOT OK!!"); cerr << "\n"; } cerr << "BitMatTest OK\n"; } ntl-6.2.1/src/CanZassTest.c000644 000765 000024 00000002356 12377144457 015777 0ustar00shoupstaff000000 000000 #include NTL_CLIENT long compare(const ZZ_pX& a, const ZZ_pX& b) { if (deg(a) < deg(b)) return 0; if (deg(a) > deg(b)) return 1; long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (rep(a.rep[i]) < rep(b.rep[i])) return 0; if (rep(a.rep[i]) > rep(b.rep[i])) return 1; } return 0; } void sort(vec_pair_ZZ_pX_long& v) { long n = v.length(); long i, j; for (i = 0; i < n-1; i++) for (j = 0; j < n-1-i; j++) if (compare(v[j].a, v[j+1].a)) { swap(v[j].a, v[j+1].a); swap(v[j].b, v[j+1].b); } } int main() { ZZ p; cin >> p; ZZ_p::init(p); ZZ_pX f; cin >> f; vec_pair_ZZ_pX_long factors; double t = GetTime(); CanZass(factors, f, 1); t = GetTime()-t; cerr << "total time: " << t << "\n"; ZZ_pX ff; mul(ff, factors); if (f != ff) Error("Incorrect factorization!!"); sort(factors); cerr << "factorization pattern:"; long i; for (i = 0; i < factors.length(); i++) { cerr << " "; long k = factors[i].b; if (k > 1) cerr << k << "*"; cerr << deg(factors[i].a); } cerr << "\n"; cout << factors << "\n"; return 0; } ntl-6.2.1/src/CanZassTestIn000644 000765 000024 00000011443 12377144457 016042 0ustar00shoupstaff000000 000000 267257146016241686964920093290467696047 [49837358131570447864817515087439013768 217790630152030295509630390043323452418 183007752636725657346015922031780246753 262113896575279912339769331241278344279 177558407200939953451023246629148421281 136929296553865076504681539657670073560 192415039389210093994081842103350165598 182557741530928548483637113503078591939 152312715846007778517225522567912229374 61070310616310966143036616435945529275 56882351798282916540663346247514573657 158686522480779859534523214608362876609 85210334586722150186842848782331419132 198362138483259282290069664523891695478 105962174491644106720737449885846770737 249033261315062656917484949663089856785 139280737583202876936726498752829998312 96203889545184151489078136782695324160 208694243930290456762944377328869542824 251198129775817736537493636046342370518 32491172002557837695014870030709955365 157057260026057739908648668261127013585 32158111277873531187646273497929686990 58023085641078573288671168992626772711 203352616803671819759251328642179414361 176832214306605225027954988995962853393 197751743759386172324631466360221889957 250675485398129152936547054273008945084 89802180792752320286820790825168446402 221927328217203245795479583872431482139 181867644367245155189096649430804155534 196573951588049184839338282394294640421 126494998583021765272120647086463689743 174657163006615797502644605616894054311 234672242556809736618320732618464101882 205348109319692361504021855702077801974 201480844443360756410435617763952548343 170821441145829211070253605577359112378 187298115367502536593622759425713052026 201353915199638771306766167529913744292 110056325175807519097151055510442724504 84674679789619373292653213867492283966 168108975031341360548972497299114799167 188785266690312084670451157982206333021 6919124922283999072938889546284835561 95172401022443537916304700401182513359 242656351122617045586289402040975850488 258917690731498966483992090617969273135 255172357998710172667686768952981848252 118175616249074875462815777656446629825 209369380640707258048170718089924020429 216746678547888281943927295868928862244 63169707116329105567261084639495637564 202333112949022656860592608187835800947 80435337513539361770944989701279792581 28559403271199376081807425371890436795 256861001114471080744832531110449193687 38657959213601984487225303100688777103 264329692965823772141881317913001435480 218475193420063453264724104126186468822 55233548185953383662963228863699064965 142847894615807036044593258566061501298 40776137890228920841990607606744773281 207391812963267976992797930441533817374 131427136606359893450088207506169771951 82054365866591169413120690376061966303 254634913083682101845032880368012778683 113001824664061224418685032691163656798 117833438072061069588705088985207648396 198178618302450682247100216569460586289 198381479150163198990715018490680028045 40108560518858431892450501419935817741 249439423887278332139791602557219952471 221966937421423130761062580294130357251 27490538843743647962500092623737267888 199032039511054771408483525115006232955 153374408545054543308974562742599189798 204441596188139879934847569435872573583 72511171850979613061537038035887332270 188055003891843700481760891626319067311 246942866306387063440530450313249487213 154432671448051407822509238106814497392 10269235724501453720265397111909271779 148857768429934113454368585111610769515 108297143766697999083231078069833743328 220532835954576708526395590637539965227 47023132625007027307413233669814369642 84333086497358423101905076861010297068 109923194851260709892302191788390844119 145532132551656120297402397944248638204 213830252095553517168726834522180278894 102749312273606281835206463742368919982 84543296032499431865178411848912028082 255842553711064592614706368471411701728 92792788881700092973313938762496041466 226246741492184645916217086335680308632 47398189106172181220565717959082348717 534841639268407919453412423169225929 227881612330362332482913814220965533258 20468583267376817360819899952174792253 144516395639654137625068920238408162625 23063430578963026866276768667282988723 78622647090193125396541826334521992292 264903205883946296353652606189457860631 73321233545830123884053316326108652224 224457856516455546437636685796583263125 89690091316250629374456315479480007830 187208222107636159370431203716381339929 171228087913280313688978034913595496145 65181480163363913025022929713156523521 260386206624679247021239706748428416618 233532508524755687017145839207222247623 104495928340502321945045270235830859361 142404893002257456916371093923595763470 70547706665310794838360176214164641180 250155930626141180499692089763382633396 173703133121986101552083136940445186732 101381348611023590273882716679386824878 52369949231407573392363550023930927779 164846348231869333212354656533341858054 167611977406913990206167373536253863095 44127887745906175987802 210066388901 458330 677 26 5 2 1] ntl-6.2.1/src/CanZassTestOut000644 000765 000024 00000011743 12377144457 016246 0ustar00shoupstaff000000 000000 [[[72398276494209883607569001664095082443 117364489934900288813772748912639262763 1] 1] [[194885164668670801306433413055322420208 46460887933725801021646400328802766319 1] 1] [[265214480819444708594123279944559159830 135555755881205794630508718609541287286 44692727376424019667265698780467837920 105348873456947058075098215336964742926 200420383267665008124992677631949344009 175037957226154573788077864523554954164 198784363762937430133582236807030005417 189197625224350476857712002941357479808 123176502074239231605912049355403842408 173219197680757673164794465537096242604 82502246015727196418180291241544180842 252148878141517772614419588889223095499 222861768237293427164610320331139899060 145279042477655847402483626711031219727 87910557872715526777045607382277034643 142072596850302561207634759593757462627 71205756108575268517401216273026274651 12651078513331907405242158198817330707 160266113454553114847517104170780094187 195464879027759626684158522704705329638 176940293918687704807235877854468104601 256684763930845904420213250872082486979 190679352948270926135966349300610845388 180925218261056184334641860647804951138 69890985699528053281337128635751875924 249647620923101369642976296912944075845 105942913538075089762334334130653298694 3898562296566255216819318123346284574 96036249681148056555888770829972641770 116954586547181158405632648906791331155 156714696811280091319378172855548989363 20102049324529059757649901773837738504 242046209169075775000997868731143868307 153110660874477601229072252534180746483 262645300558512784314570152020176734087 170644937290658478142860569172821089079 236324059282643408066541233152180268668 91420241446920934270222801792817823163 221895909267925472012615501139074144107 65585860673582603802310418767748147371 175284970274766593398967509698077212527 264577434882178626916502171362966809724 248619213343209942390691463132907556843 48694357302037897882508173061369838915 7590271812997530261785510569226703355 41579865942640367934632794995077059110 25903764683100553843924000316062727206 208277694495623391365783965784035058862 20574104178269334275866063132729651833 32390265141750340906945023778238315879 48391540618880119406049654232187869232 68678876632229582296123624388982684769 50350996346028914093248748742495458871 104801543658718378265450948780789553345 170541167825831826486226694019149131735 191712035005915681570453205945152435115 171132197785251136981628932361511268322 94274910720002633503096975918879251922 131705134092713179690105683659114095235 39198110458547272415690420119622383324 46934920344877609024617702381518055784 23165921134083299943549996062416170591 28459767746923491203355891737619983167 259003325998562294815931954475285084505 132573405345042766236588923626423134760 125044589325274435507575739483784144221 143842666056873673875855062404427652880 77045649566194835393229740528339656886 230721416549574802093826739521838241759 136984872197606244217262196765704845330 179963548013928826293965633036986606846 81093794490723279885994296550509929282 175340915677491500317276597749413950329 57047311937998596889239670071739911078 78345967891418982524389386889543351652 93400063263712556706184675445068663367 180200784179611435611501496080960686407 135119048356203726778728767376260501672 10486454602716462586191022987435392902 266180484471226163583776411401032555923 177922567296382887995292645607281764774 147354638941110748901071777613832077504 11386236491379506830728620963094661745 42647393401281707520209780845057964211 560012345672962108635101650391927614 135105021891377379180374693260873457591 224760786679278206405412871787773939009 73961499887977539989001000821829880530 201511135175463460025181871183378346942 115951205938373310071143721922524848428 200405446663062724609631010980787818513 4084499686464546462830526469012407101 152724466051124045433884928207554220950 126901627861321624285024729051799564271 242367754280050045324139831677280684141 213094306936169441482299557482247052572 85651902354263777822663401884585899399 107061500515903509923074464269206283499 221594000868361748687063067883562138255 23369088685973206706623693970501448229 225855286644190676337782370996698625468 80297213561030314459788121000041822216 104375640259389070400243588809323828300 189446580253479282905484486251777171917 13339974796188630005869457676998089978 241064276410560038338723364620921385192 76395515368032998743463293241788398517 188914664855694160488405094145717027307 29475305348626328925169323294949894329 118126738456573750249388337944191859619 221689202784680185314494482532119456449 94812282609491148726311465288993793033 152692588155831901280608072033125732355 225123885569700674110694161715400402535 116499445366526195693200909257658932928 62753483122144112754233240781236179858 15444805687749127948434404171151371996 14095553723150444214265207378160628689 47449972008672602110053765929544594603 222342338045680629345204692875855824856 213944253857122075734729482547141604817 37079316985276538985773977257059183254 256448445640796358952644860664830285753 103431768147615597129500944049025666967 1] 1]] ntl-6.2.1/src/CharPolyTest.c000644 000765 000024 00000000325 12377144457 016150 0ustar00shoupstaff000000 000000 #include NTL_CLIENT int main() { ZZX a, f, g; cin >> a; cin >> f; double t = GetTime();; CharPolyMod(g, a, f); cerr << GetTime()-t << "\n"; cout << g << "\n"; return 0; } ntl-6.2.1/src/CharPolyTestIn000644 000765 000024 00000002320 12377144457 016213 0ustar00shoupstaff000000 000000 [0394820 309072154 109014622 1426290 175222167 825171846 88106125 543013 726393158 718508011 224282105 670970394 84911920 856082243 51432313 356689413 487830678 743695336 929502 439479925 136123276 707988349 831373101 66679668 746727 540936511 114305132 82147118 380194841 79736700 862619239 676125089 510124380 35667584 474394435 720924125 724948 222793534 105330644 871564016 68412077 165794770 279048705 126777275 17627 174553324 851984080 873153773 495650905 188357106 289635478 760525082 90604 467949471 828574359 866977171 812328920 825671785 9758 640977503 35747401 791343 602111985 393648] [560394820 309072154 109014622 281426290 175222167 825171846 88106125 595543013 726393158 718508011 224282105 670970394 784911920 856082243 51432313 356689413 487830678 743695336 630929502 439479925 136123276 707988349 831373101 66679668 182746727 540936511 114305132 82147118 380194841 79736700 862619239 676125089 510124380 35667584 474394435 720924125 338724948 222793534 105330644 871564016 68412077 165794770 279048705 126777275 73317627 174553324 851984080 873153773 495650905 188357106 289635478 760525082 63690604 467949471 828574359 866977171 812328920 825671785 368289758 640977503 35747401 791340303 602111985 393652348 1] ntl-6.2.1/src/CharPolyTestOut000644 000765 000024 00000155306 12377144457 016431 0ustar00shoupstaff000000 000000 [190508694806967015998600611097132060049717118365016280475020799440937327406646942789463171342229692206347643711656823487561893705323611973115765000429375831263108569315225427694150247540246831153992507299992825439755817111538589609613023922678205180207300350411328634748456398347317769763113112532949991488988450573239123152557436015405152850660488623917857833818683001387193609953938476094742107938276333134954685460879041352353213523705745901290368321559046533980676310568693475940388053682248147969674444106923575773142801027102175343542579052985992474969967454917969163643940460819332006220647042696260091357235019028610323559379428816498125971469436220619879921223810882259943059156398587216631554149611899809727132305526391913730249737864692929996282208822321711506302712970006968799992644118563580707422065774467792905866650907789662026726695059010485690597774061864567960192738380217011200884878157520759920017356366290889818183668529815140973598202522753939144473600027992971354118778520924921276625945271355017006545810816893146727901309540633127638217572327583960024077147518348286178124206625881051474510793410494138927402297512333148160000000 5510370375206376125805735185537274993180811627757919519755287408102657543105514120792053265823597303123658199603190909569821147417926587591837948891619607615404159338429979309010981827777265483023527116617038416675735836718068782894703173068052932387089155053446282556998354357342954371353946291827882920830186259111039667082687772480659627704424961644441004621954251872383257999920305246693623623498482718299450630387944250424028179677314085650306231332277967061921960251729426061804857726399930059931907366410943776901370704889872998997777631140261117929980793431899765308093602311276420817885590340576896739344657734289639054912398163280271557909299828203587370332167866138589662124644838451869911270013194124015287901127671853661852442880293741916634440272968369900740132355610706928640899686635103468378085757505718584806093099415444501421862714784284070333433948596923713685684574641540702890150015865159237374688805375049432465077932740662557791642851660645069380471195882146186453681686664702908783838072092969407751326548494273380663918625448882464696110955357483705033360786105019870179686630400090123377232360917098071205836248722702336 76636285697827388747309150397897338703479382655435292390554714660407941511174746464243025647528622769737495338417763000019752933198203429069288208786893348291060629771936723001636718081554593978950514639343299849165764060314063003740717219445956162206615008145807100960233499022750960786803534436409840076666609990348072618173778799055867435553418661212328637044438515447861390096923942145452184550926103620714191992966658028523149438488617327736796164690205303611559851533348391220497893652311305086830636423146920281968022984997613739234215642701976964164397239787490393250734733620138901318869290768097670428843847479492870130488315826039236794818526738146932716621531032665547834525578389396835279873989042511968000540704297800489965929294381610645655637781300868741853833969598348341278121723340700947141766103901608611245230634594534138275745968582584616004535088835018595756746851357210313362093691247845116569117168912286575004344006357633865556011340608321685351516589956019986482228918514350139373609635120134296139491552111152715937110193382344029831207490105756020517515406659981844923071514299766843216132915342254701398327296 682967003344890835104695900793461228916913282023162349416019476885347047156759153830343120041870425125569604438946978617346346223802843129244409026989530580448709099715921025449151356852730096275479574615719078213208988161876991217023296146618565394073289073124848475354819462769506785090935269931460083937050792647715752262044025073338413934921518433111330878769086105978574924684859970370731689106411068075813771466717648400417984385910546076246317409340120988390231835922623872949359375373395547861053095973616176322399894174273765908103222264211747808396140882054612886289413912925004315543450775343461823364610689104041918562764276178075501439400697622053625550952618137968427279232226138077885052216249165524377571639876002893437253703273718596321975206629081443850727596346094491858960684321942142381936301394414333513107590064735382496422091136268562587050129410391248793338093640930328696656251923097684767440301807638687503824842067179628362144610969716679671925283856807610141684043053481248490183832573811408991949667380869760117396637297998369355376561865448872187244433527686282937515305111719666762008504477296919552 4396287874266350268417177805786841295493285845771288614320531722181450577440496198267540620122441281553812907400504909524660352843872107689903998501003247215720798299930569761579252919847263597017778263780200759304776124632551896764004200319773966307706700837585719362472911584420160829320074823113112187068424639830701017474825263597859572552083301841676783056997824812281207005222515987398155599961381284956593211460558976826936242990196571756335894460511674105502282700984315091337756595274747455563525695047962064436078517466962488134179515600566425940659015475067087631091550405699107099365563958969655433429595966567972539232512595888850734247448002102630529844063167928403354823170988961018692168827249173766875055077986870320850147504036659688993124424941419462548993704935179215624593583416622387732393558335009285828678194876074307762996487949549217902665276840258170080597450696368401354134918695158808862725965698566836610154549833757914692891695902811629791088761009326218529170961543557487512210617065814711103170567820807023070096232258273723831311098314998089425172517665091602134431378731762129472035179249 21975839272414395140361539785289148168737851601427458106777755540491334819163322484647244978641576412004122655167427242365378926150687855704244197490363755992292471167821947596597285923459298708017342763275484040196472357872457323212426003258309692000740218485926878522772170127883562943966756258953435551301344298636848316395708197448952847533805085919981476788000303763063749547614198262442705566581963433679537784550150274110413247581659422808793927285653952739466893622437618071127017592576972854442335113267274667707244651098414183394666701084263995550246669025925884806103308866095793683394213988768560031805699567081080363316032748368087823642161357731024813134467363964793281047599734182925994046660369640730321168593303294139003203933511829270132988039147532396132671420753632126315580576038889456326274419565551013232046578798578618873797907261992571005987755213987784888628036003990588206548067335221448237972961862770839037675891152426688093187411493332273636238909511476593797282376050324676361977699816044607823657737979943629751365692194020511409834121987811331317079116625509824147947161648994117662 90614572248167832815398901237692019368525145085533138287685444807567873204605246604398275364599214250950175235171627805701057597182975632869431126594165858643501966801330401701884178826293853784654266932084418159299910396757430868083130186649756193170672642494752192628065980129443480078681559872292550125041244266137297279861048796846169326664796602071039267580150457326682548667162241050100846792062281616565917920117176525496157042264079387008296747997513691112950993064961357912157542541361239544658084051215442219429376780912474018936426931476238924451921866695962822487292868699840533224902464369267076667572591038734279554702463167517642637118155796167154515207970256621250915178345320909915299152054879019436390822689493822916282165358794664029287244374521577173641509213361383304713851144993302120088461588930231691757002754227719102412898327883927285380172840945990247971689534806358922800882578508024879529511841393273052597976594405438110148788980182813122865554195573932864901904909286094707181763733741079778836930551780931164321209391340730494169796298921330443829194579510911833655576601377 328970398417249875437738673791810670683647177007669554639061977661129100259388636124853047280349180968995650521486117611261304774855877172118818503217976563637794662123745036086469964386605974339488969452314068670779496333555667260276057696519162720936386665699718862715372641593041230458364666891030299116596377056920968571888893465794425500091218841221526095522810974059764947932904726898749021756246707937422584947654173499250106585907320417442000646966083556296607788743563855449319383344414945991420349690655656572763836066709064607426306646832925531075519272224784344606184131358705975839652153843794680601129001228882668623998957850199335696114626372129092315495250157484480620506477204266405136218111512712589632928130561672876426318364373974128796119771175230813968549877506567434438125790847566327516518294857166955570644984229507908647723196006884389541854025643867101067179678490320518453668197131386782690931516841798901968731850277321174688014066857404664758976402868866557275703580522731564202058255775248697080239282936435654805413030583016332080024310102484631101698158062067490199 1127579186957279465567668413182166261397126766366319885142562182868033829423390009947792480046827709615996364865149656955177256175360655982981652377844755656703086872891547668751079735240226870806580504325683552641781613734598976127577230632147939492768120951488677479596772843739320350792156288111647654894320229252992971612171484642080125139314340876334784023575117675940955402037348660795174532129778527784638963525831806417148407590099717948311458840122301529476398574966897559165380798926543906149343707861656819996067396890665167537769521520650155177445335334404782275667914595436068084005414865156078561007411769443544001978569847632042119527015851991803584322700647043343678885335970712148283137252705043154445174772568964759581374098650514877175166730024379788369366185937637692589623967096975465827342905551004697669216024080226292024812174472626656605850289484314826519488201803952735942230029839337765567769407453010191965826318974242809590315145991767303399763633467299753793823335835788081811850780569472659902942011532595431085475913394407208321374000736048501106892346552196 3828041097219390857907082551067745839476775728326108881879204364051036739270222883898243519649048587642069576968281141303097991041018521880872948859074212972982480449636159997684984126299406495337515903672735412353899285441049046431315131720847467461635427950759940265793408225958463477923656798926652172053707784414886859466167575187298829948847616648829314671347189690358265482551663036686190713893382929400857167710163163729354824015596295132972609948785664123113633400305046225801228443620327395362882461723640091710316379011210504884717075728724641838344258079857344943803769697097560745957594234550289137121341427605700174589001506374718509179023501502389872884093440923152550892501817583961673278241805137409553957313416749430122047354932415388574412196293616806554972921398129524769926234010626224067096643334001194753251645415328660304032278529100608261378305772515847975694249308640869899779642831560727309583425352906457046981218535153118614520625245105811319924139353834363134046379556619709601106013471271498116343693680126950788286778727880803528173998527018709543211 12846134731688678874091515609227180027437690702746448213342751690753878562510042778660573488767873354769669317691187032722535030135303209764786747127868178272363478080136747815943752727880681013530676352679956461180005064025710332201101730891353638781103510027299392807972101297674408887762189593699894895525116998295886036859208784764517719293702188737006741979158231258249397710045725785608974164198068415408769382390899720139267750604996537552615497472442675629598714235521235200473357114765795449976837706509938246497769234249256837375183387716855184063918654748134789245470766987274600625684341809777905089658552539780640596719377160142093793100935591877956074240688187266602111532044043715224141229435638253334136063649115123041470933430553962665790743567847484538982628767295204492897880624550871686675533193752156303545638905826964767986887275149742469089443969949848597046642581030974447859327066316039701202403271834352137565019594158277845648681602629364580908320567325004601703035295876317848269027005261020499575466287921842640599487183076541840358945569793753 41046983192534522533335169525136765306600811060513966258767005515620968135643738818842371156102573321691144163061313175735289972587684800501673555777397097134195735202271088503178235858188882262649966998998275202228701215157055999496646719386034958002307593053418734615992027304115386834015123932695277057767984414997298159383099033467257898944764425338679791490906981961439153570377071417385946693210021092344133437630368644045821396458359968401212847680583808841391739885911779092086333396344701573836116255224700123293901585505971177624372765972351113536305140808608187662657753313060455900360496358254508194457882151721477763003798366482721585236424452141686305834178064765615407864281847488216470092971242615404371740176055518815045280121719735735059110329913104888812448649958627902271186994444227106172584304733521997451563549006785596680059304971930918971009039321422587031126996437792329230683473369797165351134164090806234697826881327259320681155748181192685414938903208953111115066829305023346231045250552876545675345461882235720979123913883979127988276 120369962019205430978689855404124372900212866215205222090358103895296148759231283753806402533034855572533338321434922099149748684298577825503701909946986150956281910695782020429702123379243351854028821131399252666599392432737132350839146686531554935267725091513381349351580172040351650497931963524146888590733767996958117308106252499763150598507713880560527810362266122786934877928749238115161454112628523538128520755120190021061256052736063390560151830042273317211547890404880184101664658895849948400163661998484100081456221309297572839442948890490150388950696172232131277679766687139834183139867099921122832197907908704608609633735919558382436288880044543333475800536136548586775667302671905517449576956106304601772228184771059609741256642232027139529888618405957065145938709716970881425409138086093981132615138744117012266121299183849581741411838861370187737459710513819502849521366609082597000809326957480876650619264281372978374209662648437206201048779834875669900827395300764841978960389991164340598542920725526398768753169985590889374335926101687132 317390868282092512891464159675406335576019420847475400634608645062826040654058734124506912818537056545680509611337511961726525747794642469756898737520592378000699701527041763678373366705001530040418950720376667599563076056319177069208904205784897373553098400914043787719673249113833234104384140216539976216768156998966282134713978459662799222559304232484057407495764809394124534082232804034009824219659054459163496283843498363231386225782200151257443027821289142021696055027740906917259641134142410147082043581149683419536913715176895243754905296910385301950887106149817372861377425734209581178617134139131298654961272698290194979185991461943128575413334064152617241077546842897682343096444192163319882020087557959980674925732863827537642715815108799502024302456279843243886904130287868777656227533467734880375316555864413697218999377364829108910069903340205165650328282705764500301481604737256903378796730728725738484527988676341816454744103887175989280705236795599534469956241089552933313845021568007821694409715810476520818750680515460794538701 747434245949570578181292635933035612072425856921900130057009004535428379144294535890529282308866690434029416449462106518118891815528994087749187724165985386180766935349891861990225450975205044879827016279791936496889423120682367069304178872753667685540685718210843403271559230208965801434195430782360915502656776511706673003940873844377653500618983242456154260750622937180099955007684065048805422469220861226201819945087982634678888815225200547750765376191063482272608383516266927895863769579892065256681776776572607399582887640357212125973987543818748772546033474374828025683421617731569870956841430428988314092633981559350133569702272073683016627343537428688065365050085741641035677907679956032228224919385238963916553657262288136056541558536871478861223374976391048721949942648127124373533717817331484205349704512261697486979839580483756001358055941617723657425578852084665416464178580793318854279381654927677862383599569513100273095147087971352329954986495290824735159974762698434222178803981416011999330180898763302215807446645423983 1573229387044305762810701712960729806419837957062370675243187252889663508622635279953927201928481514186795665445703580725453464896674494229451296953752915279032258877704866380340656463330520225616557456362548916196929799891892939772491827777453482562995342293736577079863986180605068401866298479779951383867420467993942838063897717911961821242956547279511050042672908226217000401726508158194050684966961607206726228989042465822012481387201661227837635268948627897540445353051617121609658117398950656618967708231227442021101460677583873814833561706174003930314667347819267409588490340674599298128875223335443745067282564160542254444421736070817445584293683064060596294818747936486825660644905498015073939646049793417694917491899903088730811553545967648558153695639996912855671927517014516169567623565359911684776740577788830188215200997801446988405027198937187633031620559718587346141186856087602712710548464323333040387186221593117079091042739689414270471754094931230742220271128440198059933290551778609649137642021409839835341117 2971907874675964671549636163311641138310784433581148857853989601197878243731153926191585920286210240130308181456314268777322887415707926752080313459518110385217099240288158920263313325284336482127032025866771153285721022236451893939337014509262983910116826065775258635967014804317466816241384669549178927805279837501266231783657632891911127980109553588901411240837224400758511748392930847870735759326294342860382213024404028808907082527919031793722454809035760904952040923541964548596397340536258852957923155006371208146939429957624594302691761080706402850196228052759672118684904575716923793865730777153497856557961915829536328784403195772125830995123543908831466409358326169617941315992792564523264795831787202945636171067425470986790499829208375227813497076628392374801256264013219847847492774280076711106157324861107587295447266262535339803381463965965567208942794446472646092479605887460884514525603020644973495711195391739803904863141835870139423068816249402847149849395676670827796577644471864843685875165512391560 5064909821165357427740898821451717695483108055661974648346952768086282713713977991223493769601282271687750969761106676324260369644937032721172647834053411318725230177794233414878578502338928635450773150648010274070822103872546340665820085840711611080101278821956202037290314619675514536838593067968292001669775958569667922188650775102898556223591120275182422470313223835900425198096918487898549701704968967220783964416498254761892847800809763841421585873530760927316572987006194345563486682545779693160483714677369544956000884966556507240737854220505337650937686902505200189197828056978701045101687081732223340117606938652988648936811684039194952857066228342412257685593198323699130618153473894239914572395221201296926905398262390985858080585938637932008742052196055693165012994572610160964714816378353854598776509896517550182301163413897772666255855095700964690826847498917941863456414161978632212826501333782135308398129733934965894915286694551486779552821180265732291733685086379205605191722998192110957403956 7828767009830700810388369063141949193420751739123318377350285208094444722839264691835113093683409279394949645185739005030906169030574921283791443596713367509939556017213885179560203881438566815434500182048823743283565445493587354351422037110268635787310017932175291423325892602135674703135362540541144218470209056419495913201930453347722254458068899007384878064501018319521751379289455429554535297973498236575176125054965632206281397848261712959523930365695279750709452415208308787835689489622345848219917675523136827822736522266753451186354365896484744861090836536726383646816188698383194003119464375915713644409725671105610925074762108160249835887512288062278145924382470580379804107140678433878773988384631708991519625587839063383419702854416884968909873970835677056393967804133890679337444480944086237950264371000505596585858499722997817806488955630844451588439580569708408393267601197550129600466932017502547950688881193144529246904777212900147052561850901135573398893616614699741101556383957623950 11027953267970630909581668660180702525710166604151574536502753399243127761293423114309112958488322904185983630490091220267741942170658761332386880130095095125454650258548732386949971262756160799788021777165408980659842648391794646086289598388046259464106068726431666480099215700127335686498548360567464330941830674129636791458860061050735620157440243918265288400504675977112486836207180247649786719533244850209726594494136352246399581221659532993631182557778926663600571479225800466743290189697181244525247031633354445948798654874558656880756208532232459180636883494595773559367258215888851553181102434280048138396322523918175525076990189255053378524235643013682609382833799813511022259200406106460958595849240623546953821707886505604197670807955128967476318436911542336553838732957091404606373712245908845082101961130007946949779338071620201378912417794748209692121465900173950168225648981276821997095473570661279993984450045156764233849452643862629607472731563542306471474302903443075714153251 14215486739027793420511165578454333171006241012338248278469606836641329694572118755154901761978190884111496362048095252966437617057161427406418816792709322460071529668593343197811895530152598553015381739667361824459870247720392325637964754930578154018241965363055967450169545586365546219350652302155348965159555621306871674496658449554070146439545286362289367632698431493166454093445340646511612334716195370512972747468588052163179510556106635160442750086203472053538549820142810860107094525701425913909439615499351035570540082895206847289472896654925023941294491351446694497959815443728727224324009034933737141512611116982444023575965025569408040259517538518590287903358851325480448948694520552199855814106858663947641612058623218782306271114793408923480312872755079110435546043520071063500723171656595429586296939369269064327899133290007363581662742491263636752135839628283615863673769087375503322975245350538096932985710004443787649203391804337656263776622567064736118244226973732102 16823213050615015574645995568954608900085789946415305967508645386810651530859610615616065900491935732108453200213727440212537069375711049806987407713976168906257897070162390521380099327284203646295831293800491535187702914650760875363281304319242813664884593086310791131029907755466417107264334129010572630304016513361342822611282389107467500492755313172690180294445757762601765851880161139661911942723832227015286754312110734894658235311290551881596546300232232079232112114203573243135529880770787769913441089596103299142135915478475807247938476721497374188525122484544188275396283889844535908320063459104525992961463986469133777633535151047812609187809171537464310826950489706486797722376935833050972156979834740358479035954635888238476246604558901239468585910262135004843451090056166810578799027304901579232798943645535248751413210862177964683750846679825599666126740068794727853373287568397275636482248940484195325918840105297298791284502764192171305684162491259529294673653 18320954461901719402603881313562377009401564547713869109606557402074913521520028052788231923042514752745365775977756102190024949830669781722226496457109336250918951619631113429495852595356739934223979784237958546063667407239316847406400854775481648161563380355501444518532682739440365957587538600264296062117645644496737763187940459929800354249562128637860956916219185440983067440511552333783961284247296332060225807120263868674689623688202286085250770772180092240965739044775498517677653674904084786480993044150365531892242656479038825840258257582394728294862433919812255124288857642814411260282234577545060045419677540238369142509478100014485181889715257019476786439121653908732334795199955735307484547356690458781965908744111000778635472303977725195451882719671045625635428640265745857452393288397994010335302724673974385975073182607618018347668468015370511487270543931601712325029537566884360257779823415403804835859406640065660402203302748500590476889654999464613 18385409832950842292089035324351512946826899541269027991837745030955087696606749499554272676240449719060302191374052313012228961211752592255454040803253928737727726936738557984533221126391304275252334846056219712825233396747961359388338667513684412893161471645863262625410801307258312354903026026916430547856903134400335537137322446299948000342910844080533731788372820688170314786054744569161064441938902823400044989834933543439709133316097990286158636499639698957989569897897124383299162476831249495725232812811854339884924944100062192642534375633185637177022263691127953716409675384018660772111790985733846554401935712519249677941862429341976348310688964181380802623013366514696908719963693895760771545029990937073407162270288935484888991334762556171132161513633483740446380732870015294065952020155266360129415940086393164737698848690808153653487667453028081404166887086250867887652949032793797062823425710167149144354011998616185500232294021330847431632410 17008368686579424815117496574809293086074091906200875734261281730368169164195677739766001360143768714784473902151810175411370635081445571404597299311781474000733427923317658126082790270740349416026378289196380418656876582825319625475320334244109049019451781381757740864569470806856406275621080946305670591307306547075555171887105833184718962111267685090470855597150670173338533858819359847058438281289423534012711457290519652603986913369081957608105566157957669255030315498607014574209543801014131332350946295450349277969967349865892774454263245568238179693220751733142631728467679344802120247528751504448876276152614430717161456971333106897257575781667430646516639116334471151927273284783410666849755608697720558583918495399810421101111906614668099978333887197260202329116346757235004274794176212046262703347146126953621416572973980481108294531192965065010744898054719398893718784524278177908301700443673056846445287329606464105566315392002815069485 14497357221394085077679237312382517578002131539538402880910299082998787709042282643500220112505747809065216942735684464616997436596456210707171052151784415284352187935359785690436471162612776127363308998022463935122728340083040297531001084255157199129246945105927264346962922853326392527116403492287489688967222443842522365269884180589847605493628438243304413060992524883279591916116066671251664293319928981990900420136274181830012817405939932318234246069976826210875774808355838848388505435874539066897840423165045159463734219064931537037265114304080824736247495960867958491212146793572355849601409543553437250406324206796721546889918077010261300607244788558933370878687400568722382690322971223165957096828081578491778577327999810476622354466437474110184276347443188730954255334078129098694864340233712442930823399200090719099929536740930334720676398853202875442324468926705209405408751029421831194880226547414912038750111502298256090787705 11369205940614014000511209341577104029139488813173928331165498102870062495615440412257343209295222692145740554547698411460718303239702377282132942984199801799048218477384755039954678522458399884694232182445364912027847114296811679348753838355473877576486648933425751325474378559329111296939828399878140649232150509379939212677131781032777176621493759781596708530888631687056736526355368016552676962231642953990908159704289702837351384595540574238088840254312196958632615287990872838099525132185584492653092229927581707431087835167658843829150031565608952061507519076993785076894776269923554651122387223532126518498109540321249751015323838004828985545179954344807681348589906471132409371576933969260625224070366669064689270369805478575119218070905111170095895365973741280569798649044505099063614867202572623694159831195823552529727198410671569056999383625843172119910889677028868744020860940676245854774959414866894188679675540644808 8184062434084091394962964843593603316635093530124292322517090443544531236393298689685854309670172660565195086967622398146628199959805961989300832190913900545951427121390544583722608062709704546689438940255432472297411829811994559208033004406483896540829932788946481933639848337863109713945483367335781335446931451625787771255071554306486025140044088404264862605362224110340698078767469783017133610874638771519302470345725128541447838809207062900290887964987309476327566189512266756113277905755207677892498922391151701604013059740001819713839827782451813907298281741186538488709114921032319443156997145350082754502785876921286166903106119125028253825880919239580124639103680943342932647665075820573240134269153059065639476637714675717376761411995139839244376239097568049127858577704968915499546972617299408212797077429745039519482273112174563321383380927156073675624553783074335045777880227373810704280398098443462711993836 5389665418118209000150519862758619702702796716527799183600217088520085003361602674992050943645314440105358346422312246816067105629738926364766520405849742807008110767254147665307597187958527051701200399865105214953893098414205292010616649329263312571541320981727215265893721318130542296957693112538916687699081307013502135884389833463076038609849713484163551834819122712718864775957427327052042642814585212056970675632794405380133936940619450338630092411739268407371099262951149642545583595282475626616290120777761678216367683507644309481321145955426684522604512781010945370392583330116177300449116818932610304255222506528552743766566836759151866937469480186772134336875955173266552776403672329112371317331509117947821249203157603581222864165325076403875057916007597248467667028651028975273998568213379299277468391054995596096089292454364381624186969883639445634841936025267327493697865842458752172772996435862085 3232653104105455965050963542144126174511394533404564441108024055494741938394025072191419617891117522318008347422011443414486128926583676768742567007693881344559331041118197192829056527517271092721789130219541733513936739042965284759338723988528222746197269437531287255281996931728692008497213985933191802690390832782941807565667827008827828868019579423203780580537598640335227507128786558318060894469586086822701421529196632338118637909214697798999651374849527946699078947574696434595717566197730108886278141589462144014534988130710310332989219299501490949224020558620508281843033139627563754250706198433133911650961955418863017030131341023979926769082692194917419036004919044502376249416391626435775606521801272070180851738672399053066070664843687291626156237856416982665263302877820820635441117202379057295745807639971171790511110931335841251926185678766926850270138494171674298460969125856781225969804 1755247756793686037125732490059066277910149489025762834423145527432874025739125761941884492016061674022498025924511047596727422239038863131551670688610872058060738734000130507330666577046705837339130587397738963347954858660279717092215258144293548814421824751222931009512925509851666913374542449219620575212195972582798148250455192265371033912726180462100509079204886961746688451125175946298567953600218569930391908288832637786607099475856298774219287831317970501988231013389902222737281322164185181956360231747553828359498403106268362761178716230325560725400079538201401283334159116328057723717712307983348645400306259579201934549460399437162109646898477258632812280913813011696409598483985085790316679828522616690442288464185933265109991939372296309035691635903011421813463672199183154795640198865944109898522581573392715087750824944127153132074420403208172603619731015375948038328909949014997 855621346364583049651755757607034401608668601171035526615008394183360755976485046768332488472377521462437364624135706102913777896567219718258475968028581700716259853832867443620941557577913585507181981361217796323205229031158670411041206954610619447718306264994164037535022654187355050703716437296185335231206453055446869816323210990145998431922720366570959844305532141814946224854843672630182857817452557220708598197801656646734241181374309484500522597228251315609896556566380393728225284222435505582578592393838413269337311559191470804917715216536067471935181230227349219608219734884284241922718295241751292323143328651782377247442476747500839364622386507047792218289360952428688327744070211928954466048783528260472603016655380845396132147940531970315730714754079360586586841816873554225103294532336956078035854777578637392107725698094217917066263206726726753744938807983333850597407 369941957363852037053003410279474816391823722932690003175756528860045519249130968063544770941634391185834542616036146391891044901572694190660680392733079223643729457064359195610897759651304773059153335869333214535732770720091854494611367353084848345054530099749073829447108865619686992745378043158361669578481905536152613241868659072845113634748784650047173389926736945234966353579225402522626336486310504123400013885107478372476734699239691660562215943834658902176561797467065736993357030303383988109473321081011325270133620538522029945607924384180926482975698638977662198216859849847588248148419376879584793000801386469829651374306597297108837725900777097461546848814007352002160044746856465558350965300431977568087647992315521995815262220437569368388155784246104231391449094792974954412991788482382355036302105284200682137186308411972361148628078939929605525616329130486764 139191364598100843671027168761130115333739203230073508584504049198713306948029606668367340592877421569262202328711352214631816344333430888224866663927910750217690398198507767286579692931128957428406466870713547237180753804673266321549300865385850018747167487230201326536136239330735653833069283919924711009354326646524735118602093950463534501810069560814698094813381528415549430024065315782636001023528948712921233203403275760464752945553398567810045911741183985712636733519308837258429584395999947098335342825835755617783240120577928324385395355601072972532493189303029050906187213598549002054867041009615131670995094676076847869555668748313657507176520813190907440336547182478133230201744715454258846238282811591909788614229538626699301214779199384582376920251846275459729250954320869202310577206597462674216996364687134766803137799019145507774282641931338193917126 44043562205733313414036828936504004429701054515845180285704927397182696140832887668786783975143554314666650588109907209444296723436732454131038103698094256184337863472429705445108750422844212892443517056326891764058203238993453983475342072912089462318310151640603493879178234343106906687646639974006265050741182575773918097627209932573998215394455430637451684558340227666732733171871174929978825049679206392052615486072747164309491396263119932669229470239722979076614818030839492587001718829636040617460890209483650534065684646884090968592356749997899187177334375897501229529442050888804562993595168864954254807250313656769086998073348710010793613307590002059463649318882670792705438035408867873165807303747666006673443131430948061577880104663642859799643744511302365497772748115064157215074175620549173005771474650437986127476366721735402899582825084713951 10861925002847327504320075403706795824019456223819973379272382447081129018235199666959659023101727367034539163597036405501200542617696994122772564647317696022147087009445291067309079115069929701338735350181801540429672590867240921627765049456452565474988868946933539776659454688256934520331273598832585642384750571654311572378032155149569838977608824214339423539102699201456694781585735937483863277218369590758105449347258392434502820444874497444771764310267081910137499708886201563652713494352196135379091471828692479382107370857606520827572904448137920679562258643533068128646856366248786885383763721493680392869952650819064642319983515151091744763609383560764830606666131134898471563533720399420844110910329565129960194288603446857171570761459348579411157619041698371464753094573881938944871956336061796983442128009603721161442952701445988490157 1594581635580909688870856131856948873962233789118578503093090414701998756676627323762619896703146499751113203432773544027609214366525969481917365329825852362231228051320747319565091520634757918269736022465030862748060849821127992742435418007246838382166242470327041621175989946906399383164995926127975797364033844659359519114943964391260672768238689425130122121072958719857430584745068854835057254870452296437218413852584338623949321798215333032181452173022958032143969953469954141519096247566523741119877846927660963667626122580477250091180649734659844292484949135918505832341910904689615744589748276674654430762667515177051483238717292311936381077164382595142828724182034867085752129370517700853572698774700025513525951609734112270450530335313883451375743271723233505227684663080786799962266443744364148697199454509544369192067795068620 -175258330374288488217699780681056007790738018516419452281991217832654531725817746986685120805050526934206221214211141521852994927206528251631399712058678982392880699800227124440195696214823380916708167445310792263345031242143035676279592625475734248832441286065902794254642514509741620998597884565902881353097461921842322070870984529159229514060165919622238464454116474141063130936752984696976799921351467288696273318318430019354280625161000802741257300306815204221600289221276550160895249928480353445064342116960056581099307365863716994163846551720672990602923358299428092665607545231959644829152413704506424911051622320036052874090548354320033672129426624281831899775321139548164347517142958538427511252378549150217840856725285327334555207840270205721245932505325761823123705947260438597139285994868809917490844945144025467690 -220204516996925692407481639318962275158355359698005005318968831105137877410318035105710030735253493203113614601148492718480669119594955222926330988813747084051194096829288602013708139413490389065268147594635456948867658605504940394238031555482960370191602547657627988580473271317223440356283286912868992645933201703098438403232137920212420959440102724896369844165067242271981986193800359091094747723345076794962221197090724157544666059314055602239994576519447991895833036047648279835490528709218893463307393510253353796421833052938499596293567284485949691751840926801159600011504013566712863640442505163583444721673287818969800667583958363492414161365095498214335337281791062974362643892979140568974220436080857130413612179269433508941820057605917648593877126906070657521089338116118571692083335137346253597230363346438 -86736665632678925155482178717541416902076376005607891408754495900348933434918513209452724010018685361893158041473663225587808925011797029588521260149269601655264376023270221929857106249729817265899694017319158207730930109639129622351016832288730019468523759267204415540775380151255429425512565935792592185965233296489721362856086319211357984593146960452637758443160166637910243405020664850087829521695097428554200043291734159717457440793421662838516158714294447522963772443831263641844249855189329155555845332410144343086066556665296069125595886804982098096438335788033789366633479851394765637333769728445267065432985566657279853389925618818844008343107578319219160786523354188227450128473210990504657882345063523456224912915046059727664646559655991260080589840205997564008010527878595560007930655715317990862 -21582126454742306667993456149556677980675932460298650535328848994746168325095862852666722458536329447597423387096751009305244842139050184544491450038967368144228011746022914115583645360623692331233474989474489219444393742965914046539434679463380651421037041943699498012845273895029251517240309503539746153134122836376598573102967018125553483751216696097816100791852880103103911552601264050283041915993619118558454428361434079044285011654871484945504053877664789720457201070079729484136519080360281111860909422248778061447745643765587425823404328107356657353938906970458620401013459131295171413389624086947025266759645994382891917066435893359532835153676706612710486528253286986244761712486266844971524920224154894618138915830104817136858848835666377534542360360110300083222617164486932381133489689581 -3197721395912341565564081952412110136169530860919163386385656007202973837007705327433023312125711351763473924016018786188937755919484674858599014596439712903164844770941217866141250736344714983164806546715253297791739899663831078378960721000334785698452304134226379392593908714462220788715616932619290014117079613611578414674308820766751225609804210768585733858466066057240133880231960864180798374206349802727313893774585143539099322978308588247355508151954504889114732631366814096556279917706062023211143064458274960070737668337702316425759599067738690845954429429400298407857211499431969609899228498434622943215486709416512227495363888797264000251869126601212793734657197459434337040578441217069635718989402007332910889176409302675400938019591258921490266883491293314586761456215738961770 -25183123559183134423074018635524921832567265127033408066598519830668308800738590152159316536479462511856139052375940167019153352366410191569916455774974730936481936472407740689794453537159299477945394874218179716458088007817339589177132979600490924502475782964795739644166657770467923215193227627376893261006656721851888476838139947219545442917759649093849334569809615727763573119590799216988467863818520639405700972431656022214085849172788952250025843472304147527886472940563732646744681254020329574575681719685485214262576685737122105672170725913417889623770432626301778650002211771426799598581241698478530425796305941118354222097953096626148205867114509728845372477611897334418262194839862537661129415586620561992889051163087412367496939111184741348290053889630495170354284007 128275949551782491640474118889911607242774013921143288004195427385429753191316410621073680915032415002991246233227241685218661767649500833260019371026766929922077186190252090680590646808375568580923518388358580405630116044119446285151876735370994962224616003501372549492788514039684921712846322649930896678422844654726772099788678741997475287649384944306743050933126902428578594909351375933898610844399632943765799134480756749732150738875295939401328991932923118218026009444193306285323722921890789771119859125621720604794898536055719867467868551264006568797001394242368280603685003713685417075488634011839908567853979278206769732648122467235571817039665159929122289138505819901539058492237967047125526640957265744234349635955895518407341265018302997163824746454137938087 36963842051408455627078292326095346501246419691467820566043752654928260360635708519143675203535094266715469760304060224887034201056737938410041473238542080972330131276773138012859711976027293161650646753000063680283470851169614128001621029560032089647000121540728734034873216463172295549679743717552505757877424913087495693058992361715922344628253564214783533834574720935823745285134657287539006424710364955973555231817000324626220956550772246888359548080627256851944674224116575128363053447942251208263767154007379582934196511400853751069963626767352734759344696048841379510765400102007519095595958932603531254720925841290118885854413489406727653366745404051980293900871756737680821341752735389489963057142251700893290170349570982879373958040232204173023894597 6067174578807453882753508695539020923333859968628303403913263562280670905602102213232710017631552907573770753069068140679475637462246560687301384947860220017158514402385174162671478980346080076597495562440866421626583532005762468447785804806628204738514111291246171469726298201141779388725308164318995081658226104112654075090713565816719599937473161020844843072726765709967526710443567524770323628072478886987184690619390671630875830952507603589427492242929410704976261817552061744654577645234599656211610253715579260456079722291995428674862563113864722845696773528951755788870714311116850396597345170291180807201764893656551450911123228743957132553672671394174588032604926396747714948205481344701433412957837221543194473981990173538847582486737301020 971164695550327316892471881277319230144861081825771285644418561121126514102955689748783732656538341192704824708237150063888076727774611503864966179200318939765919288445046521087555430815379597081937522609887476758129473089655827989487053701225651356542513908590686236171081594017781764761922710349346758377262798118275462154489349177944578221743389445540203506895642378539922840587871907292652558453453396357065517291921665634437090215929395048200343232386724384404583333781856076099664543319224848254642268353089301170089910494152967988433817567975947425876339410081317280834758550575869803559163798201156301489358203554822339031417391872906622726932181112253772995176180540797206282250073555909994274582396693822760802046170444942349140186 305036345493182155889442536292403071932596904420670668853502291563573867944598082511166761027895898173116934410911879913377548692099530873229032000817703467966997420724171955656509974496220898794905850355504313531829000951395618367904698857322853686129408450855805854071328499658844029561336767988651095243219847939247053250383854294500676536313935416993391926170132383451904184245262833764118599919155947685509575938361073495014692445254191349734304706389836339450591131002258675833002573374737502780762133276227409467670512009376094428722486750470394353067572548145747953124406467507224507612572529561059009136195017360664320871069052010795988350844840031450055643345848625572356540106608016932772566377206894261963399408707535429 105402147299284393801684646885778765742279178573992233031002910205250604702107223611864499918268527819101366742356007311005598768213571349766642491482728851958450950455889076721535783401002573368065986641078538028177544079941158139701344311765223277908415309351243081916785925470763744013483181045308661510512983799198957649602467883671699837397899465611265192162955058717050114297847549743385238281013700095022129633406711965279543685618083033571213158068909888120832409670101576348978811101537536208970395785467601852766952819049221485815628398517759178058517844029811060975065473131245800169534764075588719469992424624467622166627042982349012632687637915493827861315497693792261057017521680719980397862367373442917876157 25690485425700007333327111291046118052916546194109933954523067798738017855304967811892753709170039580388138276001812699286681159645069291618895891194879761696331727008600641934194473897886852528388560036713296401415074448604856009511906586657616465393600319522201499868805163005338376243350208867769783685669787198200747184429863674508841940316235553259068361994071128057351734893274960785298347081660660264238009720132244399784201277754062818527274311389411709867520460740661039284659109334041614417751085450050575155730149368510175650199046168852037071844173108903183316159364494461747307840277224000732804339394664231823372983684233671675576111529458692852486624912591483861819847132408468500128390390412482138 4215035667590888985965337359443737702195499617955407573077454563146784318779137203129821443296887722633551646953717495161745778610526621162333698225795054973314855581534019375834217718972908143471154846977571546017208423085406558162928278706853427103802761450898397243477928296062723848690389563178829255707841336335359415879160397344049578440289746047145057551995762998797567233587941639801361974253344177437179996074137443886617174425826822831268913377654925421417599260409139402113644684201977541552066007144688581988784173586755471581570836991346570105975945420711503849529541929295904156542683598760758845679378157072396937034110306179362927719659230904628961645530501360977522978808476694302943186 462608017710741149518921076515242367264310594099722535292736461315143127358867450486911423197949754642022766376343537286573284946456631788802043092001043896546292343099970117513140142876413958588930953599662628736745369506823323897452022806104104529802623340126278463345791040740606201163943262041386643332415085548334817258827802340131096308637534109003534454046336053946567998799673728380561979967733281395234989365130219066756264394109321296110934236015777796862896750313519753357650032471553283593689556428033365906555050953469040246556394965449213751121321069122824472412896675102149973952890085685970772980198278212100194335225120047097292109798954577716767576673399096865805426031898042 33862882529009830392485750866401109291648756085239885192082193097784920731593510260850294819451992370540561827534054561043033181886121065508178168097047466348896543655968913775469625023261852734567755690444784377082618901195121097163060014104094528589150920034706346712588776891700145293759544057581161523708488868539894989826251069867715958740770359882727101057333241529220124806976175891772510013657016401004102493186345636955722434001726286775167696494812419825444677061717883293199341538009742231099116825607061048095514686072084597278370412671931651845336784138496241689057151288722793849241157333200359325678533457807666714016815119119891017483729637924628747757394881277636790 1814623801974185696815411432306974014379062647175798499062528227782363002203191819942324519164433161232052472621761280070112514159919420240010712015103508983852372125429523943794433421628338145728876227573271925890034546001131071085439503633266645106075112295601727385107254180910165696906145047683869744641314125436224088096228900107268787766673078208658527478859567891322851448775940551764542001214799552683090377894121653548550575556075535747002343835038737644780867590842510832150540594815550414392332097232034612397903028036182050628308867653849432243505136662631356743179732676539609289709606155493542338238043241358032059032628463146842515700175757168778764095505759 93249888791181405042891390110774057102972740421065529154532451790004315096467048152350846217767211853115221918973072905637280639319499388476067438107304005045618477850818111196816958030142369907861726827052730264000569007382147991186409984517351604436769447197567185458368327875073308764506295090352637281036797615844448188127999213812845697180008086762047306094725568426355832344785271436502705237563126481219955894227622900528094243798610227925703776440230934671798963120546661856209134853604493722945315746084805142400631303978633284704971131134077611735198494799656712080010887074787301599408554520182158518438151437286098561879378410661311904076531922059185 4921498129852006424675299227573952821415882781331655892547799121843146815123947125603369893485756274753305528741917211894425572123308839699198568100362792179918425427995889493742458117705487858667254313174540216219309981972579082976319232928821327039892861057638179204340332660957287682233833005671999449095166127905075871387601986746761580173192664891901026731422751457459655514767954157000108433632026130871403579293221376313661255899621749906507629683182995716794782056017691100468715575369671957055745623421358122499170675579034750975916470271385931509184453519776648405650846194058985391901895227982621183162123025473842137674656349700426683056077 201272902562305689472571200491331851750049636933880578899333598076293964505742493042459180484126457126465401121797451596202908612946695380686396377033841585914389410302477301705112170287889865975851157757507465549323652763901840790205622628817939616400535635536652521657953857053611322588643586675183084699607388843166404226187657419153219853333625020688501210708293131524312769920565161689113511055648748532848818271016123653266692893441555288882689645026034714316432372128195031585720729197776036330109543487202131022997674917997849083896635639725036480827904589680949947237809251437137288956412469527468501734114310918240063291480050930942 6074751253304373699478103005423767194392460180178532242779132131883134798971251952194610961512672663543035654127756153712450507211561368973571976634207783355252804686544103676265001237260184773446824873437506138389881580498386927743109268036309633256751542644893511555286815487627956463069829692824237568007690960531273076445032010133947772936218555810889901230346272520955630280919825571309963348627906976862989869796455699119995006635298335538115452044779862172192986061031087449594487565989656917008256321642347817336596876445523851568976128441660664521879336687329733154120379435756686684095884126156330120727152201024121141435 158835640368624927032590567603298033578619460428181240275271178311247955906385358780880609108729731593000528649866256208791406940775600121819889914361157014596934714258355297904117710616353860489019083482117241921698807099414430612049481575726358558043601754835057019630102310430472592841252337908017889440767202384995675110755961647212986318461061788135296343800480157889647383498289820679293341354940262895884389598393484839276117181543909642716707954164229246657614251709668652420572710512949807247063044678349724511089981459422690779865347519696887457564045446080141772939950269568858082012591313957710183996464958422 3378902776872134909204839634350780570489386444602833200454760900258461158456475968767786638826676577991767426735542388159200737328011394812485955461262633296784485901814533654752799406903518798599048703026651458655257379291725908577613016050003151556791844209730414928304386452743655025491000998238763687307956696603617748086915536390338655047635126787848262872245644469285183252398652508297220725721995236789120114906732141512842760857593190120638372023923729622526452382862969080559959232688153460133906800190053367105284950075055827365166620172993694924414174980373672898385726820481538485431659006278194509 43079331259939515919275698578804185620986197244696798415016495720873670933657463215743464320826822818217043520103056534209916056157195395750471704735369170458016194728611156362683682500685550935485395203593729702769779759594200935064821306591638627011883484686976790112753212915600441815632077904449113748453399259468531763936142962291681638398372605510439393259145855884510266583260056334357613740785660705739276425104145786006056312697160438032838601633621767509204695962293044418377847996849526662006253108210889296421165933617690710605289828221283228905818261545639312850768818457519140627933059 241888549947281780453970332376533021011282816110362728271203139436475765057942802071196872840393868465027289459959410799788461175668613254139063157050636058392181269139232404141461880298738058796474652008228390097224085674472117318668135699123548934145057351803730650123864459215458336646869134720211474335685153578049826170902230696097090172541924249742742735455798580881018087903927097407092457336479159013029800043877603400653137762357381820397447743848915397214280255912384053813197361790665976579382707258006965027976397355870442671717523377265419561146645361069308842409716414749823 2376666192959846633516107374330794714748296292371435769889972320797571626802118600704583172570991283874821908434105402149381098559830077967475461633717911514260338342247661573203110589842201645894704836171721825311983421771649377974425053594782235622798898959134633315987735133144574981207375842994980940751142886625727144663673518413109414933454784015023169517143545340341136893308618175231432552370076990743951870797931924001487930023505152696548269229638467144136238737326349883098595437180422242838214426859842155775740707758296424184218989209744806567739431156071 12224062625832648183516693488530135118514258747173591610235394106191837482287498065840699381079070193230023620339082954952758518319905977223914718987561206209653761576001047130961967535872674537183498320220994771834545529715371523489357329178329639953948515526053154981117517445196850102059032579570738873131904056879673688661280476002767416938718011459524318277612243153293359296829432754457534753162164415110718998005028639349072782744247477763832792261907563795101315208763137730846936640573388864436242175078215481286793261658163010047075816510 1] ntl-6.2.1/src/DIRNAME000644 000765 000024 00000000012 12377144457 014416 0ustar00shoupstaff000000 000000 ntl-6.2.1 ntl-6.2.1/src/DispSettings.c000644 000765 000024 00000004326 12377144457 016214 0ustar00shoupstaff000000 000000 #include #if (defined(NTL_STD_CXX) || defined(NTL_PSTD_NHF)) #include using namespace std; #else #include #endif #define make_string_aux(x) #x #define make_string(x) make_string_aux(x) int main() { cout << "\n\n"; cout << "Basic Configuration Options:\n"; #ifdef NTL_STD_CXX cout << "NTL_STD_CXX\n"; #endif #ifdef NTL_PSTD_NNS cout << "NTL_PSTD_NNS\n"; #endif #ifdef NTL_PSTD_NHF cout << "NTL_PSTD_NHF\n"; #endif #ifdef NTL_PSTD_NTN cout << "NTL_PSTD_NTN\n"; #endif #ifdef NTL_GMP_LIP cout << "NTL_GMP_LIP\n"; #endif #ifdef NTL_GF2X_LIB cout << "NTL_GF2X_LIB\n"; #endif #ifdef NTL_LONG_LONG_TYPE cout << "NTL_LONG_LONG_TYPE: "; cout << make_string(NTL_LONG_LONG_TYPE) << "\n"; #endif #ifdef NTL_UNSIGNED_LONG_LONG_TYPE cout << "NTL_UNSIGNED_LONG_LONG_TYPE: "; cout << make_string(NTL_UNSIGNED_LONG_LONG_TYPE) << "\n"; #endif #ifdef NTL_X86_FIX cout << "NTL_X86_FIX\n"; #endif #ifdef NTL_NO_X86_FIX cout << "NTL_NO_X86_FIX\n"; #endif #ifdef NTL_NO_INIT_TRANS cout << "NTL_NO_INIT_TRANS\n"; #endif #ifdef NTL_CLEAN_INT cout << "NTL_CLEAN_INT\n"; #endif #ifdef NTL_CLEAN_PTR cout << "NTL_CLEAN_PTR\n"; #endif #ifdef NTL_RANGE_CHECK cout << "NTL_RANGE_CHECK\n"; #endif cout << "\n"; cout << "Resolution of double-word types:\n"; cout << make_string(NTL_LL_TYPE) << "\n"; cout << make_string(NTL_ULL_TYPE) << "\n"; cout << "\n"; cout << "Performance Options:\n"; #ifdef NTL_LONG_LONG cout << "NTL_LONG_LONG\n"; #endif #ifdef NTL_AVOID_FLOAT cout << "NTL_AVOID_FLOAT\n"; #endif #ifdef NTL_SPMM_UL cout << "NTL_SPMM_UL\n"; #endif #ifdef NTL_SPMM_ULL cout << "NTL_SPMM_ULL\n"; #endif #ifdef NTL_SPMM_ASM cout << "NTL_SPMM_ASM\n"; #endif #ifdef NTL_AVOID_BRANCHING cout << "NTL_AVOID_BRANCHING\n"; #endif #ifdef NTL_FFT_BIGTAB cout << "NTL_FFT_BIGTAB\n"; #endif #ifdef NTL_FFT_LAZYMUL cout << "NTL_FFT_LAZYMUL\n"; #endif #ifdef NTL_TBL_REM cout << "NTL_TBL_REM\n"; #endif #ifdef NTL_GF2X_ALTCODE cout << "NTL_GF2X_ALTCODE\n"; #endif #ifdef NTL_GF2X_ALTCODE1 cout << "NTL_GF2X_ALTCODE1\n"; #endif #ifdef NTL_GF2X_NOINLINE cout << "NTL_GF2X_NOINLINE\n"; #endif cout << "\n\n"; return 0; } ntl-6.2.1/src/DoConfig000644 000765 000024 00000014770 12377144456 015046 0ustar00shoupstaff000000 000000 # This is a perl script, invoked from a shell # use warnings; # this doesn't work on older versions of perl %MakeFlag = ( 'WIZARD' => 'on', 'SHARED' => 'off', ); %MakeVal = ( 'CXX' => 'g++', 'CXXFLAGS' => '-O2', 'AR' => 'ar', 'ARFLAGS' => 'ruv', 'RANLIB' => 'ranlib', 'LIBTOOL' => 'libtool', 'LDFLAGS' => '', 'LDLIBS' => '-lm', 'CPPFLAGS' => '', 'DEF_PREFIX' => '/usr/local', 'PREFIX' => '$(DEF_PREFIX)', 'LIBDIR' => '$(PREFIX)/lib', 'INCLUDEDIR' => '$(PREFIX)/include', 'DOCDIR' => '$(PREFIX)/share/doc', 'GMP_PREFIX' => '$(DEF_PREFIX)', 'GMP_INCDIR' => '$(GMP_PREFIX)/include', 'GMP_LIBDIR' => '$(GMP_PREFIX)/lib', 'GF2X_PREFIX' => '$(DEF_PREFIX)', 'GF2X_INCDIR' => '$(GF2X_PREFIX)/include', 'GF2X_LIBDIR' => '$(GF2X_PREFIX)/lib', ); %ConfigFlag = ( 'NTL_STD_CXX' => 'on', 'NTL_PSTD_NNS' => 'off', 'NTL_PSTD_NHF' => 'off', 'NTL_PSTD_NTN' => 'off', 'NTL_GMP_LIP' => 'off', 'NTL_GF2X_LIB' => 'off', 'NTL_X86_FIX' => 'off', 'NTL_NO_X86_FIX' => 'off', 'NTL_AVOID_FLOAT' => 'off', 'NTL_LONG_LONG' => 'off', 'NTL_SPMM_ULL' => 'off', 'NTL_SPMM_UL' => 'off', 'NTL_SPMM_ASM' => 'off', 'NTL_AVOID_BRANCHING' => 'off', 'NTL_TBL_REM' => 'off', 'NTL_GF2X_NOINLINE' => 'off', 'NTL_GF2X_ALTCODE' => 'off', 'NTL_GF2X_ALTCODE1' => 'off', 'NTL_NO_INIT_TRANS' => 'off', 'NTL_CLEAN_INT' => 'off', 'NTL_CLEAN_PTR' => 'off', 'NTL_RANGE_CHECK' => 'off', 'NTL_FFT_BIGTAB' => 'off', 'NTL_FFT_LAZYMUL' => 'off', ); %ConfigVal = ( 'NTL_LONG_LONG_TYPE' => undef, 'NTL_UNSIGNED_LONG_LONG_TYPE' => undef, ); %Variable = (); foreach $arg (@ARGV) { if ($arg =~ '^(-h|help|-help|--help)$') { system("more ../doc/config.txt"); exit; } if (($name, $val) = ($arg =~ /(.*?)=(.*)/)) { $Variable{$name} = 0; if (exists($MakeFlag{$name}) && ($val =~ 'on|off')) { $MakeFlag{$name} = $val; next; } elsif (exists($MakeVal{$name})) { $MakeVal{$name} = $val; next; } elsif (exists($ConfigFlag{$name}) && ($val =~ 'on|off')) { $ConfigFlag{$name} = $val; next; } elsif (exists($ConfigVal{$name})) { $ConfigVal{$name} = $val; next; } } die "Error: unrecognized option: $arg\ntype \"./configure -h\" for help\n"; } # some special MakeVal values that are determined by SHARED if ($MakeFlag{'SHARED'} eq 'off') { $MakeVal{'LSTAT'} = ''; $MakeVal{'LSHAR'} = '# '; } else { # sanity check for libtool print("***** checking for libtool *****\n"); if (system("$MakeVal{'LIBTOOL'} --version")) { die "Error: bad libtool ($MakeVal{'LIBTOOL'}) -- try glibtool?"; } print("***** libtool OK *****\n\n"); $MakeVal{'LSTAT'} = '# '; $MakeVal{'LSHAR'} = ''; } # special GMP variables $MakeVal{'GMPI'} = '# '; $MakeVal{'GMPL'} = '# '; $MakeVal{'GMP'} = '# '; if ($ConfigFlag{'NTL_GMP_LIP'} eq 'on' || $ConfigFlag{'NTL_GMP_HACK'} eq 'on') { $MakeVal{'GMP'} = ''; if (exists($Variable{'DEF_PREFIX'}) || exists($Variable{'GMP_PREFIX'}) || exists($Variable{'GMP_INCDIR'})) { $MakeVal{'GMPI'} = ''; } if (exists($Variable{'DEF_PREFIX'}) || exists($Variable{'GMP_PREFIX'}) || exists($Variable{'GMP_LIBDIR'})) { $MakeVal{'GMPL'} = ''; } } # special GF2X variables $MakeVal{'GF2XI'} = '# '; $MakeVal{'GF2XL'} = '# '; $MakeVal{'GF2X'} = '# '; if ($ConfigFlag{'NTL_GF2X_LIB'} eq 'on') { $MakeVal{'GF2X'} = ''; if (exists($Variable{'DEF_PREFIX'}) || exists($Variable{'GF2X_PREFIX'}) || exists($Variable{'GF2X_INCDIR'})) { $MakeVal{'GF2XI'} = ''; } if (exists($Variable{'DEF_PREFIX'}) || exists($Variable{'GF2X_PREFIX'}) || exists($Variable{'GF2X_LIBDIR'})) { $MakeVal{'GF2XL'} = ''; } } # copy %MakeVal and %MakeFlag as is into %MakeSub %MakeSub = (%MakeVal, %MakeFlag); # copy %ConfigFlag into %ConfigSub, substituting 0 for off and 1 of on %ConfigSub = ( ); foreach $name (keys %ConfigFlag) { if ($ConfigFlag{$name} eq 'on') { $ConfigSub{$name} = 1; } else { $ConfigSub{$name} = 0; } } # special logic for NTL_LONG_LONG_TYPE if (defined($ConfigVal{'NTL_LONG_LONG_TYPE'})) { $ConfigSub{'NTL_LONG_LONG_TYPE'} = $ConfigVal{'NTL_LONG_LONG_TYPE'}; $ConfigSub{'FLAG_LONG_LONG_TYPE'} = 1; } else { $ConfigSub{'NTL_LONG_LONG_TYPE'} = 'long long'; $ConfigSub{'FLAG_LONG_LONG_TYPE'} = 0; } # special logic for NTL_UNSIGNED_LONG_LONG_TYPE if (defined($ConfigVal{'NTL_UNSIGNED_LONG_LONG_TYPE'})) { $ConfigSub{'NTL_UNSIGNED_LONG_LONG_TYPE'} = $ConfigVal{'NTL_UNSIGNED_LONG_LONG_TYPE'}; $ConfigSub{'FLAG_UNSIGNED_LONG_LONG_TYPE'} = 1; } else { $ConfigSub{'NTL_UNSIGNED_LONG_LONG_TYPE'} = 'unsigned long long'; $ConfigSub{'FLAG_UNSIGNED_LONG_LONG_TYPE'} = 0; } # special logic for WIZARD_HACK $ConfigSub{'WIZARD_HACK'} = ''; # some extra logic consistency checks if ($ConfigSub{'NTL_X86_FIX'} + $ConfigSub{'NTL_NO_X86_FIX'} > 1) { die "Error: at most one of NTL_X86_FIX and NTL_NO_X86_FIX may be on\n"; } if ($ConfigSub{'NTL_GMP_HACK'} + $ConfigSub{'NTL_GMP_LIP'} > 1) { die "Error: at most one of NTL_GMP_HACK and NTL_GMP_LIP may be on\n"; } if ($ConfigSub{'NTL_AVOID_FLOAT'} + $ConfigSub{'NTL_LONG_LONG'} > 1) { die "Error: at most one of NTL_AVOID_FLOAT and NTL_LONG_LONG may be on\n"; } if ($ConfigSub{'NTL_SPMM_UL'} + $ConfigSub{'NTL_SPMM_ULL'} + $ConfigSub{'NTL_SPMM_ASM'} > 1) { die "Error: at most one of NTL_SPMM_UL, NTL_SPMM_ULL and NTL_SPMM_ASM may be on\n"; } if ($ConfigSub{'NTL_GF2X_ALTCODE'} + $ConfigSub{'NTL_GF2X_ALTCODE1'} > 1) { die "Error: at most one of NTL_GF2X_ALTCODE and NTL_GF2X_ALTCODE1 may be on\n"; } ###################################### # all tests pass -- generate files ###################################### # generate makefile open(MFILE, "< mfile"); open(MFILEOUT, "> mfileout"); while ($line = ) { $line =~ s/@\{(.*?)\}/$MakeSub{$1}/ge; print MFILEOUT $line; } close(MFILE); close(MFILEOUT); # generate config.h open(CFILE, "< cfile"); open(CFILEOUT, "> cfileout"); while ($line = ) { $line =~ s/@\{(.*?)\}/$ConfigSub{$1}/ge; print CFILEOUT $line; } close(CFILE); close(CFILEOUT); print("writing makefile\n"); system("cp mfileout makefile"); print("writing ../include/NTL/config.h\n"); system("cp cfileout ../include/NTL/config.h"); ntl-6.2.1/src/FFT.c000644 000765 000024 00000067715 12377144456 014225 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL NTL_THREAD_LOCAL FFTPrimeInfo **FFTTables = 0; NTL_THREAD_LOCAL static Vec FFTTables_store; NTL_THREAD_LOCAL long *FFTPrime = 0; NTL_THREAD_LOCAL static Vec FFTPrime_store; NTL_THREAD_LOCAL double *FFTPrimeInv = 0; NTL_THREAD_LOCAL static Vec FFTPrimeInv_store; // We separate the pointer from the Vec, to ensure // portability: global initialization of C++ objects // can be problematic. NTL_THREAD_LOCAL long NumFFTPrimes = 0; /************************* FIXME: in a thread safe implememntation, we need to do a lot of work so that we can share common tables across threads. One problem is how to represent the tables FFTPrimeInfo and FFTPrime (we can ultimately get rid of FFTPrimeInv). Option 1: If we put an absolute upper bound on the # of FFTPrimes, and allocate space for these tables just once and for all (the upper bound can default to some constant, and be dynamically adjusted at the very beginning of execution), then we can use standard double-checked locking to grow the tables. This means we need 16-bytes per FFT prime, if we are careful. If we allow 1MB of space for these tables... This means up to 2^20/16 = 65536 primes. Each prime gives us 50 bits, so 3276800 bits, divide by 2: 1638400...so we can do ZZ_pX arithmetic with p up to 1.6M bits. That's pretty good. Option 2: Represent as 2D arrays, which we can grow dynamically, row by row. Advantage: don't need to allocate all space up front. Disadvantage: array references now more expensive. Option 3: Dynamically grow 1D vectors, but keep thread-local copies. This can be done, but leads to other complications. I kind of like option 1. We still have to get rid of a few references to NumFFTPrimes which are lurking in the code. But it's not too bad. Another are the FFTMultipliers. I can also allocate the outer vectors once and for all (this comes to about 400B per prime, and so at most 400*256 = 100K). Then use double-checked locking to initialize rows as needed. *************************/ long IsFFTPrime(long n, long& w) { long m, x, y, z; long j, k; if (n <= 1 || n >= NTL_SP_BOUND) return 0; if (n % 2 == 0) return 0; if (n % 3 == 0) return 0; if (n % 5 == 0) return 0; if (n % 7 == 0) return 0; m = n - 1; k = 0; while ((m & 1) == 0) { m = m >> 1; k++; } for (;;) { x = RandomBnd(n); if (x == 0) continue; z = PowerMod(x, m, n); if (z == 1) continue; x = z; j = 0; do { y = z; z = MulMod(y, y, n); j++; } while (j != k && z != 1); if (z != 1 || y != n-1) return 0; if (j == k) break; } /* x^{2^k} = 1 mod n, x^{2^{k-1}} = -1 mod n */ long TrialBound; TrialBound = m >> k; if (TrialBound > 0) { if (!ProbPrime(n, 5)) return 0; /* we have to do trial division by special numbers */ TrialBound = SqrRoot(TrialBound); long a, b; for (a = 1; a <= TrialBound; a++) { b = (a << k) + 1; if (n % b == 0) return 0; } } /* n is an FFT prime */ for (j = NTL_FFTMaxRoot; j < k; j++) x = MulMod(x, x, n); w = x; return 1; } static void NextFFTPrime(long& q, long& w) { NTL_THREAD_LOCAL static long m = NTL_FFTMaxRootBnd + 1; NTL_THREAD_LOCAL static long k = 0; long t, cand; for (;;) { if (k == 0) { m--; if (m < 5) Error("ran out of FFT primes"); k = 1L << (NTL_SP_NBITS-m-2); } k--; cand = (1L << (NTL_SP_NBITS-1)) + (k << (m+1)) + (1L << m) + 1; if (!IsFFTPrime(cand, t)) continue; q = cand; w = t; return; } } long CalcMaxRoot(long p) { p = p-1; long k = 0; while ((p & 1) == 0) { p = p >> 1; k++; } if (k > NTL_FFTMaxRoot) return NTL_FFTMaxRoot; else return k; } void InitFFTPrimeInfo(FFTPrimeInfo& info, long q, long w, long bigtab) { double qinv = 1/((double) q); long mr = CalcMaxRoot(q); info.q = q; info.qinv = qinv; info.zz_p_context = 0; info.RootTable.SetLength(mr+1); info.RootInvTable.SetLength(mr+1); info.TwoInvTable.SetLength(mr+1); info.TwoInvPreconTable.SetLength(mr+1); long *rt = &info.RootTable[0]; long *rit = &info.RootInvTable[0]; long *tit = &info.TwoInvTable[0]; mulmod_precon_t *tipt = &info.TwoInvPreconTable[0]; long j; long t; rt[mr] = w; for (j = mr-1; j >= 0; j--) rt[j] = MulMod(rt[j+1], rt[j+1], q); rit[mr] = InvMod(w, q); for (j = mr-1; j >= 0; j--) rit[j] = MulMod(rit[j+1], rit[j+1], q); t = InvMod(2, q); tit[0] = 1; for (j = 1; j <= mr; j++) tit[j] = MulMod(tit[j-1], t, q); for (j = 0; j <= mr; j++) tipt[j] = PrepMulModPrecon(tit[j], q, qinv); info.bigtab = bigtab; } #ifndef NTL_WIZARD_HACK zz_pInfoT *Build_zz_pInfo(FFTPrimeInfo *info); #else zz_pInfoT *Build_zz_pInfo(FFTPrimeInfo *info) { return 0; } #endif void UseFFTPrime(long index) { long numprimes = FFTTables_store.length(); if (index < 0 || index > numprimes) Error("invalid FFT prime index"); if (index < numprimes) return; // index == numprimes long q, w; NextFFTPrime(q, w); FFTTables_store.SetLength(numprimes+1); FFTTables = FFTTables_store.elts(); FFTTables[numprimes] = NTL_NEW_OP FFTPrimeInfo(); if (!FFTTables[numprimes]) Error("out of memory in UseFFTPrime"); FFTPrimeInfo& info = *FFTTables[numprimes]; long bigtab = 0; #ifdef NTL_FFT_BIGTAB if (index < NTL_FFT_BIGTAB_LIMIT) bigtab = 1; #endif InitFFTPrimeInfo(info, q, w, bigtab); info.zz_p_context = Build_zz_pInfo(&info); // initialize data structures for the legacy inteface NumFFTPrimes = FFTTables_store.length(); FFTPrime_store.SetLength(NumFFTPrimes); FFTPrime = FFTPrime_store.elts(); FFTPrime[NumFFTPrimes-1] = q; FFTPrimeInv_store.SetLength(NumFFTPrimes); FFTPrimeInv = FFTPrimeInv_store.elts(); FFTPrimeInv[NumFFTPrimes-1] = 1/((double) q); } /* * Our FFT is based on the routine in Cormen, Leiserson, Rivest, and Stein. * For very large inputs, it should be relatively cache friendly. * The inner loop has been unrolled and pipelined, to exploit any * low-level parallelism in the machine. * * This version now allows input to alias output. */ static long RevInc(long a, long k) { long j, m; j = k; m = 1L << (k-1); while (j && (m & a)) { a ^= m; m >>= 1; j--; } if (j) a ^= m; return a; } NTL_THREAD_LOCAL static Vec brc_mem[NTL_FFTMaxRoot+1]; // NOTE: maybe try COBRA for BitReverseCopy? see: // Towards an optimal bit-reversal permutation program // This is more cache friendly. // However, on some tests on a fairly old macbook (circa 2011), // the contribution of BitReverseCopy for k up to 18 was // pretty small...at worst, about 10% of the total time. // So this may not be very pressing. static void BitReverseCopy(long *A, const long *a, long k) { long n = 1L << k; long* rev; long i, j; rev = brc_mem[k].elts(); if (!rev) { brc_mem[k].SetLength(n); rev = brc_mem[k].elts(); for (i = 0, j = 0; i < n; i++, j = RevInc(j, k)) rev[i] = j; } for (i = 0; i < n; i++) A[rev[i]] = a[i]; } static void BitReverseCopy(unsigned long *A, const long *a, long k) { long n = 1L << k; long* rev; long i, j; rev = brc_mem[k].elts(); if (!rev) { brc_mem[k].SetLength(n); rev = brc_mem[k].elts(); for (i = 0, j = 0; i < n; i++, j = RevInc(j, k)) rev[i] = j; } for (i = 0; i < n; i++) A[rev[i]] = a[i]; } void FFT(long* A, const long* a, long k, long q, const long* root) // performs a 2^k-point convolution modulo q { if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { long a0 = AddMod(a[0], a[1], q); long a1 = SubMod(a[0], a[1], q); A[0] = a0; A[1] = a1; return; } } // assume k > 1 NTL_THREAD_LOCAL static Vec wtab_store; NTL_THREAD_LOCAL static Vec wqinvtab_store; NTL_THREAD_LOCAL static Vec AA_store; wtab_store.SetLength(1L << (k-2)); wqinvtab_store.SetLength(1L << (k-2)); AA_store.SetLength(1L << k); long * NTL_RESTRICT wtab = wtab_store.elts(); mulmod_precon_t * NTL_RESTRICT wqinvtab = wqinvtab_store.elts(); long *AA = AA_store.elts(); double qinv = 1/((double) q); wtab[0] = 1; wqinvtab[0] = PrepMulModPrecon(1, q, qinv); BitReverseCopy(AA, a, k); long n = 1L << k; long s, m, m_half, m_fourth, i, j, t, u, t1, u1, tt, tt1; long w; mulmod_precon_t wqinv; // s = 1 for (i = 0; i < n; i += 2) { t = AA[i + 1]; u = AA[i]; AA[i] = AddMod(u, t, q); AA[i+1] = SubMod(u, t, q); } for (s = 2; s < k; s++) { m = 1L << s; m_half = 1L << (s-1); m_fourth = 1L << (s-2); w = root[s]; wqinv = PrepMulModPrecon(w, q, qinv); // prepare wtab... if (s == 2) { wtab[1] = MulModPrecon(wtab[0], w, q, wqinv); wqinvtab[1] = PrepMulModPrecon(wtab[1], q, qinv); } else { // some software pipelining i = m_half-1; j = m_fourth-1; wtab[i-1] = wtab[j]; wqinvtab[i-1] = wqinvtab[j]; wtab[i] = MulModPrecon(wtab[i-1], w, q, wqinv); i -= 2; j --; for (; i >= 0; i -= 2, j --) { long wp2 = wtab[i+2]; long wm1 = wtab[j]; wqinvtab[i+2] = PrepMulModPrecon(wp2, q, qinv); wtab[i-1] = wm1; wqinvtab[i-1] = wqinvtab[j]; wtab[i] = MulModPrecon(wm1, w, q, wqinv); } wqinvtab[1] = PrepMulModPrecon(wtab[1], q, qinv); } for (i = 0; i < n; i+= m) { long * NTL_RESTRICT AA0 = &AA[i]; long * NTL_RESTRICT AA1 = &AA[i + m_half]; t = AA1[0]; u = AA0[0]; t1 = MulModPrecon(AA1[1], w, q, wqinv); u1 = AA0[1]; for (j = 0; j < m_half-2; j += 2) { long a02 = AA0[j+2]; long a03 = AA0[j+3]; long a12 = AA1[j+2]; long a13 = AA1[j+3]; long w2 = wtab[j+2]; long w3 = wtab[j+3]; mulmod_precon_t wqi2 = wqinvtab[j+2]; mulmod_precon_t wqi3 = wqinvtab[j+3]; tt = MulModPrecon(a12, w2, q, wqi2); long b00 = AddMod(u, t, q); long b10 = SubMod(u, t, q); t = tt; u = a02; tt1 = MulModPrecon(a13, w3, q, wqi3); long b01 = AddMod(u1, t1, q); long b11 = SubMod(u1, t1, q); t1 = tt1; u1 = a03; AA0[j] = b00; AA1[j] = b10; AA0[j+1] = b01; AA1[j+1] = b11; } AA0[j] = AddMod(u, t, q); AA1[j] = SubMod(u, t, q); AA0[j + 1] = AddMod(u1, t1, q); AA1[j + 1] = SubMod(u1, t1, q); } } // s == k...special case m = 1L << s; m_half = 1L << (s-1); m_fourth = 1L << (s-2); w = root[s]; wqinv = PrepMulModPrecon(w, q, qinv); // j = 0, 1 t = AA[m_half]; u = AA[0]; t1 = MulModPrecon(AA[1+ m_half], w, q, wqinv); u1 = AA[1]; A[0] = AddMod(u, t, q); A[m_half] = SubMod(u, t, q); A[1] = AddMod(u1, t1, q); A[1 + m_half] = SubMod(u1, t1, q); for (j = 2; j < m_half; j += 2) { t = MulModPrecon(AA[j + m_half], wtab[j >> 1], q, wqinvtab[j >> 1]); u = AA[j]; t1 = MulModPrecon(AA[j + 1+ m_half], wtab[j >> 1], q, wqinvtab[j >> 1]); t1 = MulModPrecon(t1, w, q, wqinv); u1 = AA[j + 1]; A[j] = AddMod(u, t, q); A[j + m_half] = SubMod(u, t, q); A[j + 1] = AddMod(u1, t1, q); A[j + 1 + m_half] = SubMod(u1, t1, q); } } #if (!defined(NTL_FFT_LAZYMUL) || \ (!defined(NTL_SPMM_ULL) && !defined(NTL_SPMM_ASM))) // FFT with precomputed tables #define NTL_PIPELINE (1) static void PrecompFFTMultipliers(long k, long q, const long *root, FFTMultipliers& tab) { if (k < 1) Error("PrecompFFTMultipliers: bad input"); if (k <= tab.MaxK) return; tab.wtab_precomp.SetLength(k+1); tab.wqinvtab_precomp.SetLength(k+1); double qinv = 1/((double) q); if (tab.MaxK == -1) { tab.wtab_precomp[1].SetLength(1); tab.wqinvtab_precomp[1].SetLength(1); tab.wtab_precomp[1][0] = 1; tab.wqinvtab_precomp[1][0] = PrepMulModPrecon(1, q, qinv); tab.MaxK = 1; } for (long s = tab.MaxK+1; s <= k; s++) { tab.wtab_precomp[s].SetLength(1L << (s-1)); tab.wqinvtab_precomp[s].SetLength(1L << (s-1)); long m = 1L << s; long m_half = 1L << (s-1); long m_fourth = 1L << (s-2); long *wtab_last = tab.wtab_precomp[s-1].elts(); mulmod_precon_t *wqinvtab_last = tab.wqinvtab_precomp[s-1].elts(); long *wtab = tab.wtab_precomp[s].elts(); mulmod_precon_t *wqinvtab = tab.wqinvtab_precomp[s].elts(); for (long i = 0; i < m_fourth; i++) { wtab[i] = wtab_last[i]; wqinvtab[i] = wqinvtab_last[i]; } long w = root[s]; mulmod_precon_t wqinv = PrepMulModPrecon(w, q, qinv); // prepare wtab... if (s == 2) { wtab[1] = MulModPrecon(wtab[0], w, q, wqinv); wqinvtab[1] = PrepMulModPrecon(wtab[1], q, qinv); } else { // some software pipelining long i, j; i = m_half-1; j = m_fourth-1; wtab[i-1] = wtab[j]; wqinvtab[i-1] = wqinvtab[j]; wtab[i] = MulModPrecon(wtab[i-1], w, q, wqinv); i -= 2; j --; for (; i >= 0; i -= 2, j --) { long wp2 = wtab[i+2]; long wm1 = wtab[j]; wqinvtab[i+2] = PrepMulModPrecon(wp2, q, qinv); wtab[i-1] = wm1; wqinvtab[i-1] = wqinvtab[j]; wtab[i] = MulModPrecon(wm1, w, q, wqinv); } wqinvtab[1] = PrepMulModPrecon(wtab[1], q, qinv); } } tab.MaxK = k; } void FFT(long* A, const long* a, long k, long q, const long* root, FFTMultipliers& tab) // performs a 2^k-point convolution modulo q { if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { long a0 = AddMod(a[0], a[1], q); long a1 = SubMod(a[0], a[1], q); A[0] = a0; A[1] = a1; return; } } // assume k > 1 if (k > tab.MaxK) PrecompFFTMultipliers(k, q, root, tab); NTL_THREAD_LOCAL static Vec AA_store; AA_store.SetLength(1L << k); long *AA = AA_store.elts(); BitReverseCopy(AA, a, k); long n = 1L << k; long s, m, m_half, m_fourth, i, j, t, u, t1, u1, tt, tt1; // s = 1 for (i = 0; i < n; i += 2) { t = AA[i + 1]; u = AA[i]; AA[i] = AddMod(u, t, q); AA[i+1] = SubMod(u, t, q); } for (s = 2; s < k; s++) { m = 1L << s; m_half = 1L << (s-1); m_fourth = 1L << (s-2); const long* wtab = tab.wtab_precomp[s].elts(); const mulmod_precon_t *wqinvtab = tab.wqinvtab_precomp[s].elts(); for (i = 0; i < n; i+= m) { long *AA0 = &AA[i]; long *AA1 = &AA[i + m_half]; #if (NTL_PIPELINE) // pipelining: seems to be faster t = AA1[0]; u = AA0[0]; t1 = MulModPrecon(AA1[1], wtab[1], q, wqinvtab[1]); u1 = AA0[1]; for (j = 0; j < m_half-2; j += 2) { long a02 = AA0[j+2]; long a03 = AA0[j+3]; long a12 = AA1[j+2]; long a13 = AA1[j+3]; long w2 = wtab[j+2]; long w3 = wtab[j+3]; mulmod_precon_t wqi2 = wqinvtab[j+2]; mulmod_precon_t wqi3 = wqinvtab[j+3]; tt = MulModPrecon(a12, w2, q, wqi2); long b00 = AddMod(u, t, q); long b10 = SubMod(u, t, q); tt1 = MulModPrecon(a13, w3, q, wqi3); long b01 = AddMod(u1, t1, q); long b11 = SubMod(u1, t1, q); AA0[j] = b00; AA1[j] = b10; AA0[j+1] = b01; AA1[j+1] = b11; t = tt; u = a02; t1 = tt1; u1 = a03; } AA0[j] = AddMod(u, t, q); AA1[j] = SubMod(u, t, q); AA0[j + 1] = AddMod(u1, t1, q); AA1[j + 1] = SubMod(u1, t1, q); } #else for (j = 0; j < m_half; j += 2) { const long a00 = AA0[j]; const long a01 = AA0[j+1]; const long a10 = AA1[j]; const long a11 = AA1[j+1]; const long w0 = wtab[j]; const long w1 = wtab[j+1]; const mulmod_precon_t wqi0 = wqinvtab[j]; const mulmod_precon_t wqi1 = wqinvtab[j+1]; const long tt = MulModPrecon(a10, w0, q, wqi0); const long uu = a00; const long b00 = AddMod(uu, tt, q); const long b10 = SubMod(uu, tt, q); const long tt1 = MulModPrecon(a11, w1, q, wqi1); const long uu1 = a01; const long b01 = AddMod(uu1, tt1, q); const long b11 = SubMod(uu1, tt1, q); AA0[j] = b00; AA0[j+1] = b01; AA1[j] = b10; AA1[j+1] = b11; } } #endif } // s == k, special case { m = 1L << s; m_half = 1L << (s-1); m_fourth = 1L << (s-2); const long* wtab = tab.wtab_precomp[s].elts(); const mulmod_precon_t *wqinvtab = tab.wqinvtab_precomp[s].elts(); for (i = 0; i < n; i+= m) { long *AA0 = &AA[i]; long *AA1 = &AA[i + m_half]; long *A0 = &A[i]; long *A1 = &A[i + m_half]; #if (NTL_PIPELINE) // pipelining: seems to be faster t = AA1[0]; u = AA0[0]; t1 = MulModPrecon(AA1[1], wtab[1], q, wqinvtab[1]); u1 = AA0[1]; for (j = 0; j < m_half-2; j += 2) { long a02 = AA0[j+2]; long a03 = AA0[j+3]; long a12 = AA1[j+2]; long a13 = AA1[j+3]; long w2 = wtab[j+2]; long w3 = wtab[j+3]; mulmod_precon_t wqi2 = wqinvtab[j+2]; mulmod_precon_t wqi3 = wqinvtab[j+3]; tt = MulModPrecon(a12, w2, q, wqi2); long b00 = AddMod(u, t, q); long b10 = SubMod(u, t, q); tt1 = MulModPrecon(a13, w3, q, wqi3); long b01 = AddMod(u1, t1, q); long b11 = SubMod(u1, t1, q); A0[j] = b00; A1[j] = b10; A0[j+1] = b01; A1[j+1] = b11; t = tt; u = a02; t1 = tt1; u1 = a03; } A0[j] = AddMod(u, t, q); A1[j] = SubMod(u, t, q); A0[j + 1] = AddMod(u1, t1, q); A1[j + 1] = SubMod(u1, t1, q); } #else for (j = 0; j < m_half; j += 2) { const long a00 = AA0[j]; const long a01 = AA0[j+1]; const long a10 = AA1[j]; const long a11 = AA1[j+1]; const long w0 = wtab[j]; const long w1 = wtab[j+1]; const mulmod_precon_t wqi0 = wqinvtab[j]; const mulmod_precon_t wqi1 = wqinvtab[j+1]; const long tt = MulModPrecon(a10, w0, q, wqi0); const long uu = a00; const long b00 = AddMod(uu, tt, q); const long b10 = SubMod(uu, tt, q); const long tt1 = MulModPrecon(a11, w1, q, wqi1); const long uu1 = a01; const long b01 = AddMod(uu1, tt1, q); const long b11 = SubMod(uu1, tt1, q); A0[j] = b00; A0[j+1] = b01; A1[j] = b10; A1[j+1] = b11; } } #endif } } #else // FFT with precomputed tables and David Harvey's lazy multiplication // strategy. static inline unsigned long LazyPrepMulModPrecon(long b, long n, double ninv) { unsigned long q, r; q = (long) ( (((double) b) * NTL_SP_FBOUND) * ninv ); r = (((unsigned long) b) << NTL_SP_NBITS ) - q * ((unsigned long) n); if (r >> (NTL_BITS_PER_LONG-1)) { q--; r += n; } else if (((long) r) >= n) { q++; r -=n; } unsigned long res = q << (NTL_BITS_PER_LONG - NTL_SP_NBITS); long qq, rr; rr = MulDivRem(qq, (long) r, 4, n, 4*ninv); res = res + (qq << (NTL_BITS_PER_LONG - NTL_SP_NBITS-2)); return res; } static inline unsigned long LazyMulModPrecon(unsigned long a, unsigned long b, unsigned long n, unsigned long bninv) { unsigned long q = MulHiUL(a, bninv); unsigned long res = a*b - q*n; return res; } static inline unsigned long LazyReduce(unsigned long a, unsigned long q) { unsigned long res; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING) && !defined(NTL_CLEAN_INT)) res = a - q; res += (((long) res) >> (NTL_BITS_PER_LONG-1)) & q; #elif (defined(NTL_AVOID_BRANCHING)) res = a - q; res += (-(res >> (NTL_BITS_PER_LONG-1))) & q; #else if (a >= q) res = a - q; else res = a; #endif return res; } static void LazyPrecompFFTMultipliers(long k, long q, const long *root, FFTMultipliers& tab) { if (k < 1) Error("LazyPrecompFFTMultipliers: bad input"); if (k <= tab.MaxK) return; tab.wtab_precomp.SetLength(k+1); tab.wqinvtab_precomp.SetLength(k+1); double qinv = 1/((double) q); if (tab.MaxK == -1) { tab.wtab_precomp[1].SetLength(1); tab.wqinvtab_precomp[1].SetLength(1); tab.wtab_precomp[1][0] = 1; tab.wqinvtab_precomp[1][0] = LazyPrepMulModPrecon(1, q, qinv); tab.MaxK = 1; } for (long s = tab.MaxK+1; s <= k; s++) { tab.wtab_precomp[s].SetLength(1L << (s-1)); tab.wqinvtab_precomp[s].SetLength(1L << (s-1)); long m = 1L << s; long m_half = 1L << (s-1); long m_fourth = 1L << (s-2); long *wtab_last = tab.wtab_precomp[s-1].elts(); mulmod_precon_t *wqinvtab_last = tab.wqinvtab_precomp[s-1].elts(); long *wtab = tab.wtab_precomp[s].elts(); mulmod_precon_t *wqinvtab = tab.wqinvtab_precomp[s].elts(); for (long i = 0; i < m_fourth; i++) { wtab[i] = wtab_last[i]; wqinvtab[i] = wqinvtab_last[i]; } long w = root[s]; mulmod_precon_t wqinv = LazyPrepMulModPrecon(w, q, qinv); // prepare wtab... if (s == 2) { wtab[1] = LazyReduce(LazyMulModPrecon(wtab[0], w, q, wqinv), q); wqinvtab[1] = LazyPrepMulModPrecon(wtab[1], q, qinv); } else { // some software pipelining long i, j; i = m_half-1; j = m_fourth-1; wtab[i-1] = wtab[j]; wqinvtab[i-1] = wqinvtab[j]; wtab[i] = LazyReduce(LazyMulModPrecon(wtab[i-1], w, q, wqinv), q); i -= 2; j --; for (; i >= 0; i -= 2, j --) { long wp2 = wtab[i+2]; long wm1 = wtab[j]; wqinvtab[i+2] = LazyPrepMulModPrecon(wp2, q, qinv); wtab[i-1] = wm1; wqinvtab[i-1] = wqinvtab[j]; wtab[i] = LazyReduce(LazyMulModPrecon(wm1, w, q, wqinv), q); } wqinvtab[1] = LazyPrepMulModPrecon(wtab[1], q, qinv); } } tab.MaxK = k; } void FFT(long* A, const long* a, long k, long q, const long* root, FFTMultipliers& tab) // performs a 2^k-point convolution modulo q { if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { long a0 = AddMod(a[0], a[1], q); long a1 = SubMod(a[0], a[1], q); A[0] = a0; A[1] = a1; return; } } // assume k > 1 if (k > tab.MaxK) LazyPrecompFFTMultipliers(k, q, root, tab); NTL_THREAD_LOCAL static Vec AA_store; AA_store.SetLength(1L << k); unsigned long *AA = AA_store.elts(); BitReverseCopy(AA, a, k); long n = 1L << k; /* we work with redundant representations, in the range [0, 4q) */ long s, m, m_half, m_fourth, i, j; unsigned long t, u, t1, u1; long two_q = 2 * q; // s = 1 for (i = 0; i < n; i += 2) { t = AA[i + 1]; u = AA[i]; AA[i] = u + t; AA[i+1] = u - t + q; } // s = 2 { const long * NTL_RESTRICT wtab = tab.wtab_precomp[2].elts(); const mulmod_precon_t * NTL_RESTRICT wqinvtab = tab.wqinvtab_precomp[2].elts(); for (i = 0; i < n; i += 4) { unsigned long * NTL_RESTRICT AA0 = &AA[i]; unsigned long * NTL_RESTRICT AA1 = &AA[i + 2]; { const long w1 = wtab[0]; const mulmod_precon_t wqi1 = wqinvtab[0]; const unsigned long a11 = AA1[0]; const unsigned long a01 = AA0[0]; const unsigned long tt1 = LazyMulModPrecon(a11, w1, q, wqi1); const unsigned long uu1 = LazyReduce(a01, two_q); const unsigned long b01 = uu1 + tt1; const unsigned long b11 = uu1 - tt1 + two_q; AA0[0] = b01; AA1[0] = b11; } { const long w1 = wtab[1]; const mulmod_precon_t wqi1 = wqinvtab[1]; const unsigned long a11 = AA1[1]; const unsigned long a01 = AA0[1]; const unsigned long tt1 = LazyMulModPrecon(a11, w1, q, wqi1); const unsigned long uu1 = LazyReduce(a01, two_q); const unsigned long b01 = uu1 + tt1; const unsigned long b11 = uu1 - tt1 + two_q; AA0[1] = b01; AA1[1] = b11; } } } // s = 3..k for (s = 3; s <= k; s++) { m = 1L << s; m_half = 1L << (s-1); m_fourth = 1L << (s-2); const long* NTL_RESTRICT wtab = tab.wtab_precomp[s].elts(); const mulmod_precon_t * NTL_RESTRICT wqinvtab = tab.wqinvtab_precomp[s].elts(); for (i = 0; i < n; i += m) { unsigned long * NTL_RESTRICT AA0 = &AA[i]; unsigned long * NTL_RESTRICT AA1 = &AA[i + m_half]; for (j = 0; j < m_half; j += 4) { { const long w1 = wtab[j+0]; const mulmod_precon_t wqi1 = wqinvtab[j+0]; const unsigned long a11 = AA1[j+0]; const unsigned long a01 = AA0[j+0]; const unsigned long tt1 = LazyMulModPrecon(a11, w1, q, wqi1); const unsigned long uu1 = LazyReduce(a01, two_q); const unsigned long b01 = uu1 + tt1; const unsigned long b11 = uu1 - tt1 + two_q; AA0[j+0] = b01; AA1[j+0] = b11; } { const long w1 = wtab[j+1]; const mulmod_precon_t wqi1 = wqinvtab[j+1]; const unsigned long a11 = AA1[j+1]; const unsigned long a01 = AA0[j+1]; const unsigned long tt1 = LazyMulModPrecon(a11, w1, q, wqi1); const unsigned long uu1 = LazyReduce(a01, two_q); const unsigned long b01 = uu1 + tt1; const unsigned long b11 = uu1 - tt1 + two_q; AA0[j+1] = b01; AA1[j+1] = b11; } { const long w1 = wtab[j+2]; const mulmod_precon_t wqi1 = wqinvtab[j+2]; const unsigned long a11 = AA1[j+2]; const unsigned long a01 = AA0[j+2]; const unsigned long tt1 = LazyMulModPrecon(a11, w1, q, wqi1); const unsigned long uu1 = LazyReduce(a01, two_q); const unsigned long b01 = uu1 + tt1; const unsigned long b11 = uu1 - tt1 + two_q; AA0[j+2] = b01; AA1[j+2] = b11; } { const long w1 = wtab[j+3]; const mulmod_precon_t wqi1 = wqinvtab[j+3]; const unsigned long a11 = AA1[j+3]; const unsigned long a01 = AA0[j+3]; const unsigned long tt1 = LazyMulModPrecon(a11, w1, q, wqi1); const unsigned long uu1 = LazyReduce(a01, two_q); const unsigned long b01 = uu1 + tt1; const unsigned long b11 = uu1 - tt1 + two_q; AA0[j+3] = b01; AA1[j+3] = b11; } } } } /* need to reduce redundant representations */ for (i = 0; i < n; i++) { unsigned long tmp = LazyReduce(AA[i], two_q); A[i] = LazyReduce(tmp, q); } } #endif NTL_END_IMPL ntl-6.2.1/src/FacVec.c000644 000765 000024 00000002621 12377144456 014716 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL static void swap(IntFactor& x, IntFactor& y) { IntFactor t; t = x; x = y; y = t; } static void FindMin(FacVec& v, long lo, long hi) { long minv = 0; long minp = -1; long i; for (i = lo; i <= hi; i++) { if (minv == 0 || v[i].val < minv) { minv = v[i].val; minp = i; } } swap(v[lo], v[minp]); } void FactorInt(FacVec& fvec, long n) { if (n <= 1) Error("internal error: FactorInt(FacVec,long n) with n<=1"); if (NTL_OVERFLOW(n, 1, 0)) Error("internal error: FactorInt(FacVec,long n) with n too large"); long NumFactors; long q; fvec.SetLength(2*NextPowerOfTwo(n)); NumFactors = 0; q = 2; while (n != 1) { if (n%q == 0) { fvec[NumFactors].q = q; n = n/q; fvec[NumFactors].a = 1; fvec[NumFactors].val = q; while (n%q == 0) { n = n/q; (fvec[NumFactors].a)++; fvec[NumFactors].val *= q; } fvec[NumFactors].link = -1; NumFactors++; } q++; } fvec.SetLength(2*NumFactors-1); long lo = 0; long hi = NumFactors - 1; while (lo < hi) { FindMin(fvec, lo, hi); FindMin(fvec, lo+1, hi); hi++; fvec[hi].link = lo; fvec[hi].val = fvec[lo].val * fvec[lo+1].val; lo += 2; } } NTL_END_IMPL ntl-6.2.1/src/GF2.c000644 000765 000024 00000000711 12377144456 014143 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL GF2 power(GF2 a, long e) { if (e == 0) { return to_GF2(1); } if (e < 0 && IsZero(a)) Error("GF2: division by zero"); return a; } ostream& operator<<(ostream& s, GF2 a) { if (a == 0) s << "0"; else s << "1"; return s; } istream& operator>>(istream& s, ref_GF2 x) { NTL_ZZRegister(a); s >> a; conv(x, a); return s; } NTL_END_IMPL ntl-6.2.1/src/GF2E.c000644 000765 000024 00000006326 12377144456 014260 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL GF2EInfoT::GF2EInfoT(const GF2X& NewP) { ref_count = 1; build(p, NewP); if (p.size == 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) KarCross = 4; else KarCross = 8; } else if (p.size == 2) KarCross = 8; else if (p.size <= 5) KarCross = 4; else if (p.size == 6) KarCross = 3; else KarCross = 2; if (p.size <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) ModCross = 20; else ModCross = 40; } else if (p.size <= 2) ModCross = 75; else if (p.size <= 4) ModCross = 50; else ModCross = 25; if (p.size == 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) DivCross = 100; else DivCross = 200; } else if (p.size == 2) DivCross = 400; else if (p.size <= 4) DivCross = 200; else if (p.size == 5) DivCross = 150; else if (p.size <= 13) DivCross = 100; else DivCross = 75; _card_init = 0; _card_exp = p.n; } const ZZ& GF2E::cardinality() { if (!GF2EInfo) Error("GF2E::cardinality: undefined modulus"); // FIXME: in a thread safe impl, this needs to be mutex'd if (!GF2EInfo->_card_init) { power(GF2EInfo->_card, 2, GF2EInfo->_card_exp); GF2EInfo->_card_init = 1; } return GF2EInfo->_card; } NTL_THREAD_LOCAL GF2EInfoT *GF2EInfo = 0; typedef GF2EInfoT *GF2EInfoPtr; static void CopyPointer(GF2EInfoPtr& dst, GF2EInfoPtr src) { if (src == dst) return; if (dst) { dst->ref_count--; if (dst->ref_count < 0) Error("internal error: negative GF2EContext ref_count"); if (dst->ref_count == 0) delete dst; } if (src) { if (src->ref_count == NTL_MAX_LONG) Error("internal error: GF2EContext ref_count overflow"); src->ref_count++; } dst = src; } void GF2E::init(const GF2X& p) { GF2EContext c(p); c.restore(); } GF2EContext::GF2EContext(const GF2X& p) { ptr = NTL_NEW_OP GF2EInfoT(p); } GF2EContext::GF2EContext(const GF2EContext& a) { ptr = 0; CopyPointer(ptr, a.ptr); } GF2EContext& GF2EContext::operator=(const GF2EContext& a) { CopyPointer(ptr, a.ptr); return *this; } GF2EContext::~GF2EContext() { CopyPointer(ptr, 0); } void GF2EContext::save() { CopyPointer(ptr, GF2EInfo); } void GF2EContext::restore() const { CopyPointer(GF2EInfo, ptr); } GF2EBak::~GF2EBak() { if (MustRestore) CopyPointer(GF2EInfo, ptr); CopyPointer(ptr, 0); } void GF2EBak::save() { MustRestore = 1; CopyPointer(ptr, GF2EInfo); } void GF2EBak::restore() { MustRestore = 0; CopyPointer(GF2EInfo, ptr); } const GF2E& GF2E::zero() { NTL_THREAD_LOCAL static GF2E z(INIT_NO_ALLOC); return z; } istream& operator>>(istream& s, GF2E& x) { GF2X y; s >> y; conv(x, y); return s; } void div(GF2E& x, const GF2E& a, const GF2E& b) { GF2E t; inv(t, b); mul(x, a, t); } void div(GF2E& x, GF2 a, const GF2E& b) { inv(x, b); mul(x, x, a); } void div(GF2E& x, long a, const GF2E& b) { inv(x, b); mul(x, x, a); } void inv(GF2E& x, const GF2E& a) { InvMod(x._GF2E__rep, a._GF2E__rep, GF2E::modulus()); } NTL_END_IMPL ntl-6.2.1/src/GF2EX.c000644 000765 000024 00000162666 12377144456 014422 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL const GF2EX& GF2EX::zero() { NTL_THREAD_LOCAL static GF2EX z; return z; } istream& operator>>(istream& s, GF2EX& x) { s >> x.rep; x.normalize(); return s; } ostream& operator<<(ostream& s, const GF2EX& a) { return s << a.rep; } void GF2EX::normalize() { long n; const GF2E* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const GF2EX& a) { return a.rep.length() == 0; } long IsOne(const GF2EX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } void GetCoeff(GF2E& x, const GF2EX& a, long i) { if (i < 0 || i > deg(a)) clear(x); else x = a.rep[i]; } void SetCoeff(GF2EX& x, long i, const GF2E& a) { long j, m; if (i < 0) Error("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { GF2E aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(GF2EX& x, long i, GF2 a) { if (i < 0) Error("SetCoeff: negative index"); if (a == 1) SetCoeff(x, i); else SetCoeff(x, i, GF2E::zero()); } void SetCoeff(GF2EX& x, long i, long a) { if (i < 0) Error("SetCoeff: negative index"); if ((a & 1) == 1) SetCoeff(x, i); else SetCoeff(x, i, GF2E::zero()); } void SetCoeff(GF2EX& x, long i) { long j, m; if (i < 0) Error("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(GF2EX& x) { clear(x); SetCoeff(x, 1); } long IsX(const GF2EX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const GF2E& coeff(const GF2EX& a, long i) { if (i < 0 || i > deg(a)) return GF2E::zero(); else return a.rep[i]; } const GF2E& LeadCoeff(const GF2EX& a) { if (IsZero(a)) return GF2E::zero(); else return a.rep[deg(a)]; } const GF2E& ConstTerm(const GF2EX& a) { if (IsZero(a)) return GF2E::zero(); else return a.rep[0]; } void conv(GF2EX& x, const GF2E& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(GF2EX& x, long a) { if (a & 1) set(x); else clear(x); } void conv(GF2EX& x, GF2 a) { if (a == 1) set(x); else clear(x); } void conv(GF2EX& x, const ZZ& a) { if (IsOdd(a)) set(x); else clear(x); } void conv(GF2EX& x, const GF2X& aa) { GF2X a = aa; // in case a aliases the rep of a coefficient of x long n = deg(a)+1; long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], coeff(a, i)); } void conv(GF2EX& x, const vec_GF2E& a) { x.rep = a; x.normalize(); } /* additional legacy conversions for v6 conversion regime */ void conv(GF2EX& x, const ZZX& a) { long n = a.rep.length(); long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], a.rep[i]); x.normalize(); } /* ------------------------------------- */ void add(GF2EX& x, const GF2EX& a, const GF2EX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const GF2E *ap, *bp; GF2E* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(GF2EX& x, const GF2EX& a, const GF2E& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x GF2E *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const GF2E *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(GF2EX& x, const GF2EX& a, GF2 b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void add(GF2EX& x, const GF2EX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void PlainMul(GF2EX& x, const GF2EX& a, const GF2EX& b) { long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } if (&a == &b) { sqr(x, a); return; } long d = da+db; const GF2E *ap, *bp; GF2E *xp; GF2EX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; GF2X t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(bp[i-j])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void sqr(GF2EX& x, const GF2EX& a) { long da = deg(a); if (da < 0) { clear(x); return; } x.rep.SetLength(2*da+1); long i; for (i = da; i > 0; i--) { sqr(x.rep[2*i], a.rep[i]); clear(x.rep[2*i-1]); } sqr(x.rep[0], a.rep[0]); x.normalize(); } static void PlainMul1(GF2X *xp, const GF2X *ap, long sa, const GF2X& b) { long i; for (i = 0; i < sa; i++) mul(xp[i], ap[i], b); } static inline void q_add(GF2X& x, const GF2X& a, const GF2X& b) // This is a quick-and-dirty add rotine used by the karatsuba routine. // It assumes that the output already has enough space allocated, // thus avoiding any procedure calls. // WARNING: it also accesses the underlying WordVector representation // directly...that is dirty!. // It shaves a few percent off the running time. { _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); long sa = ap[-1]; long sb = bp[-1]; long i; if (sa == sb) { for (i = 0; i < sa; i++) xp[i] = ap[i] ^ bp[i]; i = sa-1; while (i >= 0 && !xp[i]) i--; xp[-1] = i+1; } else if (sa < sb) { for (i = 0; i < sa; i++) xp[i] = ap[i] ^ bp[i]; for (; i < sb; i++) xp[i] = bp[i]; xp[-1] = sb; } else { // sa > sb for (i = 0; i < sb; i++) xp[i] = ap[i] ^ bp[i]; for (; i < sa; i++) xp[i] = ap[i]; xp[-1] = sa; } } static inline void q_copy(GF2X& x, const GF2X& a) // see comments for q_add above { _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long sa = ap[-1]; long i; for (i = 0; i < sa; i++) xp[i] = ap[i]; xp[-1] = sa; } static void KarFold(GF2X *T, const GF2X *b, long sb, long hsa) { long m = sb - hsa; long i; for (i = 0; i < m; i++) q_add(T[i], b[i], b[hsa+i]); for (i = m; i < hsa; i++) q_copy(T[i], b[i]); } static void KarAdd(GF2X *T, const GF2X *b, long sb) { long i; for (i = 0; i < sb; i++) q_add(T[i], T[i], b[i]); } static void KarFix(GF2X *c, const GF2X *b, long sb, long hsa) { long i; for (i = 0; i < hsa; i++) q_copy(c[i], b[i]); for (i = hsa; i < sb; i++) q_add(c[i], c[i], b[i]); } static void KarMul(GF2X *c, const GF2X *a, long sa, const GF2X *b, long sb, GF2X *stk) { if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const GF2X *t = a; a = b; b = t; } } if (sb == 1) { if (sa == 1) mul(*c, *a, *b); else PlainMul1(c, a, sa, *b); return; } if (sb == 2 && sa == 2) { mul(c[0], a[0], b[0]); mul(c[2], a[1], b[1]); q_add(stk[0], a[0], a[1]); q_add(stk[1], b[0], b[1]); mul(c[1], stk[0], stk[1]); q_add(c[1], c[1], c[0]); q_add(c[1], c[1], c[2]); return; } long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long hsa2 = hsa << 1; GF2X *T1, *T2, *T3; T1 = stk; stk += hsa; T2 = stk; stk += hsa; T3 = stk; stk += hsa2 - 1; /* compute T1 = a_lo + a_hi */ KarFold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ KarFold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ KarMul(T3, T1, hsa, T2, hsa, stk); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ KarMul(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk); KarAdd(T3, c + hsa2, sa + sb - hsa2 - 1); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ KarMul(c, a, hsa, b, hsa, stk); KarAdd(T3, c, hsa2 - 1); clear(c[hsa2 - 1]); /* finally, add T3 * X^{hsa} to c */ KarAdd(c+hsa, T3, hsa2-1); } else { /* degenerate case */ GF2X *T; T = stk; stk += hsa + sb - 1; /* recursively compute b*a_hi into high part of c */ KarMul(c + hsa, a + hsa, sa - hsa, b, sb, stk); /* recursively compute b*a_lo into T */ KarMul(T, a, hsa, b, sb, stk); KarFix(c, T, hsa + sb - 1, hsa); } } void ExtractBits(_ntl_ulong *cp, const _ntl_ulong *ap, long k, long n) // extract k bits from a at position n { long sc = (k + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long i; if (bn == 0) { for (i = 0; i < sc; i++) cp[i] = ap[i+wn]; } else { for (i = 0; i < sc-1; i++) cp[i] = (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn)); if (k > sc*NTL_BITS_PER_LONG - bn) cp[sc-1] = (ap[sc+wn-1] >> bn)|(ap[sc+wn] << (NTL_BITS_PER_LONG - bn)); else cp[sc-1] = ap[sc+wn-1] >> bn; } long p = k % NTL_BITS_PER_LONG; if (p != 0) cp[sc-1] &= ((1UL << p) - 1UL); } void KronSubst(GF2X& aa, const GF2EX& a) { long sa = a.rep.length(); long blocksz = 2*GF2E::degree() - 1; long saa = sa*blocksz; long wsaa = (saa + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; aa.xrep.SetLength(wsaa+1); _ntl_ulong *paa = aa.xrep.elts(); long i; for (i = 0; i < wsaa+1; i++) paa[i] = 0; for (i = 0; i < sa; i++) ShiftAdd(paa, rep(a.rep[i]).xrep.elts(), rep(a.rep[i]).xrep.length(), blocksz*i); aa.normalize(); } void KronMul(GF2EX& x, const GF2EX& a, const GF2EX& b) { if (a == 0 || b == 0) { clear(x); return; } GF2X aa, bb, xx; long sx = deg(a) + deg(b) + 1; long blocksz = 2*GF2E::degree() - 1; if (NTL_OVERFLOW(blocksz, sx, 0)) Error("overflow in GF2EX KronMul"); KronSubst(aa, a); KronSubst(bb, b); mul(xx, aa, bb); GF2X c; long wc = (blocksz + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; x.rep.SetLength(sx); long i; for (i = 0; i < sx-1; i++) { c.xrep.SetLength(wc); ExtractBits(c.xrep.elts(), xx.xrep.elts(), blocksz, i*blocksz); c.normalize(); conv(x.rep[i], c); } long last_blocksz = deg(xx) - (sx-1)*blocksz + 1; wc = (last_blocksz + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; c.xrep.SetLength(wc); ExtractBits(c.xrep.elts(), xx.xrep.elts(), last_blocksz, (sx-1)*blocksz); c.normalize(); conv(x.rep[sx-1], c); x.normalize(); } void mul(GF2EX& c, const GF2EX& a, const GF2EX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { sqr(c, a); return; } long sa = a.rep.length(); long sb = b.rep.length(); if (sa == 1) { mul(c, b, a.rep[0]); return; } if (sb == 1) { mul(c, a, b.rep[0]); return; } if (sa < GF2E::KarCross() || sb < GF2E::KarCross()) { PlainMul(c, a, b); return; } if (GF2E::WordLength() <= 1) { KronMul(c, a, b); return; } /* karatsuba */ long n, hn, sp; n = max(sa, sb); sp = 0; do { hn = (n+1) >> 1; sp += (hn << 2) - 1; n = hn; } while (n > 1); GF2XVec stk; stk.SetSize(sp + 2*(sa+sb)-1, 2*GF2E::WordLength()); long i; for (i = 0; i < sa; i++) stk[i+sa+sb-1] = rep(a.rep[i]); for (i = 0; i < sb; i++) stk[i+2*sa+sb-1] = rep(b.rep[i]); KarMul(&stk[0], &stk[sa+sb-1], sa, &stk[2*sa+sb-1], sb, &stk[2*(sa+sb)-1]); c.rep.SetLength(sa+sb-1); for (i = 0; i < sa+sb-1; i++) conv(c.rep[i], stk[i]); c.normalize(); } void MulTrunc(GF2EX& x, const GF2EX& a, const GF2EX& b, long n) { GF2EX t; mul(t, a, b); trunc(x, t, n); } void SqrTrunc(GF2EX& x, const GF2EX& a, long n) { GF2EX t; sqr(t, a); trunc(x, t, n); } void PlainDivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2E *qp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) Error("GF2EX: division by zero"); if (da < db) { r = a; clear(q); return; } GF2EX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } GF2XVec x(da + 1, 2*GF2E::WordLength()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainRem(GF2EX& r, const GF2EX& a, const GF2EX& b, GF2XVec& x) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) Error("GF2EX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b, GF2XVec& x) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2E *qp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) Error("GF2EX: division by zero"); if (da < db) { r = a; clear(q); return; } GF2EX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDiv(GF2EX& q, const GF2EX& a, const GF2EX& b) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2E *qp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) Error("GF2EX: division by zero"); if (da < db) { clear(q); return; } GF2EX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } GF2XVec x(da + 1 - db, 2*GF2E::WordLength()); for (i = db; i <= da; i++) x[i-db] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j-db], xp[i+j-db], s); } } } void PlainRem(GF2EX& r, const GF2EX& a, const GF2EX& b) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) Error("GF2EX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } GF2XVec x(da + 1, 2*GF2E::WordLength()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void mul(GF2EX& x, const GF2EX& a, const GF2E& b) { if (IsZero(a) || IsZero(b)) { clear(x); return; } GF2X bb, t; long i, da; const GF2E *ap; GF2E* xp; bb = rep(b); da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) { mul(t, rep(ap[i]), bb); conv(xp[i], t); } x.normalize(); } void mul(GF2EX& x, const GF2EX& a, GF2 b) { if (b == 0) clear(x); else x = a; } void mul(GF2EX& x, const GF2EX& a, long b) { if ((b & 1) == 0) clear(x); else x = a; } void GCD(GF2EX& x, const GF2EX& a, const GF2EX& b) { GF2E t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; GF2EX u(INIT_SIZE, n), v(INIT_SIZE, n); GF2XVec tmp(n, 2*GF2E::WordLength()); u = a; v = b; do { PlainRem(u, u, v, tmp); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } void XGCD(GF2EX& d, GF2EX& s, GF2EX& t, const GF2EX& a, const GF2EX& b) { GF2E z; if (IsZero(b)) { set(s); clear(t); d = a; } else if (IsZero(a)) { clear(s); set(t); d = b; } else { long e = max(deg(a), deg(b)) + 1; GF2EX temp(INIT_SIZE, e), u(INIT_SIZE, e), v(INIT_SIZE, e), u0(INIT_SIZE, e), v0(INIT_SIZE, e), u1(INIT_SIZE, e), v1(INIT_SIZE, e), u2(INIT_SIZE, e), v2(INIT_SIZE, e), q(INIT_SIZE, e); set(u1); clear(v1); clear(u2); set(v2); u = a; v = b; do { DivRem(q, u, u, v); swap(u, v); u0 = u2; v0 = v2; mul(temp, q, u2); add(u2, u1, temp); mul(temp, q, v2); add(v2, v1, temp); u1 = u0; v1 = v0; } while (!IsZero(v)); d = u; s = u1; t = v1; } if (IsZero(d)) return; if (IsOne(LeadCoeff(d))) return; /* make gcd monic */ inv(z, LeadCoeff(d)); mul(d, d, z); mul(s, s, z); mul(t, t, z); } void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) Error("MulMod: bad args"); GF2EX t; mul(t, a, b); rem(x, t, f); } void SqrMod(GF2EX& x, const GF2EX& a, const GF2EX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("SqrMod: bad args"); GF2EX t; sqr(t, a); rem(x, t, f); } void InvMod(GF2EX& x, const GF2EX& a, const GF2EX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvMod: bad args"); GF2EX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) Error("GF2EX InvMod: can't compute multiplicative inverse"); } long InvModStatus(GF2EX& x, const GF2EX& a, const GF2EX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvModStatus: bad args"); GF2EX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } static void MulByXModAux(GF2EX& h, const GF2EX& a, const GF2EX& f) { long i, n, m; GF2E* hh; const GF2E *aa, *ff; GF2E t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) Error("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); z = aa[n-1]; if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(GF2EX& h, const GF2EX& a, const GF2EX& f) { if (&h == &f) { GF2EX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void random(GF2EX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void CopyReverse(GF2EX& x, const GF2EX& a, long hi) // x[0..hi] = reverse(a[0..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi+1; m = a.rep.length(); x.rep.SetLength(n); const GF2E* ap = a.rep.elts(); GF2E* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void trunc(GF2EX& x, const GF2EX& a, long m) // x = a % X^m, output may alias input { if (m < 0) Error("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; GF2E* xp; const GF2E* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void NewtonInvTrunc(GF2EX& c, const GF2EX& a, long e) { GF2E x; inv(x, ConstTerm(a)); if (e == 1) { conv(c, x); return; } vec_long E; E.SetLength(0); append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long L = E.length(); GF2EX g, g0, g1, g2; g.rep.SetMaxLength(E[0]); g0.rep.SetMaxLength(E[0]); g1.rep.SetMaxLength((3*E[0]+1)/2); g2.rep.SetMaxLength(E[0]); conv(g, x); long i; for (i = L-1; i > 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); add(g, g, g2); } c = g; } void InvTrunc(GF2EX& c, const GF2EX& a, long e) { if (e < 0) Error("InvTrunc: bad args"); if (e == 0) { clear(c); return; } if (NTL_OVERFLOW(e, 1, 0)) Error("overflow in InvTrunc"); NewtonInvTrunc(c, a, e); } const long GF2EX_MOD_PLAIN = 0; const long GF2EX_MOD_MUL = 1; void build(GF2EXModulus& F, const GF2EX& f) { long n = deg(f); if (n <= 0) Error("build(GF2EXModulus,GF2EX): deg(f) <= 0"); if (NTL_OVERFLOW(n, GF2E::degree(), 0)) Error("build(GF2EXModulus,GF2EX): overflow"); F.tracevec.SetLength(0); F.f = f; F.n = n; if (F.n < GF2E::ModCross()) { F.method = GF2EX_MOD_PLAIN; } else { F.method = GF2EX_MOD_MUL; GF2EX P1; GF2EX P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); trunc(F.f0, f, n); F.hlc = ConstTerm(P2); } } GF2EXModulus::GF2EXModulus() { n = -1; method = GF2EX_MOD_PLAIN; } GF2EXModulus::GF2EXModulus(const GF2EX& ff) { n = -1; method = GF2EX_MOD_PLAIN; build(*this, ff); } void UseMulRem21(GF2EX& r, const GF2EX& a, const GF2EXModulus& F) { GF2EX P1; GF2EX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); add(r, r, P1); } void UseMulDivRem21(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F) { GF2EX P1; GF2EX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); add(r, r, P1); q = P2; } void UseMulDiv21(GF2EX& q, const GF2EX& a, const GF2EXModulus& F) { GF2EX P1; GF2EX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); q = P2; } void rem(GF2EX& x, const GF2EX& a, const GF2EXModulus& F) { if (F.method == GF2EX_MOD_PLAIN) { PlainRem(x, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulRem21(x, a, F); return; } GF2EX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulRem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F) { if (F.method == GF2EX_MOD_PLAIN) { PlainDivRem(q, r, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDivRem21(q, r, a, F); return; } GF2EX buf(INIT_SIZE, 2*n-1); GF2EX qbuf(INIT_SIZE, n-1); GF2EX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulDivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F) { if (F.method == GF2EX_MOD_PLAIN) { PlainDiv(q, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDiv21(q, a, F); return; } GF2EX buf(INIT_SIZE, 2*n-1); GF2EX qbuf(INIT_SIZE, n-1); GF2EX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) UseMulDivRem21(qbuf, buf, buf, F); else UseMulDiv21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(GF2EX& c, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F) { if (deg(a) >= F.n || deg(b) >= F.n) Error("MulMod: bad args"); GF2EX t; mul(t, a, b); rem(c, t, F); } void SqrMod(GF2EX& c, const GF2EX& a, const GF2EXModulus& F) { if (deg(a) >= F.n) Error("MulMod: bad args"); GF2EX t; sqr(t, a); rem(c, t, F); } static long OptWinSize(long n) // finds k that minimizes n/(k+1) + 2^{k-1} { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/(double(k+2)) + double(1L << k); if (v_new >= v) break; v = v_new; k++; } return k; } void PowerMod(GF2EX& h, const GF2EX& g, const ZZ& e, const GF2EXModulus& F) // h = g^e mod f using "sliding window" algorithm { if (deg(g) >= F.n) Error("PowerMod: bad args"); if (e == 0) { set(h); return; } if (e == 1) { h = g; return; } if (e == -1) { InvMod(h, g, F); return; } if (e == 2) { SqrMod(h, g, F); return; } if (e == -2) { SqrMod(h, g, F); InvMod(h, h, F); return; } long n = NumBits(e); GF2EX res; res.SetMaxLength(F.n); set(res); long i; if (n < 16) { // plain square-and-multiply algorithm for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, g, F); } if (e < 0) InvMod(res, res, F); h = res; return; } long k = OptWinSize(n); k = min(k, 5); vec_GF2EX v; v.SetLength(1L << (k-1)); v[0] = g; if (k > 1) { GF2EX t; SqrMod(t, g, F); for (i = 1; i < (1L << (k-1)); i++) MulMod(v[i], v[i-1], t, F); } long val; long cnt; long m; val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | bit(e, i); if (val == 0) SqrMod(res, res, F); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { SqrMod(res, res, F); m = m >> 1; } MulMod(res, res, v[val >> 1], F); while (cnt > 0) { SqrMod(res, res, F); cnt--; } val = 0; } } if (e < 0) InvMod(res, res, F); h = res; } void PowerXMod(GF2EX& hh, const ZZ& e, const GF2EXModulus& F) { if (F.n < 0) Error("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; GF2EX h; h.SetMaxLength(F.n+1); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) { MulByXMod(h, h, F.f); } } if (e < 0) InvMod(h, h, F); hh = h; } void UseMulRem(GF2EX& r, const GF2EX& a, const GF2EX& b) { GF2EX P1; GF2EX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); add(P1, P1, a); r = P1; } void UseMulDivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b) { GF2EX P1; GF2EX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); add(P1, P1, a); r = P1; q = P2; } void UseMulDiv(GF2EX& q, const GF2EX& a, const GF2EX& b) { GF2EX P1; GF2EX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); q = P2; } void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < GF2E::DivCross() || sa-sb < GF2E::DivCross()) PlainDivRem(q, r, a, b); else if (sa < 4*sb) UseMulDivRem(q, r, a, b); else { GF2EXModulus B; build(B, b); DivRem(q, r, a, B); } } void div(GF2EX& q, const GF2EX& a, const GF2EX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < GF2E::DivCross() || sa-sb < GF2E::DivCross()) PlainDiv(q, a, b); else if (sa < 4*sb) UseMulDiv(q, a, b); else { GF2EXModulus B; build(B, b); div(q, a, B); } } void div(GF2EX& q, const GF2EX& a, const GF2E& b) { GF2E t; inv(t, b); mul(q, a, t); } void div(GF2EX& q, const GF2EX& a, GF2 b) { if (b == 0) Error("div: division by zero"); q = a; } void div(GF2EX& q, const GF2EX& a, long b) { if ((b & 1) == 0) Error("div: division by zero"); q = a; } void rem(GF2EX& r, const GF2EX& a, const GF2EX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < GF2E::DivCross() || sa-sb < GF2E::DivCross()) PlainRem(r, a, b); else if (sa < 4*sb) UseMulRem(r, a, b); else { GF2EXModulus B; build(B, b); rem(r, a, B); } } void diff(GF2EX& x, const GF2EX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { if ((i+1)&1) x.rep[i] = a.rep[i+1]; else clear(x.rep[i]); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void RightShift(GF2EX& x, const GF2EX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) Error("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(GF2EX& x, const GF2EX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void ShiftAdd(GF2EX& U, const GF2EX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) add(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void IterBuild(GF2E* a, long n) { long i, k; GF2E b, t; if (n <= 0) return; for (k = 1; k <= n-1; k++) { b = a[k]; add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void BuildFromRoots(GF2EX& x, const vec_GF2E& a) { long n = a.length(); if (n == 0) { set(x); return; } x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); } void eval(GF2E& b, const GF2EX& f, const GF2E& a) // does a Horner evaluation { GF2E acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_GF2E& b, const GF2EX& f, const vec_GF2E& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_GF2E bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(GF2EX& f, const vec_GF2E& a, const vec_GF2E& b) { long m = a.length(); if (b.length() != m) Error("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_GF2E prod; prod = a; GF2E t1, t2; long k, i; vec_GF2E res; res.SetLength(m); for (k = 0; k < m; k++) { const GF2E& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(GF2EX& x, const vec_GF2E& v, long low, long high, const vec_GF2EX& H, long n, GF2XVec& t) { GF2X s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_GF2E& h = H[i-low].rep; long m = h.length(); const GF2X& w = rep(v[i]); for (j = 0; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) conv(x.rep[j], t[j]); x.normalize(); } void CompMod(GF2EX& x, const GF2EX& g, const GF2EXArgument& A, const GF2EXModulus& F) { if (deg(g) <= 0) { x = g; return; } GF2EX s, t; GF2XVec scratch(F.n, 2*GF2E::WordLength()); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const GF2EX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(GF2EXArgument& A, const GF2EX& h, const GF2EXModulus& F, long m) { long i; if (m <= 0 || deg(h) >= F.n) Error("build GF2EXArgument: bad args"); if (m > F.n) m = F.n; if (GF2EXArgBound > 0) { double sz = GF2E::storage(); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_GF2E); sz = sz/1024; m = min(m, long(GF2EXArgBound/sz)); m = max(m, 1); } A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], h, F); } NTL_THREAD_LOCAL long GF2EXArgBound = 0; void CompMod(GF2EX& x, const GF2EX& g, const GF2EX& h, const GF2EXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } GF2EXArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(GF2EX& x1, GF2EX& x2, const GF2EX& g1, const GF2EX& g2, const GF2EX& h, const GF2EXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } GF2EXArgument A; build(A, h, F, m); GF2EX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(GF2EX& x1, GF2EX& x2, GF2EX& x3, const GF2EX& g1, const GF2EX& g2, const GF2EX& g3, const GF2EX& h, const GF2EXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } GF2EXArgument A; build(A, h, F, m); GF2EX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } void build(GF2EXTransMultiplier& B, const GF2EX& b, const GF2EXModulus& F) { long db = deg(b); if (db >= F.n) Error("build TransMultiplier: bad args"); GF2EX t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, d); // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, d); if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, db); } void TransMulMod(GF2EX& x, const GF2EX& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F) { if (deg(a) >= F.n) Error("TransMulMod: bad args"); GF2EX t1, t2; mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); LeftShift(t2, t2, 1); add(x, t1, t2); } void UpdateMap(vec_GF2E& x, const vec_GF2E& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F) { GF2EX xx; TransMulMod(xx, to_GF2EX(a), B, F); x = xx.rep; } static void ProjectPowers(vec_GF2E& x, const GF2EX& a, long k, const GF2EXArgument& H, const GF2EXModulus& F) { if (k < 0 || NTL_OVERFLOW(k, 1, 0) || deg(a) >= F.n) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; GF2EXTransMultiplier M; build(M, H.H[m], F); GF2EX s; s = a; x.SetLength(k); long i; for (i = 0; i <= l; i++) { long m1 = min(m, k-i*m); for (long j = 0; j < m1; j++) InnerProduct(x[i*m+j], H.H[j].rep, s.rep); if (i < l) TransMulMod(s, s, M, F); } } static void ProjectPowers(vec_GF2E& x, const GF2EX& a, long k, const GF2EX& h, const GF2EXModulus& F) { if (k < 0 || deg(a) >= F.n || deg(h) >= F.n) Error("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0);; return; } long m = SqrRoot(k); GF2EXArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F) { ProjectPowers(x, to_GF2EX(a), k, H, F); } void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F) { ProjectPowers(x, to_GF2EX(a), k, h, F); } void BerlekampMassey(GF2EX& h, const vec_GF2E& a, long m) { GF2EX Lambda, Sigma, Temp; long L; GF2E Delta, Delta1, t1; long shamt; GF2X tt1, tt2; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(tt1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(tt2, rep(Lambda.rep[i]), rep(a[r-i-1])); add(tt1, tt1, tt2); } conv(Delta1, tt1); if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftAdd(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftAdd(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void MinPolySeq(GF2EX& h, const vec_GF2E& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) Error("MinPoly: bad args"); if (a.length() < 2*m) Error("MinPoly: sequence too short"); BerlekampMassey(h, a, m); } void DoMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m, const GF2EX& R) { vec_GF2E x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) Error("ProbMinPoly: bad args"); GF2EX R; random(R, n); DoMinPolyMod(h, g, F, m, R); } void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } void MinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F, long m) { GF2EX h, h1; long n = F.n; if (m < 1 || m > n) Error("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ GF2EX h2, h3; GF2EX R; GF2EXTransMultiplier H1; for (;;) { random(R, n); build(H1, h1, F); TransMulMod(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m) { if (m < 1 || m > F.n) Error("IrredPoly: bad args"); GF2EX R; set(R); DoMinPolyMod(h, g, F, m, R); } void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F) { IrredPolyMod(h, g, F, F.n); } void MinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F) { MinPolyMod(hh, g, F, F.n); } void MakeMonic(GF2EX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; GF2E t; inv(t, LeadCoeff(x)); mul(x, x, t); } long divide(GF2EX& q, const GF2EX& a, const GF2EX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } GF2EX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const GF2EX& a, const GF2EX& b) { if (IsZero(b)) return IsZero(a); GF2EX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } long operator==(const GF2EX& a, long b) { if (b & 1) return IsOne(a); else return IsZero(a); } long operator==(const GF2EX& a, GF2 b) { if (b == 1) return IsOne(a); else return IsZero(a); } long operator==(const GF2EX& a, const GF2E& b) { if (IsZero(b)) return IsZero(a); if (deg(a) != 0) return 0; return a.rep[0] == b; } void power(GF2EX& x, const GF2EX& a, long e) { if (e < 0) { Error("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) Error("overflow in power"); GF2EX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } void reverse(GF2EX& x, const GF2EX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) Error("overflow in reverse"); if (&x == &a) { GF2EX tmp; CopyReverse(tmp, a, hi); x = tmp; } else CopyReverse(x, a, hi); } static void FastTraceVec(vec_GF2E& S, const GF2EXModulus& f) { long n = deg(f); GF2EX x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); S.SetLength(n); S[0] = n; long i; for (i = 1; i < n; i++) S[i] = coeff(x, i); } void PlainTraceVec(vec_GF2E& S, const GF2EX& ff) { if (deg(ff) <= 0) Error("TraceVec: bad args"); GF2EX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; GF2X acc, t; GF2E t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } } void TraceVec(vec_GF2E& S, const GF2EX& f) { if (deg(f) < GF2E::DivCross()) PlainTraceVec(S, f); else FastTraceVec(S, f); } static void ComputeTraceVec(const GF2EXModulus& F) { vec_GF2E& S = *((vec_GF2E *) &F.tracevec); if (S.length() > 0) return; if (F.method == GF2EX_MOD_PLAIN) { PlainTraceVec(S, F.f); } else { FastTraceVec(S, F); } } void TraceMod(GF2E& x, const GF2EX& a, const GF2EXModulus& F) { long n = F.n; if (deg(a) >= n) Error("trace: bad args"); // FIXME: in a thread safe version, we should use // some kind of mutex if (F.tracevec.length() == 0) ComputeTraceVec(F); InnerProduct(x, a.rep, F.tracevec); } void TraceMod(GF2E& x, const GF2EX& a, const GF2EX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) Error("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(GF2E& rres, const GF2EX& a, const GF2EX& b) { GF2E res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; GF2E lc; set(res); long n = max(deg(a),deg(b)) + 1; GF2EX u(INIT_SIZE, n), v(INIT_SIZE, n); GF2XVec tmp(n, 2*GF2E::WordLength()); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v, tmp); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } rres = res; } } void resultant(GF2E& rres, const GF2EX& a, const GF2EX& b) { PlainResultant(rres, a, b); } void NormMod(GF2E& x, const GF2EX& a, const GF2EX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) Error("norm: bad args"); if (IsZero(a)) { clear(x); return; } GF2E t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { GF2E t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } // tower stuff... void InnerProduct(GF2EX& x, const GF2X& v, long low, long high, const vec_GF2EX& H, long n, vec_GF2E& t) { long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, deg(v)); for (i = low; i <= high; i++) { const vec_GF2E& h = H[i-low].rep; long m = h.length(); if (coeff(v, i) != 0) { for (j = 0; j < m; j++) { add(t[j], t[j], h[j]); } } } x.rep.SetLength(n); for (j = 0; j < n; j++) x.rep[j] = t[j]; x.normalize(); } void CompTower(GF2EX& x, const GF2X& g, const GF2EXArgument& A, const GF2EXModulus& F) { if (deg(g) <= 0) { conv(x, g); return; } GF2EX s, t; vec_GF2E scratch; scratch.SetLength(deg(F)); long m = A.H.length() - 1; long l = (((deg(g)+1)+m-1)/m) - 1; const GF2EX& M = A.H[m]; InnerProduct(t, g, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void CompTower(GF2EX& x, const GF2X& g, const GF2EX& h, const GF2EXModulus& F) // x = g(h) mod f { long m = SqrRoot(deg(g)+1); if (m == 0) { clear(x); return; } GF2EXArgument A; build(A, h, F, m); CompTower(x, g, A, F); } void PrepareProjection(vec_vec_GF2& tt, const vec_GF2E& s, const vec_GF2& proj) { long l = s.length(); tt.SetLength(l); GF2XTransMultiplier M; long i; for (i = 0; i < l; i++) { build(M, rep(s[i]), GF2E::modulus()); UpdateMap(tt[i], proj, M, GF2E::modulus()); } } void ProjectedInnerProduct(ref_GF2 x, const vec_GF2E& a, const vec_vec_GF2& b) { long n = min(a.length(), b.length()); GF2 t, res; res = 0; long i; for (i = 0; i < n; i++) { project(t, b[i], rep(a[i])); res += t; } x = res; } void PrecomputeProj(vec_GF2& proj, const GF2X& f) { long n = deg(f); if (n <= 0) Error("PrecomputeProj: bad args"); if (ConstTerm(f) != 0) { proj.SetLength(1); proj[0] = 1; } else { proj.SetLength(n); clear(proj); proj[n-1] = 1; } } void ProjectPowersTower(vec_GF2& x, const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F, const vec_GF2& proj) { long n = F.n; if (a.length() > n || k < 0) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; GF2EXTransMultiplier M; build(M, H.H[m], F); vec_GF2E s(INIT_SIZE, n); s = a; x.SetLength(k); vec_vec_GF2 tt; for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); PrepareProjection(tt, s, proj); for (long j = 0; j < m1; j++) { GF2 r; ProjectedInnerProduct(r, H.H[j].rep, tt); x.put(i*m + j, r); } if (i < l) UpdateMap(s, s, M, F); } } void ProjectPowersTower(vec_GF2& x, const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F, const vec_GF2& proj) { if (a.length() > F.n || k < 0) Error("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); GF2EXArgument H; build(H, h, F, m); ProjectPowersTower(x, a, k, H, F, proj); } void DoMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m, const vec_GF2E& R, const vec_GF2& proj) { vec_GF2 x; ProjectPowersTower(x, R, 2*m, g, F, proj); MinPolySeq(h, x, m); } void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m) { long n = F.n; if (m < 1 || m > n*GF2E::degree()) Error("ProbMinPoly: bad args"); vec_GF2E R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); vec_GF2 proj; PrecomputeProj(proj, GF2E::modulus()); DoMinPolyTower(h, g, F, m, R, proj); } void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m, const vec_GF2& proj) { long n = F.n; if (m < 1 || m > n*GF2E::degree()) Error("ProbMinPoly: bad args"); vec_GF2E R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); DoMinPolyTower(h, g, F, m, R, proj); } void MinPolyTower(GF2X& hh, const GF2EX& g, const GF2EXModulus& F, long m) { GF2X h; GF2EX h1; long n = F.n; if (m < 1 || m > n*GF2E::degree()) { Error("MinPoly: bad args"); } vec_GF2 proj; PrecomputeProj(proj, GF2E::modulus()); /* probabilistically compute min-poly */ ProbMinPolyTower(h, g, F, m, proj); if (deg(h) == m) { hh = h; return; } CompTower(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; GF2X h2; GF2EX h3; vec_GF2E R; GF2EXTransMultiplier H1; for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyTower(h2, g, F, m-deg(h), R, proj); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompTower(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m) { if (m < 1 || m > deg(F)*GF2E::degree()) Error("IrredPoly: bad args"); vec_GF2E R; R.SetLength(1); R[0] = 1; vec_GF2 proj; proj.SetLength(1); proj.put(0, 1); DoMinPolyTower(h, g, F, m, R, proj); } NTL_END_IMPL ntl-6.2.1/src/GF2EXFactoring.c000644 000765 000024 00000112151 12377144456 016237 0ustar00shoupstaff000000 000000 #include #include #include #include #include #include NTL_START_IMPL static void IterSqr(GF2E& c, const GF2E& a, long n) { GF2E res; long i; res = a; for (i = 0; i < n; i++) sqr(res, res); c = res; } void SquareFreeDecomp(vec_pair_GF2EX_long& u, const GF2EX& ff) { GF2EX f = ff; if (!IsOne(LeadCoeff(f))) Error("SquareFreeDecomp: bad args"); GF2EX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a square */ long k, d; d = deg(r)/2; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) IterSqr(f.rep[k], r.rep[k*2], GF2E::degree()-1); m = m*2; } } while (!finished); } static void NullSpace(long& r, vec_long& D, vec_GF2XVec& M, long verbose) { long k, l, n; long i, j; long pos; GF2X t1, t2; GF2X *x, *y; const GF2XModulus& p = GF2E::modulus(); n = M.length(); D.SetLength(n); for (j = 0; j < n; j++) D[j] = -1; r = 0; l = 0; for (k = 0; k < n; k++) { if (verbose && k % 10 == 0) cerr << "+"; pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { swap(M[pos], M[l]); // make M[l, k] == -1 mod p, and make row l reduced InvMod(t1, M[l][k], p); for (j = k+1; j < n; j++) { rem(t2, M[l][j], p); MulMod(M[l][j], t2, t1, p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } D[k] = l; // variable k is defined by row l l++; } else { r++; } } } static void BuildMatrix(vec_GF2XVec& M, long n, const GF2EX& g, const GF2EXModulus& F, long verbose) { long i, j, m; GF2EX h; M.SetLength(n); for (i = 0; i < n; i++) M[i].SetSize(n, 2*GF2E::WordLength()); set(h); for (j = 0; j < n; j++) { if (verbose && j % 10 == 0) cerr << "+"; m = deg(h); for (i = 0; i < n; i++) { if (i <= m) M[i][j] = rep(h.rep[i]); else clear(M[i][j]); } if (j < n-1) MulMod(h, h, g, F); } for (i = 0; i < n; i++) add(M[i][i], M[i][i], 1); } static void TraceMap(GF2EX& h, const GF2EX& a, const GF2EXModulus& F) // one could consider making a version based on modular composition, // as in ComposeFrobeniusMap... { GF2EX res, tmp; res = a; tmp = a; long i; for (i = 0; i < GF2E::degree()-1; i++) { SqrMod(tmp, tmp, F); add(res, res, tmp); } h = res; } void PlainFrobeniusMap(GF2EX& h, const GF2EXModulus& F) { GF2EX res; SetX(res); long i; for (i = 0; i < GF2E::degree(); i++) SqrMod(res, res, F); h = res; } long UseComposeFrobenius(long d, long n) { long i; i = 1; while (i <= d) i = i << 1; i = i >> 1; i = i >> 1; long m = 1; long dz; if (n == 2) { dz = 1; } else { while (i) { long m1 = 2*m; if (i & d) m1++; if (m1 >= NTL_BITS_PER_LONG-1 || (1L << m1) >= n) break; m = m1; i = i >> 1; } dz = 1L << m; } long rootn = SqrRoot(n); long cnt = 0; if (i) { cnt += SqrRoot(dz+1); i = i >> 1; } while (i) { cnt += rootn; i = i >> 1; } return 4*cnt <= d; } void ComposeFrobeniusMap(GF2EX& y, const GF2EXModulus& F) { long d = GF2E::degree(); long n = deg(F); long i; i = 1; while (i <= d) i = i << 1; i = i >> 1; GF2EX z(INIT_SIZE, n), z1(INIT_SIZE, n); i = i >> 1; long m = 1; if (n == 2) { SetX(z); SqrMod(z, z, F); } else { while (i) { long m1 = 2*m; if (i & d) m1++; if (m1 >= NTL_BITS_PER_LONG-1 || (1L << m1) >= n) break; m = m1; i = i >> 1; } clear(z); SetCoeff(z, 1L << m); } while (i) { z1 = z; long j, k, dz; dz = deg(z); for (j = 0; j <= dz; j++) for (k = 0; k < m; k++) sqr(z1.rep[j], z1.rep[j]); CompMod(z, z1, z, F); m = 2*m; if (d & i) { SqrMod(z, z, F); m++; } i = i >> 1; } y = z; } void FrobeniusMap(GF2EX& h, const GF2EXModulus& F) { long n = deg(F); long d = GF2E::degree(); if (n == 1) { h = ConstTerm(F); return; } if (UseComposeFrobenius(d, n)) ComposeFrobeniusMap(h, F); else PlainFrobeniusMap(h, F); } static void RecFindRoots(vec_GF2E& x, const GF2EX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); x[k] = ConstTerm(f); return; } GF2EX h; GF2E r; { GF2EXModulus F; build(F, f); do { random(r); clear(h); SetCoeff(h, 1, r); TraceMap(h, h, F); GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_GF2E& x, const GF2EX& ff) { GF2EX f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoots: bad args"); x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } static void RandomBasisElt(GF2EX& g, const vec_long& D, const vec_GF2XVec& M) { GF2X t1, t2; long n = D.length(); long i, j, s; g.rep.SetLength(n); vec_GF2E& v = g.rep; for (j = n-1; j >= 0; j--) { if (D[j] == -1) random(v[j]); else { i = D[j]; // v[j] = sum_{s=j+1}^{n-1} v[s]*M[i,s] clear(t1); for (s = j+1; s < n; s++) { mul(t2, rep(v[s]), M[i][s]); add(t1, t1, t2); } conv(v[j], t1); } } g.normalize(); } static void split(GF2EX& f1, GF2EX& g1, GF2EX& f2, GF2EX& g2, const GF2EX& f, const GF2EX& g, const vec_GF2E& roots, long lo, long mid) { long r = mid-lo+1; GF2EXModulus F; build(F, f); vec_GF2E lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; GF2EX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } static void RecFindFactors(vec_GF2EX& factors, const GF2EX& f, const GF2EX& g, const vec_GF2E& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } GF2EX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } static void FindFactors(vec_GF2EX& factors, const GF2EX& f, const GF2EX& g, const vec_GF2E& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } #if 0 static void IterFindFactors(vec_GF2EX& factors, const GF2EX& f, const GF2EX& g, const vec_GF2E& roots) { long r = roots.length(); long i; GF2EX h; factors.SetLength(r); for (i = 0; i < r; i++) { add(h, g, roots[i]); GCD(factors[i], f, h); } } #endif void SFBerlekamp(vec_GF2EX& factors, const GF2EX& ff, long verbose) { GF2EX f = ff; if (!IsOne(LeadCoeff(f))) Error("SFBerlekamp: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } double t; long n = deg(f); GF2EXModulus F; build(F, f); GF2EX g, h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } FrobeniusMap(g, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_long D; long r; vec_GF2XVec M; if (verbose) { cerr << "building matrix..."; t = GetTime(); } BuildMatrix(M, n, g, F, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "diagonalizing..."; t = GetTime(); } NullSpace(r, D, M, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) cerr << "number of factors = " << r << "\n"; if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (verbose) { cerr << "factor extraction..."; t = GetTime(); } vec_GF2E roots; RandomBasisElt(g, D, M); MinPolyMod(h, g, F, r); if (deg(h) == r) M.kill(); FindRoots(roots, h); FindFactors(factors, f, g, roots); GF2EX g1; vec_GF2EX S, S1; long i; while (factors.length() < r) { if (verbose) cerr << "+"; RandomBasisElt(g, D, M); S.kill(); for (i = 0; i < factors.length(); i++) { const GF2EX& f = factors[i]; if (deg(f) == 1) { append(S, f); continue; } build(F, f); rem(g1, g, F); if (deg(g1) <= 0) { append(S, f); continue; } MinPolyMod(h, g1, F, min(deg(f), r-factors.length()+1)); FindRoots(roots, h); S1.kill(); FindFactors(S1, f, g1, roots); append(S, S1); } swap(factors, S); } if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "degrees:"; long i; for (i = 0; i < factors.length(); i++) cerr << " " << deg(factors[i]); cerr << "\n"; } } void berlekamp(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose) { double t; vec_pair_GF2EX_long sfd; vec_GF2EX x; if (!IsOne(LeadCoeff(f))) Error("berlekamp: bad args"); if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFBerlekamp(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } static void AddFactor(vec_pair_GF2EX_long& factors, const GF2EX& g, long d, long verbose) { if (verbose) cerr << "degree=" << d << ", number=" << deg(g)/d << "\n"; append(factors, cons(g, d)); } static void ProcessTable(GF2EX& f, vec_pair_GF2EX_long& factors, const GF2EXModulus& F, long limit, const vec_GF2EX& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; GF2EX t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); GF2EX t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); } void TraceMap(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& b) { if (d < 0) Error("TraceMap: bad args"); GF2EX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(GF2EX& y, const GF2EX& h, long q, const GF2EXModulus& F) { if (q < 0) Error("powerCompose: bad args"); GF2EX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const GF2EX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; GF2EXModulus F; build(F, f); GF2EX b, r, s; FrobeniusMap(b, F); long all_zero = 1; long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); all_zero = all_zero && IsZero(s); if (deg(s) > 0) return 0; } if (!all_zero || (n & 1)) return 1; PowerCompose(s, b, n/2, F); return !IsX(s); } NTL_THREAD_LOCAL long GF2EX_BlockingFactor = 10; void DDF(vec_pair_GF2EX_long& factors, const GF2EX& ff, const GF2EX& hh, long verbose) { GF2EX f = ff; GF2EX h = hh; if (!IsOne(LeadCoeff(f))) Error("DDF: bad args"); factors.SetLength(0); if (deg(f) == 0) return; if (deg(f) == 1) { AddFactor(factors, f, 1, verbose); return; } long CompTableSize = 2*SqrRoot(deg(f)); long GCDTableSize = GF2EX_BlockingFactor; GF2EXModulus F; build(F, f); GF2EXArgument H; build(H, h, F, min(CompTableSize, deg(f))); long i, d, limit, old_n; GF2EX g, X; vec_GF2EX tbl(INIT_SIZE, GCDTableSize); SetX(X); i = 0; g = h; d = 1; limit = GCDTableSize; while (2*d <= deg(f)) { old_n = deg(f); add(tbl[i], g, X); i++; if (i == limit) { ProcessTable(f, factors, F, i, tbl, d, verbose); i = 0; } d = d + 1; if (2*d <= deg(f)) { // we need to go further if (deg(f) < old_n) { // f has changed build(F, f); rem(h, h, f); rem(g, g, f); build(H, h, F, min(CompTableSize, deg(f))); } CompMod(g, g, H, F); } } ProcessTable(f, factors, F, i, tbl, d-1, verbose); if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose); } void RootEDF(vec_GF2EX& factors, const GF2EX& f, long verbose) { vec_GF2E roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); add(factors[j], factors[j], roots[j]); } } static void EDFSplit(vec_GF2EX& v, const GF2EX& f, const GF2EX& b, long d) { GF2EX a, g, h; GF2EXModulus F; vec_GF2E roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } static void RecEDF(vec_GF2EX& factors, const GF2EX& f, const GF2EX& b, long d, long verbose) { vec_GF2EX v; long i; GF2EX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { GF2EX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_GF2EX& factors, const GF2EX& ff, const GF2EX& bb, long d, long verbose) { GF2EX f = ff; GF2EX b = bb; if (!IsOne(LeadCoeff(f))) Error("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_GF2EX& factors, const GF2EX& ff, long verbose) { GF2EX f = ff; if (!IsOne(LeadCoeff(f))) Error("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; GF2EXModulus F; build(F, f); GF2EX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } FrobeniusMap(h, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_GF2EX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } GF2EX hh; vec_GF2EX v; long i; for (i = 0; i < u.length(); i++) { const GF2EX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose) { if (!IsOne(LeadCoeff(f))) Error("CanZass: bad args"); double t; vec_pair_GF2EX_long sfd; vec_GF2EX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(GF2EX& f, const vec_pair_GF2EX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); GF2EX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } static long BaseCase(const GF2EX& h, long q, long a, const GF2EXModulus& F) { long b, e; GF2EX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } static void TandemPowerCompose(GF2EX& y1, GF2EX& y2, const GF2EX& h, long q1, long q2, const GF2EXModulus& F) { GF2EX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } static long RecComputeDegree(long u, const GF2EX& h, const GF2EXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); GF2EX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long RecComputeDegree(const GF2EX& h, const GF2EXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } void FindRoot(GF2E& root, const GF2EX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { GF2EXModulus F; GF2EX h, h1, f; GF2E r; f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoot: bad args"); if (deg(f) == 0) Error("FindRoot: bad args"); while (deg(f) > 1) { build(F, f); random(r); clear(h); SetCoeff(h, 1, r); TraceMap(h, h, F); GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } root = ConstTerm(f); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const GF2EX& h, long q, long a, const GF2EXModulus& F) { long e; GF2EX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); add(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const GF2EX& h, const GF2EXModulus& F, const FacVec& fvec) { long q1, q2; GF2EX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const GF2EX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; GF2EXModulus F; build(F, f); GF2EX h; FrobeniusMap(h, F); GF2EX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const GF2EX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; GF2EXModulus F; build(F, f); GF2EX h; FrobeniusMap(h, F); long CompTableSize = 2*SqrRoot(deg(f)); GF2EXArgument H; build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; GF2EX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { add(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { CompMod(g, g, H, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_GF2EX& h, const GF2EX& f, const GF2EX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { GF2EX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); add(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); add(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(GF2EX& x, const GF2EX& f, const GF2EX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_GF2EX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_GF2E a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(GF2EX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(GF2EX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { GF2EX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(GF2EX& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } #if 0 void BuildIrred(GF2EX& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } GF2EX g; do { random(g, n); SetCoeff(g, n); } while (!IterIrredTest(g)); f = g; } #endif void BuildRandomIrred(GF2EX& f, const GF2EX& g) { GF2EXModulus G; GF2EX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_THREAD_LOCAL long GF2EX_GCDTableSize = 4; NTL_THREAD_LOCAL char GF2EX_stem[256] = ""; NTL_THREAD_LOCAL double GF2EXFileThresh = NTL_FILE_THRESH; NTL_THREAD_LOCAL static vec_GF2EX BabyStepFile; NTL_THREAD_LOCAL static vec_GF2EX GiantStepFile; NTL_THREAD_LOCAL static long use_files; // FIXME: in a thread-safe implementation, we have to rethink the // use of external files for auxilliary storage...there could be // name clashes...maybe use thread IDs? static double CalcTableSize(long n, long k) { double sz = GF2E::storage(); sz = sz * n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_GF2E); sz = sz * k; sz = sz/1024; return sz; } static void GenerateBabySteps(GF2EX& h1, const GF2EX& f, const GF2EX& h, long k, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } GF2EXModulus F; build(F, f); GF2EXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); h1 = h; long i; long HexOutput = GF2X::HexOutput; GF2X::HexOutput = 1; if (!use_files) { BabyStepFile.kill(); BabyStepFile.SetLength(k-1); } for (i = 1; i <= k-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName(GF2EX_stem, "baby", i)); s << h1 << "\n"; s.close(); } else BabyStepFile(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (verbose) cerr << (GetTime()-t) << "\n"; GF2X::HexOutput = HexOutput; } static void GenerateGiantSteps(const GF2EX& f, const GF2EX& h, long l, long verbose) { double t; if (verbose) { cerr << "generating giant steps..."; t = GetTime(); } GF2EXModulus F; build(F, f); GF2EXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); GF2EX h1; h1 = h; long i; long HexOutput = GF2X::HexOutput; GF2X::HexOutput = 1; if (!use_files) { GiantStepFile.kill(); GiantStepFile.SetLength(l); } for (i = 1; i <= l-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName(GF2EX_stem, "giant", i)); s << h1 << "\n"; s.close(); } else GiantStepFile(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (use_files) { ofstream s; OpenWrite(s, FileName(GF2EX_stem, "giant", i)); s << h1 << "\n"; s.close(); } else GiantStepFile(i) = h1; if (verbose) cerr << (GetTime()-t) << "\n"; GF2X::HexOutput = HexOutput; } static void FileCleanup(long k, long l) { if (use_files) { long i; for (i = 1; i <= k-1; i++) remove(FileName(GF2EX_stem, "baby", i)); for (i = 1; i <= l; i++) remove(FileName(GF2EX_stem, "giant", i)); } else { BabyStepFile.kill(); GiantStepFile.kill(); } } static void NewAddFactor(vec_pair_GF2EX_long& u, const GF2EX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_GF2EX_long& u, GF2EX& f, const GF2EXModulus& F, vec_GF2EX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; GF2EX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(GF2EX& g, long gs, const GF2EXModulus& F) { if (use_files) { ifstream s; OpenRead(s, FileName(GF2EX_stem, "giant", gs)); s >> g; s.close(); } else g = GiantStepFile(gs); rem(g, g, F); } static void FetchBabySteps(vec_GF2EX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { if (use_files) { ifstream s; OpenRead(s, FileName(GF2EX_stem, "baby", i)); s >> v[i]; s.close(); } else v[i] = BabyStepFile(i); } } static void GiantRefine(vec_pair_GF2EX_long& u, const GF2EX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_GF2EX BabyStep; FetchBabySteps(BabyStep, k); vec_GF2EX buf(INIT_SIZE, GF2EX_GCDTableSize); GF2EX f; f = ff; GF2EXModulus F; build(F, f); GF2EX g; GF2EX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); add(buf[size-1], g, BabyStep[bs]); } else { add(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == GF2EX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_GF2EX_long& factors, const GF2EX& ff, long k, long gs, const vec_GF2EX& BabyStep, long verbose) { vec_GF2EX buf(INIT_SIZE, GF2EX_GCDTableSize); GF2EX f; f = ff; GF2EXModulus F; build(F, f); GF2EX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); add(buf[size], buf[size], g); size++; if (size == GF2EX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_GF2EX_long& factors, const vec_pair_GF2EX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_GF2EX BabyStep; long i; for (i = 0; i < u.length(); i++) { const GF2EX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h, long verbose) { if (!IsOne(LeadCoeff(f))) Error("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } if (!GF2EX_stem[0]) sprintf(GF2EX_stem, "ddf-%ld", RandomBnd(10000)); long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; GF2EX h1; if (CalcTableSize(deg(f), k + l - 1) > GF2EXFileThresh) use_files = 1; else use_files = 0; GenerateBabySteps(h1, f, h, k, verbose); GenerateGiantSteps(f, h1, l, verbose); vec_pair_GF2EX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); FileCleanup(k, l); } long IterComputeDegree(const GF2EX& h, const GF2EXModulus& F) { long n = deg(F); if (n == 1 || IsX(h)) return 1; long B = n/2; long k = SqrRoot(B); long l = (B+k-1)/k; GF2EXArgument H; #if 0 double n2 = sqrt(double(n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); GF2EX h1; h1 = h; vec_GF2EX baby; baby.SetLength(k); SetX(baby[0]); long i; for (i = 1; i <= k-1; i++) { baby[i] = h1; CompMod(h1, h1, H, F); if (IsX(h1)) return i+1; } build(H, h1, F, sz); long j; for (j = 2; j <= l; j++) { CompMod(h1, h1, H, F); for (i = k-1; i >= 0; i--) { if (h1 == baby[i]) return j*k-i; } } return n; } NTL_END_IMPL ntl-6.2.1/src/GF2EXTest.c000644 000765 000024 00000004062 12377144457 015244 0ustar00shoupstaff000000 000000 #include #include NTL_OPEN_NNS void PlainMul(GF2EX&, const GF2EX&, const GF2EX&); NTL_CLOSE_NNS NTL_CLIENT int main() { GF2X p; BuildIrred(p, 200); GF2E::init(p); GF2EX f; SetCoeff(f, 41); SetCoeff(f, 1); SetCoeff(f, 0); GF2X a; SetCoeff(a, 117); SetCoeff(a, 10); SetCoeff(a, 0); GF2EX g, h; SetX(g); SetCoeff(g, 0, to_GF2E(a)); MinPolyMod(h, g, f); f = h; vec_pair_GF2EX_long u; CanZass(u, f, 1); cerr << "factorization pattern:"; long i; for (i = 0; i < u.length(); i++) { cerr << " "; long k = u[i].b; if (k > 1) cerr << k << "*"; cerr << deg(u[i].a); } cerr << "\n\n\n"; GF2EX ff; mul(ff, u); if (f != ff || u.length() != 11) { cerr << "GF2EXTest NOT OK\n"; return 1; } { cerr << "multiplication test...\n"; BuildIrred(p, 512); GF2E::init(p); GF2EX A, B, C, C1; random(A, 512); random(B, 512); double t; long i; t = GetTime(); for (i = 0; i < 10; i++) PlainMul(C, A, B); t = GetTime() - t; cerr << "time for plain mul of degree 511 over GF(2^512): " << (t/10) << "s\n"; t = GetTime(); for (i = 0; i < 10; i++) mul(C1, A, B); t = GetTime() - t; cerr << "time for karatsuba mul of degree 511 over GF(2^512): " << (t/10) << "s\n"; if (C != C1) { cerr << "GF2EXTest NOT OK\n"; return 1; } } { cerr << "multiplication test...\n"; BuildIrred(p, 16); GF2E::init(p); GF2EX A, B, C, C1; random(A, 512); random(B, 512); double t; t = GetTime(); for (i = 0; i < 10; i++) PlainMul(C, A, B); t = GetTime() - t; cerr << "time for plain mul of degree 511 over GF(2^16): " << (t/10) << "s\n"; t = GetTime(); for (i = 0; i < 10; i++) mul(C1, A, B); t = GetTime() - t; cerr << "time for karatsuba mul of degree 511 over GF(2^16): " << (t/10) << "s\n"; if (C != C1) { cerr << "GF2EXTest NOT OK\n"; return 1; } } cerr << "GF2EXTest OK\n"; return 0; } ntl-6.2.1/src/GF2X.c000644 000765 000024 00000120345 12377144456 014301 0ustar00shoupstaff000000 000000 #include #include #include #include #if (defined(NTL_WIZARD_HACK) && defined(NTL_GF2X_LIB)) #undef NTL_GF2X_LIB #endif #ifdef NTL_GF2X_LIB #include #endif NTL_START_IMPL long GF2X::HexOutput = 0; void GF2X::SetMaxLength(long n) { if (n < 0) Error("GF2X::SetMaxLength: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("GF2X::SetMaxLength: excessive length"); long w = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; xrep.SetMaxLength(w); } GF2X::GF2X(INIT_SIZE_TYPE, long n) { SetMaxLength(n); } const GF2X& GF2X::zero() { NTL_THREAD_LOCAL static GF2X z; return z; } void GF2X::normalize() { long n; const _ntl_ulong *p; n = xrep.length(); if (n == 0) return; p = xrep.elts() + n; while (n > 0 && (*--p) == 0) { n--; } xrep.QuickSetLength(n); } void GF2X::SetLength(long n) { if (n < 0) { Error("SetLength: negative index"); return; } long w = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long old_w = xrep.length(); xrep.SetLength(w); long i; if (w > old_w) { // zero out new words for (i = old_w; i < w; i++) xrep[i] = 0; } else { // zero out high order bits of last word long wi = n/NTL_BITS_PER_LONG; long bi = n - wi*NTL_BITS_PER_LONG; if (bi == 0) return; unsigned long mask = (1UL << bi) - 1UL; xrep[wi] &= mask; } } ref_GF2 GF2X::operator[](long i) { if (i < 0) Error("GF2X: subscript out of range"); long wi = i/NTL_BITS_PER_LONG; if (wi >= xrep.length()) Error("GF2X: subscript out of range"); long bi = i - wi*NTL_BITS_PER_LONG; return ref_GF2(INIT_LOOP_HOLE, &xrep[wi], bi); } const GF2 GF2X::operator[](long i) const { if (i < 0) Error("GF2X: subscript out of range"); long wi = i/NTL_BITS_PER_LONG; if (wi >= xrep.length()) Error("GF2X: subscript out of range"); long bi = i - wi*NTL_BITS_PER_LONG; return to_GF2((xrep[wi] & (1UL << bi)) != 0); } long IsZero(const GF2X& a) { return a.xrep.length() == 0; } long IsOne(const GF2X& a) { return a.xrep.length() == 1 && a.xrep[0] == 1; } long IsX(const GF2X& a) { return a.xrep.length() == 1 && a.xrep[0] == 2; } const GF2 coeff(const GF2X& a, long i) { if (i < 0) return to_GF2(0); long wi = i/NTL_BITS_PER_LONG; if (wi >= a.xrep.length()) return to_GF2(0); long bi = i - wi*NTL_BITS_PER_LONG; return to_GF2((a.xrep[wi] & (1UL << bi)) != 0); } const GF2 LeadCoeff(const GF2X& a) { if (IsZero(a)) return to_GF2(0); else return to_GF2(1); } const GF2 ConstTerm(const GF2X& a) { if (IsZero(a)) return to_GF2(0); else return to_GF2((a.xrep[0] & 1) != 0); } void set(GF2X& x) { x.xrep.SetLength(1); x.xrep[0] = 1; } void SetX(GF2X& x) { x.xrep.SetLength(1); x.xrep[0] = 2; } void SetCoeff(GF2X& x, long i) { if (i < 0) { Error("SetCoeff: negative index"); return; } long n, j; n = x.xrep.length(); long wi = i/NTL_BITS_PER_LONG; if (wi >= n) { x.xrep.SetLength(wi+1); for (j = n; j <= wi; j++) x.xrep[j] = 0; } long bi = i - wi*NTL_BITS_PER_LONG; x.xrep[wi] |= (1UL << bi); } void SetCoeff(GF2X& x, long i, long val) { if (i < 0) { Error("SetCoeff: negative index"); return; } val = val & 1; if (val) { SetCoeff(x, i); return; } // we want to clear position i long n; n = x.xrep.length(); long wi = i/NTL_BITS_PER_LONG; if (wi >= n) return; long bi = i - wi*NTL_BITS_PER_LONG; x.xrep[wi] &= ~(1UL << bi); if (wi == n-1 && !x.xrep[wi]) x.normalize(); } void SetCoeff(GF2X& x, long i, GF2 a) { SetCoeff(x, i, rep(a)); } void swap(GF2X& a, GF2X& b) { swap(a.xrep, b.xrep); } long deg(const GF2X& aa) { long n = aa.xrep.length(); if (n == 0) return -1; _ntl_ulong a = aa.xrep[n-1]; long i = 0; if (a == 0) Error("GF2X: unnormalized polynomial detected in deg"); while (a>=256) i += 8, a >>= 8; if (a >=16) i += 4, a >>= 4; if (a >= 4) i += 2, a >>= 2; if (a >= 2) i += 2; else if (a >= 1) i++; return NTL_BITS_PER_LONG*(n-1) + i - 1; } long operator==(const GF2X& a, const GF2X& b) { return a.xrep == b.xrep; } long operator==(const GF2X& a, long b) { if (b & 1) return IsOne(a); else return IsZero(a); } long operator==(const GF2X& a, GF2 b) { if (b == 1) return IsOne(a); else return IsZero(a); } static istream & HexInput(istream& s, GF2X& a) { long n; long c; long i; long val; GF2X ibuf; n = 0; clear(ibuf); c = s.peek(); val = CharToIntVal(c); while (val != -1) { for (i = 0; i < 4; i++) if (val & (1L << i)) SetCoeff(ibuf, n+i); n += 4; s.get(); c = s.peek(); val = CharToIntVal(c); } a = ibuf; return s; } istream & operator>>(istream& s, GF2X& a) { NTL_ZZRegister(ival); long c; if (!s) Error("bad GF2X input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c == '0') { s.get(); c = s.peek(); if (c == 'x' || c == 'X') { s.get(); return HexInput(s, a); } else { Error("bad GF2X input"); } } if (c != '[') { Error("bad GF2X input"); } GF2X ibuf; long n; n = 0; clear(ibuf); s.get(); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } while (c != ']' && c != EOF) { if (!(s >> ival)) Error("bad GF2X input"); SetCoeff(ibuf, n, to_GF2(ival)); n++; c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } } if (c == EOF) Error("bad GF2X input"); s.get(); a = ibuf; return s; } static ostream & HexOutput(ostream& s, const GF2X& a) { s << "0x"; long da = deg(a); if (da < 0) { s << '0'; return s; } long i, n, val; val = 0; n = 0; for (i = 0; i <= da; i++) { val = val | (rep(coeff(a, i)) << n); n++; if (n == 4) { s << IntValToChar(val); val = 0; n = 0; } } if (val) s << IntValToChar(val); return s; } ostream& operator<<(ostream& s, const GF2X& a) { if (GF2X::HexOutput) return HexOutput(s, a); long i, da; GF2 c; da = deg(a); s << '['; for (i = 0; i <= da; i++) { c = coeff(a, i); if (c == 0) s << "0"; else s << "1"; if (i < da) s << " "; } s << ']'; return s; } void random(GF2X& x, long n) { if (n < 0) Error("GF2X random: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("GF2X random: excessive length"); long wl = (n+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; x.xrep.SetLength(wl); long i; for (i = 0; i < wl-1; i++) { x.xrep[i] = RandomWord(); } if (n > 0) { long pos = n % NTL_BITS_PER_LONG; if (pos == 0) pos = NTL_BITS_PER_LONG; x.xrep[wl-1] = RandomBits_ulong(pos); } x.normalize(); } void add(GF2X& x, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); long i; if (sa == sb) { x.xrep.SetLength(sa); if (sa == 0) return; _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); for (i = 0; i < sa; i++) xp[i] = ap[i] ^ bp[i]; i = sa-1; while (i >= 0 && !xp[i]) i--; x.xrep.QuickSetLength(i+1); } else if (sa < sb) { x.xrep.SetLength(sb); _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); for (i = 0; i < sa; i++) xp[i] = ap[i] ^ bp[i]; for (; i < sb; i++) xp[i] = bp[i]; } else { // sa > sb x.xrep.SetLength(sa); _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); for (i = 0; i < sb; i++) xp[i] = ap[i] ^ bp[i]; for (; i < sa; i++) xp[i] = ap[i]; } } /* * The bodies of mul1, Mul1, AddMul1, and mul_half * are generated by the MakeDesc program, and the * macros NTL_BB_MUL_CODE... are defined in mach_desc.h. * Thanks to Paul Zimmermann for providing improvements * to this approach. */ #if (defined(NTL_GF2X_ALTCODE1)) #define NTL_EFF_BB_MUL_CODE0 NTL_ALT1_BB_MUL_CODE0 #define NTL_EFF_BB_MUL_CODE1 NTL_ALT1_BB_MUL_CODE1 #define NTL_EFF_BB_MUL_CODE2 NTL_ALT1_BB_MUL_CODE2 #define NTL_EFF_SHORT_BB_MUL_CODE1 NTL_ALT1_SHORT_BB_MUL_CODE1 #define NTL_EFF_HALF_BB_MUL_CODE0 NTL_ALT1_HALF_BB_MUL_CODE0 #elif (defined(NTL_GF2X_ALTCODE)) #define NTL_EFF_BB_MUL_CODE0 NTL_ALT_BB_MUL_CODE0 #define NTL_EFF_BB_MUL_CODE1 NTL_ALT_BB_MUL_CODE1 #define NTL_EFF_BB_MUL_CODE2 NTL_ALT_BB_MUL_CODE2 #define NTL_EFF_SHORT_BB_MUL_CODE1 NTL_ALT_SHORT_BB_MUL_CODE1 #define NTL_EFF_HALF_BB_MUL_CODE0 NTL_ALT_HALF_BB_MUL_CODE0 #else #define NTL_EFF_BB_MUL_CODE0 NTL_BB_MUL_CODE0 #define NTL_EFF_BB_MUL_CODE1 NTL_BB_MUL_CODE1 #define NTL_EFF_BB_MUL_CODE2 NTL_BB_MUL_CODE2 #define NTL_EFF_SHORT_BB_MUL_CODE1 NTL_SHORT_BB_MUL_CODE1 #define NTL_EFF_HALF_BB_MUL_CODE0 NTL_HALF_BB_MUL_CODE0 #endif static void mul1(_ntl_ulong *c, _ntl_ulong a, _ntl_ulong b) { NTL_EFF_BB_MUL_CODE0 } #ifdef NTL_GF2X_NOINLINE #define mul1_IL mul1 #else static inline void mul1_inline(_ntl_ulong *c, _ntl_ulong a, _ntl_ulong b) { NTL_EFF_BB_MUL_CODE0 } #define mul1_IL mul1_inline #endif static void Mul1(_ntl_ulong *cp, const _ntl_ulong *bp, long sb, _ntl_ulong a) { NTL_EFF_BB_MUL_CODE1 } static void AddMul1(_ntl_ulong *cp, const _ntl_ulong* bp, long sb, _ntl_ulong a) { NTL_EFF_BB_MUL_CODE2 } static void Mul1_short(_ntl_ulong *cp, const _ntl_ulong *bp, long sb, _ntl_ulong a) { NTL_EFF_SHORT_BB_MUL_CODE1 } static void mul_half(_ntl_ulong *c, _ntl_ulong a, _ntl_ulong b) { NTL_EFF_HALF_BB_MUL_CODE0 } // mul2...mul8 hard-code 2x2...8x8 word multiplies. // I adapted these routines from LiDIA (except mul3, see below). // Inlining these seems to hurt, not help. static void mul2(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0, hs1; _ntl_ulong hl2[2]; hs0 = a[0] ^ a[1]; hs1 = b[0] ^ b[1]; mul1_IL(c, a[0], b[0]); mul1_IL(c+2, a[1], b[1]); mul1_IL(hl2, hs0, hs1); hl2[0] = hl2[0] ^ c[0] ^ c[2]; hl2[1] = hl2[1] ^ c[1] ^ c[3]; c[1] ^= hl2[0]; c[2] ^= hl2[1]; } /* * This version of mul3 I got from Weimerskirch, Stebila, * and Shantz, "Generic GF(2^m) arithmetic in software * an its application to ECC" (ACISP 2003). */ static void mul3 (_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong d0[2], d1[2], d2[2], d01[2], d02[2], d12[2]; mul1_IL(d0, a[0], b[0]); mul1_IL(d1, a[1], b[1]); mul1_IL(d2, a[2], b[2]); mul1_IL(d01, a[0]^a[1], b[0]^b[1]); mul1_IL(d02, a[0]^a[2], b[0]^b[2]); mul1_IL(d12, a[1]^a[2], b[1]^b[2]); c[0] = d0[0]; c[1] = d0[1] ^ d01[0] ^ d1[0] ^ d0[0]; c[2] = d01[1] ^ d1[1] ^ d0[1] ^ d02[0] ^ d2[0] ^ d0[0] ^ d1[0]; c[3] = d02[1] ^ d2[1] ^ d0[1] ^ d1[1] ^ d12[0] ^ d1[0] ^ d2[0]; c[4] = d12[1] ^ d1[1] ^ d2[1] ^ d2[0]; c[5] = d2[1]; } static void mul4(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[2], hs1[2]; _ntl_ulong hl2[4]; hs0[0] = a[0] ^ a[2]; hs0[1] = a[1] ^ a[3]; hs1[0] = b[0] ^ b[2]; hs1[1] = b[1] ^ b[3]; mul2(c, a, b); mul2(c+4, a+2, b+2); mul2(hl2, hs0, hs1); hl2[0] = hl2[0] ^ c[0] ^ c[4]; hl2[1] = hl2[1] ^ c[1] ^ c[5]; hl2[2] = hl2[2] ^ c[2] ^ c[6]; hl2[3] = hl2[3] ^ c[3] ^ c[7]; c[2] ^= hl2[0]; c[3] ^= hl2[1]; c[4] ^= hl2[2]; c[5] ^= hl2[3]; } static void mul5 (_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[3], hs1[3]; _ntl_ulong hl2[6]; hs0[0] = a[0] ^ a[3]; hs0[1] = a[1] ^ a[4]; hs0[2] = a[2]; hs1[0] = b[0] ^ b[3]; hs1[1] = b[1] ^ b[4]; hs1[2] = b[2]; mul3(c, a, b); mul3(hl2, hs0, hs1); mul2(c+6, a+3, b+3); hl2[0] = hl2[0] ^ c[0] ^ c[6]; hl2[1] = hl2[1] ^ c[1] ^ c[7]; hl2[2] = hl2[2] ^ c[2] ^ c[8]; hl2[3] = hl2[3] ^ c[3] ^ c[9]; hl2[4] = hl2[4] ^ c[4]; hl2[5] = hl2[5] ^ c[5]; c[3] ^= hl2[0]; c[4] ^= hl2[1]; c[5] ^= hl2[2]; c[6] ^= hl2[3]; c[7] ^= hl2[4]; c[8] ^= hl2[5]; } static void mul6(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[3], hs1[3]; _ntl_ulong hl2[6]; hs0[0] = a[0] ^ a[3]; hs0[1] = a[1] ^ a[4]; hs0[2] = a[2] ^ a[5]; hs1[0] = b[0] ^ b[3]; hs1[1] = b[1] ^ b[4]; hs1[2] = b[2] ^ b[5]; mul3(c, a, b); mul3(c+6, a+3, b+3); mul3(hl2, hs0, hs1); hl2[0] = hl2[0] ^ c[0] ^ c[6]; hl2[1] = hl2[1] ^ c[1] ^ c[7]; hl2[2] = hl2[2] ^ c[2] ^ c[8]; hl2[3] = hl2[3] ^ c[3] ^ c[9]; hl2[4] = hl2[4] ^ c[4] ^ c[10]; hl2[5] = hl2[5] ^ c[5] ^ c[11]; c[3] ^= hl2[0]; c[4] ^= hl2[1]; c[5] ^= hl2[2]; c[6] ^= hl2[3]; c[7] ^= hl2[4]; c[8] ^= hl2[5]; } static void mul7(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[4], hs1[4]; _ntl_ulong hl2[8]; hs0[0] = a[0] ^ a[4]; hs0[1] = a[1] ^ a[5]; hs0[2] = a[2] ^ a[6]; hs0[3] = a[3]; hs1[0] = b[0] ^ b[4]; hs1[1] = b[1] ^ b[5]; hs1[2] = b[2] ^ b[6]; hs1[3] = b[3]; mul4(c, a, b); mul4(hl2, hs0, hs1); mul3(c+8, a+4, b+4); hl2[0] = hl2[0] ^ c[0] ^ c[8]; hl2[1] = hl2[1] ^ c[1] ^ c[9]; hl2[2] = hl2[2] ^ c[2] ^ c[10]; hl2[3] = hl2[3] ^ c[3] ^ c[11]; hl2[4] = hl2[4] ^ c[4] ^ c[12]; hl2[5] = hl2[5] ^ c[5] ^ c[13]; hl2[6] = hl2[6] ^ c[6]; hl2[7] = hl2[7] ^ c[7]; c[4] ^= hl2[0]; c[5] ^= hl2[1]; c[6] ^= hl2[2]; c[7] ^= hl2[3]; c[8] ^= hl2[4]; c[9] ^= hl2[5]; c[10] ^= hl2[6]; c[11] ^= hl2[7]; } static void mul8(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[4], hs1[4]; _ntl_ulong hl2[8]; hs0[0] = a[0] ^ a[4]; hs0[1] = a[1] ^ a[5]; hs0[2] = a[2] ^ a[6]; hs0[3] = a[3] ^ a[7]; hs1[0] = b[0] ^ b[4]; hs1[1] = b[1] ^ b[5]; hs1[2] = b[2] ^ b[6]; hs1[3] = b[3] ^ b[7]; mul4(c, a, b); mul4(c+8, a+4, b+4); mul4(hl2, hs0, hs1); hl2[0] = hl2[0] ^ c[0] ^ c[8]; hl2[1] = hl2[1] ^ c[1] ^ c[9]; hl2[2] = hl2[2] ^ c[2] ^ c[10]; hl2[3] = hl2[3] ^ c[3] ^ c[11]; hl2[4] = hl2[4] ^ c[4] ^ c[12]; hl2[5] = hl2[5] ^ c[5] ^ c[13]; hl2[6] = hl2[6] ^ c[6] ^ c[14]; hl2[7] = hl2[7] ^ c[7] ^ c[15]; c[4] ^= hl2[0]; c[5] ^= hl2[1]; c[6] ^= hl2[2]; c[7] ^= hl2[3]; c[8] ^= hl2[4]; c[9] ^= hl2[5]; c[10] ^= hl2[6]; c[11] ^= hl2[7]; } static void KarMul(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b, long len, _ntl_ulong *stk) { if (len <= 8) { switch (len) { case 1: mul1(c, a[0], b[0]); break; case 2: mul2(c, a, b); break; case 3: mul3(c, a, b); break; case 4: mul4(c, a, b); break; case 5: mul5(c, a, b); break; case 6: mul6(c, a, b); break; case 7: mul7(c, a, b); break; case 8: mul8(c, a, b); break; } return; } long ll, lh, i, ll2, lh2; const _ntl_ulong *a0, *a1, *b0, *b1; _ntl_ulong *a01, *b01, *h; lh = len >> 1; ll = (len+1) >> 1; ll2 = ll << 1; lh2 = lh << 1; a01 = stk; stk += ll+1; b01 = stk; stk += ll+1; h = stk; stk += ll2+1; a0 = a; a1 = a+ll; b0 = b; b1 = b+ll; KarMul(c, a0, b0, ll, stk); KarMul(c+ll2, a1, b1, lh, stk); for (i = 0; i < lh; i++) { a01[i] = a[i] ^ a[i+ll]; b01[i] = b[i] ^ b[i+ll]; } if (lh < ll) { a01[lh] = a[lh]; b01[lh] = b[lh]; } KarMul(h, a01, b01, ll, stk); for (i = 0; i < ll2; i++) h[i] ^= c[i]; for (i = 0; i < lh2; i++) h[i] ^= c[i+ll2]; for (i = 0; i < ll2; i++) c[i+ll] ^= h[i]; } #ifdef NTL_GF2X_LIB void mul(GF2X& c, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sa <= 0 || sb <= 0) { clear(c); return; } _ntl_ulong a0 = a.xrep[0]; _ntl_ulong b0 = b.xrep[0]; if (sb == 1 && b0 == 1) { c = a; return; } if (sa == 1 && a0 == 1) { c = b; return; } if (&a == &b) { sqr(c, a); return; } if (sa == 1 && sb == 1) { // special case... _ntl_ulong v[2]; if (!(a0 >> NTL_BITS_PER_LONG/2)) mul_half(v, b0, a0); else if (!(b0 >> NTL_BITS_PER_LONG/2)) mul_half(v, a0, b0); else mul1(v, a0, b0); if (v[1]) { c.xrep.SetLength(2); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; } else { c.xrep.SetLength(1); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; } return; } if (sa == 2 && sb == 2) { // special case... _ntl_ulong v[4]; mul2(v, &a.xrep[0], &b.xrep[0]); if (v[3]) { c.xrep.SetLength(4); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; } else { c.xrep.SetLength(3); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; } return; } // another special case: one of the two inputs // has length 1 (or less). if (sa == 1) { c.xrep.SetLength(sb + 1); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); if (a0 >> (NTL_BITS_PER_LONG-NTL_BB_MUL1_BITS+1)) Mul1(cp, bp, sb, a0); else Mul1_short(cp, bp, sb, a0); c.normalize(); return; } if (sb == 1) { c.xrep.SetLength(sa + 1); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); if (b0 >> (NTL_BITS_PER_LONG-NTL_BB_MUL1_BITS+1)) Mul1(cp, ap, sa, b0); else Mul1_short(cp, ap, sa, b0); c.normalize(); return; } // finally: the general case NTL_THREAD_LOCAL static WordVector mem; const _ntl_ulong *ap = a.xrep.elts(), *bp = b.xrep.elts(); _ntl_ulong *cp; long sc = sa + sb; long in_mem = 0; if (&a == &c || &b == &c) { mem.SetLength(sc); cp = mem.elts(); in_mem = 1; } else { c.xrep.SetLength(sc); cp = c.xrep.elts(); } gf2x_mul(cp, ap, sa, bp, sb); if (in_mem) { c.xrep = mem; } c.normalize(); mem.release(); } #else void OldMul(GF2X& c, const GF2X& a, const GF2X& b) { mul(c, a, b); } #endif #ifdef NTL_GF2X_LIB void OldMul(GF2X& c, const GF2X& a, const GF2X& b) #else void mul(GF2X& c, const GF2X& a, const GF2X& b) #endif { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sa <= 0 || sb <= 0) { clear(c); return; } _ntl_ulong a0 = a.xrep[0]; _ntl_ulong b0 = b.xrep[0]; if (sb == 1 && b0 == 1) { c = a; return; } if (sa == 1 && a0 == 1) { c = b; return; } if (&a == &b) { sqr(c, a); return; } if (sa == sb && sa <= 8) { // we treat these cases specially for efficiency reasons switch (sa) { case 1: { _ntl_ulong v[2]; if (!(a0 >> NTL_BITS_PER_LONG/2)) mul_half(v, b0, a0); else if (!(b0 >> NTL_BITS_PER_LONG/2)) mul_half(v, a0, b0); else mul1(v, a0, b0); if (v[1]) { c.xrep.SetLength(2); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; } else { c.xrep.SetLength(1); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; } } return; case 2: { _ntl_ulong v[4]; mul2(v, &a.xrep[0], &b.xrep[0]); if (v[3]) { c.xrep.SetLength(4); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; } else { c.xrep.SetLength(3); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; } } return; case 3: { _ntl_ulong v[6]; mul3(v, &a.xrep[0], &b.xrep[0]); if (v[5]) { c.xrep.SetLength(6); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; } else { c.xrep.SetLength(5); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; } } return; case 4: { _ntl_ulong v[8]; mul4(v, &a.xrep[0], &b.xrep[0]); if (v[7]) { c.xrep.SetLength(8); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; } else { c.xrep.SetLength(7); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; } } return; case 5: { _ntl_ulong v[10]; mul5(v, &a.xrep[0], &b.xrep[0]); if (v[9]) { c.xrep.SetLength(10); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; } else { c.xrep.SetLength(9); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; } } return; case 6: { _ntl_ulong v[12]; mul6(v, &a.xrep[0], &b.xrep[0]); if (v[11]) { c.xrep.SetLength(12); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; } else { c.xrep.SetLength(11); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; } } return; case 7: { _ntl_ulong v[14]; mul7(v, &a.xrep[0], &b.xrep[0]); if (v[13]) { c.xrep.SetLength(14); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; cp[12] = v[12]; cp[13] = v[13]; } else { c.xrep.SetLength(13); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; cp[12] = v[12]; } } return; case 8: { _ntl_ulong v[16]; mul8(v, &a.xrep[0], &b.xrep[0]); if (v[15]) { c.xrep.SetLength(16); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; cp[12] = v[12]; cp[13] = v[13]; cp[14] = v[14]; cp[15] = v[15]; } else { c.xrep.SetLength(15); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; cp[12] = v[12]; cp[13] = v[13]; cp[14] = v[14]; } } return; } } // another special case: one of the two inputs // has length 1 (or less). if (sa == 1) { c.xrep.SetLength(sb + 1); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); if (a0 >> (NTL_BITS_PER_LONG-NTL_BB_MUL1_BITS+1)) Mul1(cp, bp, sb, a0); else Mul1_short(cp, bp, sb, a0); c.normalize(); return; } if (sb == 1) { c.xrep.SetLength(sa + 1); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); if (b0 >> (NTL_BITS_PER_LONG-NTL_BB_MUL1_BITS+1)) Mul1(cp, ap, sa, b0); else Mul1_short(cp, ap, sa, b0); c.normalize(); return; } // finally: the general case NTL_THREAD_LOCAL static WordVector mem; NTL_THREAD_LOCAL static WordVector stk; NTL_THREAD_LOCAL static WordVector vec; const _ntl_ulong *ap, *bp; _ntl_ulong *cp; long sc = sa + sb; long in_mem = 0; if (&a == &c || &b == &c) { mem.SetLength(sc); cp = mem.elts(); in_mem = 1; } else { c.xrep.SetLength(sc); cp = c.xrep.elts(); } long n, hn, sp; n = min(sa, sb); sp = 0; while (n > 8) { hn = (n+1) >> 1; sp += (hn << 2) + 3; n = hn; } stk.SetLength(sp); _ntl_ulong *stk_p = stk.elts(); if (sa > sb) { { long t; t = sa; sa = sb; sb = t; } ap = b.xrep.elts(); bp = a.xrep.elts(); } else { ap = a.xrep.elts(); bp = b.xrep.elts(); } vec.SetLength(2*sa); _ntl_ulong *v = vec.elts(); long i, j; for (i = 0; i < sc; i++) cp[i] = 0; do { if (sa == 0) break; if (sa == 1) { AddMul1(cp, bp, sb, ap[0]); break; } // general case for (i = 0; i+sa <= sb; i += sa) { KarMul(v, ap, bp + i, sa, stk_p); for (j = 0; j < 2*sa; j++) cp[i+j] ^= v[j]; } { const _ntl_ulong *t; t = ap; ap = bp + i; bp = t; } { long t; t = sa; sa = sb - i; sb = t; } cp = cp + i; } while (1); if (in_mem) c.xrep = mem; c.normalize(); mem.release(); stk.release(); vec.release(); } void mul(GF2X& c, const GF2X& a, long b) { if (b & 1) c = a; else clear(c); } void mul(GF2X& c, const GF2X& a, GF2 b) { if (b == 1) c = a; else clear(c); } void trunc(GF2X& x, const GF2X& a, long m) { if (m < 0) Error("trunc: bad args"); long n = a.xrep.length(); if (n == 0 || m == 0) { clear(x); return; } if (&x == &a) { if (n*NTL_BITS_PER_LONG > m) { long wm = (m-1)/NTL_BITS_PER_LONG; long bm = m - NTL_BITS_PER_LONG*wm; _ntl_ulong msk; if (bm == NTL_BITS_PER_LONG) msk = ~(0UL); else msk = ((1UL << bm) - 1UL); x.xrep[wm] &= msk; x.xrep.QuickSetLength(wm+1); x.normalize(); } } else if (n*NTL_BITS_PER_LONG <= m) x = a; else { long wm = (m-1)/NTL_BITS_PER_LONG; long bm = m - NTL_BITS_PER_LONG*wm; x.xrep.SetLength(wm+1); _ntl_ulong *xp = &x.xrep[0]; const _ntl_ulong *ap = &a.xrep[0]; long i; for (i = 0; i < wm; i++) xp[i] = ap[i]; _ntl_ulong msk; if (bm == NTL_BITS_PER_LONG) msk = ~(0UL); else msk = ((1UL << bm) - 1UL); xp[wm] = ap[wm] & msk; x.normalize(); } } void MulByX(GF2X& x, const GF2X& a) { long n = a.xrep.length(); if (n == 0) { clear(x); return; } if (a.xrep[n-1] & (1UL << (NTL_BITS_PER_LONG-1))) { x.xrep.SetLength(n+1); x.xrep[n] = 1; } else if (&x != &a) x.xrep.SetLength(n); _ntl_ulong *xp = &x.xrep[0]; const _ntl_ulong *ap = &a.xrep[0]; long i; for (i = n-1; i > 0; i--) xp[i] = (ap[i] << 1) | (ap[i-1] >> (NTL_BITS_PER_LONG-1)); xp[0] = ap[0] << 1; // no need to normalize } static const _ntl_ulong sqrtab[256] = { 0UL, 1UL, 4UL, 5UL, 16UL, 17UL, 20UL, 21UL, 64UL, 65UL, 68UL, 69UL, 80UL, 81UL, 84UL, 85UL, 256UL, 257UL, 260UL, 261UL, 272UL, 273UL, 276UL, 277UL, 320UL, 321UL, 324UL, 325UL, 336UL, 337UL, 340UL, 341UL, 1024UL, 1025UL, 1028UL, 1029UL, 1040UL, 1041UL, 1044UL, 1045UL, 1088UL, 1089UL, 1092UL, 1093UL, 1104UL, 1105UL, 1108UL, 1109UL, 1280UL, 1281UL, 1284UL, 1285UL, 1296UL, 1297UL, 1300UL, 1301UL, 1344UL, 1345UL, 1348UL, 1349UL, 1360UL, 1361UL, 1364UL, 1365UL, 4096UL, 4097UL, 4100UL, 4101UL, 4112UL, 4113UL, 4116UL, 4117UL, 4160UL, 4161UL, 4164UL, 4165UL, 4176UL, 4177UL, 4180UL, 4181UL, 4352UL, 4353UL, 4356UL, 4357UL, 4368UL, 4369UL, 4372UL, 4373UL, 4416UL, 4417UL, 4420UL, 4421UL, 4432UL, 4433UL, 4436UL, 4437UL, 5120UL, 5121UL, 5124UL, 5125UL, 5136UL, 5137UL, 5140UL, 5141UL, 5184UL, 5185UL, 5188UL, 5189UL, 5200UL, 5201UL, 5204UL, 5205UL, 5376UL, 5377UL, 5380UL, 5381UL, 5392UL, 5393UL, 5396UL, 5397UL, 5440UL, 5441UL, 5444UL, 5445UL, 5456UL, 5457UL, 5460UL, 5461UL, 16384UL, 16385UL, 16388UL, 16389UL, 16400UL, 16401UL, 16404UL, 16405UL, 16448UL, 16449UL, 16452UL, 16453UL, 16464UL, 16465UL, 16468UL, 16469UL, 16640UL, 16641UL, 16644UL, 16645UL, 16656UL, 16657UL, 16660UL, 16661UL, 16704UL, 16705UL, 16708UL, 16709UL, 16720UL, 16721UL, 16724UL, 16725UL, 17408UL, 17409UL, 17412UL, 17413UL, 17424UL, 17425UL, 17428UL, 17429UL, 17472UL, 17473UL, 17476UL, 17477UL, 17488UL, 17489UL, 17492UL, 17493UL, 17664UL, 17665UL, 17668UL, 17669UL, 17680UL, 17681UL, 17684UL, 17685UL, 17728UL, 17729UL, 17732UL, 17733UL, 17744UL, 17745UL, 17748UL, 17749UL, 20480UL, 20481UL, 20484UL, 20485UL, 20496UL, 20497UL, 20500UL, 20501UL, 20544UL, 20545UL, 20548UL, 20549UL, 20560UL, 20561UL, 20564UL, 20565UL, 20736UL, 20737UL, 20740UL, 20741UL, 20752UL, 20753UL, 20756UL, 20757UL, 20800UL, 20801UL, 20804UL, 20805UL, 20816UL, 20817UL, 20820UL, 20821UL, 21504UL, 21505UL, 21508UL, 21509UL, 21520UL, 21521UL, 21524UL, 21525UL, 21568UL, 21569UL, 21572UL, 21573UL, 21584UL, 21585UL, 21588UL, 21589UL, 21760UL, 21761UL, 21764UL, 21765UL, 21776UL, 21777UL, 21780UL, 21781UL, 21824UL, 21825UL, 21828UL, 21829UL, 21840UL, 21841UL, 21844UL, 21845UL }; static inline void sqr1(_ntl_ulong *c, _ntl_ulong a) { _ntl_ulong hi, lo; NTL_BB_SQR_CODE c[0] = lo; c[1] = hi; } void sqr(GF2X& c, const GF2X& a) { long sa = a.xrep.length(); if (sa <= 0) { clear(c); return; } c.xrep.SetLength(sa << 1); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long i; for (i = sa-1; i >= 0; i--) sqr1(cp + (i << 1), ap[i]); c.normalize(); return; } void LeftShift(GF2X& c, const GF2X& a, long n) { if (IsZero(a)) { clear(c); return; } if (n == 1) { MulByX(c, a); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(c); else RightShift(c, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in LeftShift"); if (n == 0) { c = a; return; } long sa = a.xrep.length(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long sc = sa + wn; if (bn) sc++; c.xrep.SetLength(sc); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long i; if (bn == 0) { for (i = sa+wn-1; i >= wn; i--) cp[i] = ap[i-wn]; for (i = wn-1; i >= 0; i--) cp[i] = 0; } else { cp[sa+wn] = ap[sa-1] >> (NTL_BITS_PER_LONG-bn); for (i = sa+wn-1; i >= wn+1; i--) cp[i] = (ap[i-wn] << bn) | (ap[i-wn-1] >> (NTL_BITS_PER_LONG-bn)); cp[wn] = ap[0] << bn; for (i = wn-1; i >= 0; i--) cp[i] = 0; } c.normalize(); } void ShiftAdd(GF2X& c, const GF2X& a, long n) // c = c + a*X^n { if (n < 0) Error("ShiftAdd: negative argument"); if (n == 0) { add(c, c, a); return; } if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in ShiftAdd"); long sa = a.xrep.length(); if (sa <= 0) { return; } long sc = c.xrep.length(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long ss = sa + wn; if (bn) ss++; if (ss > sc) c.xrep.SetLength(ss); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long i; for (i = sc; i < ss; i++) cp[i] = 0; if (bn == 0) { for (i = sa+wn-1; i >= wn; i--) cp[i] ^= ap[i-wn]; } else { cp[sa+wn] ^= ap[sa-1] >> (NTL_BITS_PER_LONG-bn); for (i = sa+wn-1; i >= wn+1; i--) cp[i] ^= (ap[i-wn] << bn) | (ap[i-wn-1] >> (NTL_BITS_PER_LONG-bn)); cp[wn] ^= ap[0] << bn; } c.normalize(); } void RightShift(GF2X& c, const GF2X& a, long n) { if (IsZero(a)) { clear(c); return; } if (n < 0) { if (n < -NTL_MAX_LONG) Error("overflow in RightShift"); LeftShift(c, a, -n); return; } if (n == 0) { c = a; return; } long sa = a.xrep.length(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (wn >= sa) { clear(c); return; } c.xrep.SetLength(sa-wn); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long i; if (bn == 0) { for (i = 0; i < sa-wn; i++) cp[i] = ap[i+wn]; } else { for (i = 0; i < sa-wn-1; i++) cp[i] = (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn)); cp[sa-wn-1] = ap[sa-1] >> bn; } c.normalize(); } static const _ntl_ulong revtab[256] = { 0UL, 128UL, 64UL, 192UL, 32UL, 160UL, 96UL, 224UL, 16UL, 144UL, 80UL, 208UL, 48UL, 176UL, 112UL, 240UL, 8UL, 136UL, 72UL, 200UL, 40UL, 168UL, 104UL, 232UL, 24UL, 152UL, 88UL, 216UL, 56UL, 184UL, 120UL, 248UL, 4UL, 132UL, 68UL, 196UL, 36UL, 164UL, 100UL, 228UL, 20UL, 148UL, 84UL, 212UL, 52UL, 180UL, 116UL, 244UL, 12UL, 140UL, 76UL, 204UL, 44UL, 172UL, 108UL, 236UL, 28UL, 156UL, 92UL, 220UL, 60UL, 188UL, 124UL, 252UL, 2UL, 130UL, 66UL, 194UL, 34UL, 162UL, 98UL, 226UL, 18UL, 146UL, 82UL, 210UL, 50UL, 178UL, 114UL, 242UL, 10UL, 138UL, 74UL, 202UL, 42UL, 170UL, 106UL, 234UL, 26UL, 154UL, 90UL, 218UL, 58UL, 186UL, 122UL, 250UL, 6UL, 134UL, 70UL, 198UL, 38UL, 166UL, 102UL, 230UL, 22UL, 150UL, 86UL, 214UL, 54UL, 182UL, 118UL, 246UL, 14UL, 142UL, 78UL, 206UL, 46UL, 174UL, 110UL, 238UL, 30UL, 158UL, 94UL, 222UL, 62UL, 190UL, 126UL, 254UL, 1UL, 129UL, 65UL, 193UL, 33UL, 161UL, 97UL, 225UL, 17UL, 145UL, 81UL, 209UL, 49UL, 177UL, 113UL, 241UL, 9UL, 137UL, 73UL, 201UL, 41UL, 169UL, 105UL, 233UL, 25UL, 153UL, 89UL, 217UL, 57UL, 185UL, 121UL, 249UL, 5UL, 133UL, 69UL, 197UL, 37UL, 165UL, 101UL, 229UL, 21UL, 149UL, 85UL, 213UL, 53UL, 181UL, 117UL, 245UL, 13UL, 141UL, 77UL, 205UL, 45UL, 173UL, 109UL, 237UL, 29UL, 157UL, 93UL, 221UL, 61UL, 189UL, 125UL, 253UL, 3UL, 131UL, 67UL, 195UL, 35UL, 163UL, 99UL, 227UL, 19UL, 147UL, 83UL, 211UL, 51UL, 179UL, 115UL, 243UL, 11UL, 139UL, 75UL, 203UL, 43UL, 171UL, 107UL, 235UL, 27UL, 155UL, 91UL, 219UL, 59UL, 187UL, 123UL, 251UL, 7UL, 135UL, 71UL, 199UL, 39UL, 167UL, 103UL, 231UL, 23UL, 151UL, 87UL, 215UL, 55UL, 183UL, 119UL, 247UL, 15UL, 143UL, 79UL, 207UL, 47UL, 175UL, 111UL, 239UL, 31UL, 159UL, 95UL, 223UL, 63UL, 191UL, 127UL, 255UL }; static inline _ntl_ulong rev1(_ntl_ulong a) { return NTL_BB_REV_CODE; } void CopyReverse(GF2X& c, const GF2X& a, long hi) // c[0..hi] = reverse(a[0..hi]), with zero fill as necessary // input may alias output { if (hi < 0) { clear(c); return; } if (NTL_OVERFLOW(hi, 1, 0)) Error("overflow in CopyReverse"); long n = hi+1; long sa = a.xrep.length(); if (n <= 0 || sa <= 0) { clear(c); return; } long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (bn != 0) { wn++; bn = NTL_BITS_PER_LONG - bn; } c.xrep.SetLength(wn); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long mm = min(sa, wn); long i; for (i = 0; i < mm; i++) cp[i] = ap[i]; for (i = mm; i < wn; i++) cp[i] = 0; if (bn != 0) { for (i = wn-1; i >= 1; i--) cp[i] = (cp[i] << bn) | (cp[i-1] >> (NTL_BITS_PER_LONG-bn)); cp[0] = cp[0] << bn; } for (i = 0; i < wn/2; i++) { _ntl_ulong t; t = cp[i]; cp[i] = cp[wn-1-i]; cp[wn-1-i] = t; } for (i = 0; i < wn; i++) cp[i] = rev1(cp[i]); c.normalize(); } void div(GF2X& q, const GF2X& a, GF2 b) { if (b == 0) Error("div: division by zero"); q = a; } void div(GF2X& q, const GF2X& a, long b) { if ((b & 1) == 0) Error("div: division by zero"); q = a; } void GF2XFromBytes(GF2X& x, const unsigned char *p, long n) { if (n <= 0) { x = 0; return; } const long BytesPerLong = NTL_BITS_PER_LONG/8; long lw, r, i, j; lw = n/BytesPerLong; r = n - lw*BytesPerLong; if (r != 0) lw++; else r = BytesPerLong; x.xrep.SetLength(lw); unsigned long *xp = x.xrep.elts(); for (i = 0; i < lw-1; i++) { unsigned long t = 0; for (j = 0; j < BytesPerLong; j++) { t >>= 8; t += (((unsigned long)(*p)) & 255UL) << ((BytesPerLong-1)*8); p++; } xp[i] = t; } unsigned long t = 0; for (j = 0; j < r; j++) { t >>= 8; t += (((unsigned long)(*p)) & 255UL) << ((BytesPerLong-1)*8); p++; } t >>= (BytesPerLong-r)*8; xp[lw-1] = t; x.normalize(); } void BytesFromGF2X(unsigned char *p, const GF2X& a, long n) { if (n < 0) n = 0; const long BytesPerLong = NTL_BITS_PER_LONG/8; long lbits = deg(a) + 1; long lbytes = (lbits+7)/8; long min_bytes = min(lbytes, n); long min_words = min_bytes/BytesPerLong; long r = min_bytes - min_words*BytesPerLong; if (r != 0) min_words++; else r = BytesPerLong; const unsigned long *ap = a.xrep.elts(); long i, j; for (i = 0; i < min_words-1; i++) { unsigned long t = ap[i]; for (j = 0; j < BytesPerLong; j++) { *p = t & 255UL; t >>= 8; p++; } } if (min_words > 0) { unsigned long t = ap[min_words-1]; for (j = 0; j < r; j++) { *p = t & 255UL; t >>= 8; p++; } } for (j = min_bytes; j < n; j++) { *p = 0; p++; } } NTL_END_IMPL ntl-6.2.1/src/GF2X1.c000644 000765 000024 00000212661 12377144456 014365 0ustar00shoupstaff000000 000000 #include #include #ifndef NTL_WIZARD_HACK #include #endif #include #if (defined(NTL_WIZARD_HACK) && defined(NTL_GF2X_LIB)) #undef NTL_GF2X_LIB #endif // some crossover points...choice depends // if we are using the gf2x lib or not #ifdef NTL_GF2X_LIB #define NTL_GF2X_GCD_CROSSOVER (400L*NTL_BITS_PER_LONG) #define NTL_GF2X_HalfGCD_CROSSOVER (6L*NTL_BITS_PER_LONG) #define NTL_GF2X_BERMASS_CROSSOVER (200L*NTL_BITS_PER_LONG) #else #define NTL_GF2X_GCD_CROSSOVER (900L*NTL_BITS_PER_LONG) #define NTL_GF2X_HalfGCD_CROSSOVER (6L*NTL_BITS_PER_LONG) #define NTL_GF2X_BERMASS_CROSSOVER (450L*NTL_BITS_PER_LONG) #endif NTL_START_IMPL NTL_THREAD_LOCAL static vec_GF2X stab; // used by PlainDivRem and PlainRem NTL_THREAD_LOCAL static WordVector GF2X_rembuf; void PlainDivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b) { long da, sa, posa, db, sb, posb, dq, sq, posq; da = deg(a); db = deg(b); if (db < 0) Error("GF2X: division by zero"); if (da < db) { r = a; clear(q); return; } sa = a.xrep.length(); posa = da - NTL_BITS_PER_LONG*(sa-1); sb = b.xrep.length(); posb = db - NTL_BITS_PER_LONG*(sb-1); dq = da - db; sq = dq/NTL_BITS_PER_LONG + 1; posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } stab.SetLength(NTL_BITS_PER_LONG); long i; stab[posb] = b; for (i = 1; i <= min(dq, NTL_BITS_PER_LONG-1); i++) MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG], stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]); _ntl_ulong *stab_ptr[NTL_BITS_PER_LONG]; long stab_cnt[NTL_BITS_PER_LONG]; for (i = 0; i <= min(dq, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1; } q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *qtop = &qp[sq-1]; _ntl_ulong *stab_top; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = stab_ptr[posa]; for (i = stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < db) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } if (posb == 0) sb--; r.xrep.SetLength(sb); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sb; i++) rp[i] = ap[i]; } r.normalize(); GF2X_rembuf.release(); for (i = 0; i <= min(dq, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; st.release(); } } void PlainDiv(GF2X& q, const GF2X& a, const GF2X& b) { NTL_GF2XRegister(r); PlainDivRem(q, r, a, b); } void PlainRem(GF2X& r, const GF2X& a, const GF2X& b) { long da, sa, posa, db, sb, posb; da = deg(a); db = deg(b); if (db < 0) Error("GF2X: division by zero"); if (da < db) { r = a; return; } sa = a.xrep.length(); posa = da - NTL_BITS_PER_LONG*(sa-1); sb = b.xrep.length(); posb = db - NTL_BITS_PER_LONG*(sb-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } stab.SetLength(NTL_BITS_PER_LONG); long i; stab[posb] = b; for (i = 1; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG], stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]); _ntl_ulong *stab_ptr[NTL_BITS_PER_LONG]; long stab_cnt[NTL_BITS_PER_LONG]; for (i = 0; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1; } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; while (1) { if (atop[0] & (1UL << posa)) { stab_top = stab_ptr[posa]; for (i = stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < db) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } } if (posb == 0) sb--; r.xrep.SetLength(sb); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sb; i++) rp[i] = ap[i]; } r.normalize(); GF2X_rembuf.release(); for (i = 0; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; st.release(); } } #define MASK8 ((1UL << 8)-1UL) static const _ntl_ulong invtab[128] = { 1UL, 255UL, 85UL, 219UL, 73UL, 151UL, 157UL, 51UL, 17UL, 175UL, 69UL, 139UL, 89UL, 199UL, 141UL, 99UL, 33UL, 95UL, 117UL, 123UL, 105UL, 55UL, 189UL, 147UL, 49UL, 15UL, 101UL, 43UL, 121UL, 103UL, 173UL, 195UL, 65UL, 191UL, 21UL, 155UL, 9UL, 215UL, 221UL, 115UL, 81UL, 239UL, 5UL, 203UL, 25UL, 135UL, 205UL, 35UL, 97UL, 31UL, 53UL, 59UL, 41UL, 119UL, 253UL, 211UL, 113UL, 79UL, 37UL, 107UL, 57UL, 39UL, 237UL, 131UL, 129UL, 127UL, 213UL, 91UL, 201UL, 23UL, 29UL, 179UL, 145UL, 47UL, 197UL, 11UL, 217UL, 71UL, 13UL, 227UL, 161UL, 223UL, 245UL, 251UL, 233UL, 183UL, 61UL, 19UL, 177UL, 143UL, 229UL, 171UL, 249UL, 231UL, 45UL, 67UL, 193UL, 63UL, 149UL, 27UL, 137UL, 87UL, 93UL, 243UL, 209UL, 111UL, 133UL, 75UL, 153UL, 7UL, 77UL, 163UL, 225UL, 159UL, 181UL, 187UL, 169UL, 247UL, 125UL, 83UL, 241UL, 207UL, 165UL, 235UL, 185UL, 167UL, 109UL, 3UL }; void NewtonInvTrunc(GF2X& c, const GF2X& a, long e) { if (e == 1) { set(c); return; } NTL_THREAD_LOCAL static vec_long E; E.SetLength(0); append(E, e); while (e > 8) { e = (e+1)/2; append(E, e); } long L = E.length(); NTL_GF2XRegister(g); NTL_GF2XRegister(g0); NTL_GF2XRegister(g1); NTL_GF2XRegister(g2); g.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1); g0.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1); g1.xrep.SetMaxLength(((3*E[0]+1)/2+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG+1); g2.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1); g.xrep.SetLength(1); g.xrep[0] = invtab[(a.xrep[0] & MASK8) >> 1] & ((1UL< 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); add(g, g, g2); } c = g; } void InvTrunc(GF2X& c, const GF2X& a, long e) { if (ConstTerm(a) == 0 || e < 0) Error("inv: bad args"); if (NTL_OVERFLOW(e, 1, 0)) Error("overflow in InvTrunc"); if (e == 0) { clear(c); return; } NewtonInvTrunc(c, a, e); } static long weight1(_ntl_ulong a) { long res = 0; while (a) { if (a & 1) res ++; a >>= 1; } return res; } long weight(const GF2X& a) { long wlen = a.xrep.length(); long res = 0; long i; for (i = 0; i < wlen; i++) res += weight1(a.xrep[i]); return res; } static void SparsityCheck(const GF2X& f, long& k3, long& k2, long& k1) { long w = weight(f); if (w != 3 && w != 5) { k3 = 0; return; } if (ConstTerm(f) != 1) { k3 = 0; return; } GF2X g = f; long n = deg(f); trunc(g, g, n); long t = deg(g); if (n-t < NTL_BITS_PER_LONG || t > (n+1)/2) { k3 = 0; return; } if (w == 3) { k3 = t; k2 = 0; return; } k3 = t; trunc(g, g, t); t = deg(g); k2 = t; trunc(g, g, t); t = deg(g); k1 = t; } const long GF2X_MOD_PLAIN = 0; const long GF2X_MOD_MUL = 1; const long GF2X_MOD_SPECIAL = 2; const long GF2X_MOD_TRI = 3; const long GF2X_MOD_PENT = 4; void build(GF2XModulus& F, const GF2X& f) { long n = deg(f); long i; if (n <= 0) Error("build(GF2XModulus,GF2X): deg(f) <= 0"); F.tracevec.SetLength(0); F.f = f; F.n = n; F.sn = f.xrep.length(); long sb = F.sn; long posb = n - NTL_BITS_PER_LONG*(sb-1); F.posn = posb; if (F.posn > 0) { F.size = F.sn; F.msk = (1UL << F.posn) - 1UL; } else { F.size = F.sn-1; F.msk = ~0UL; } SparsityCheck(f, F.k3, F.k2, F.k1); if (F.k3 != 0) { if (F.k2 == 0) F.method = GF2X_MOD_TRI; else F.method = GF2X_MOD_PENT; return; } GF2X f0; trunc(f0, f, n); long deg_f0 = deg(f0); if (F.sn > 1 && deg_f0 < NTL_BITS_PER_LONG && deg_f0 >= NTL_BITS_PER_LONG/2) { if (F.size >= 6) F.method = GF2X_MOD_MUL; else F.method = GF2X_MOD_SPECIAL; } else if (F.sn > 1 && deg_f0 < NTL_BITS_PER_LONG/2) { if (F.size >= 4) F.method = GF2X_MOD_MUL; else F.method = GF2X_MOD_SPECIAL; } else if (F.size >= 8) F.method = GF2X_MOD_MUL; else F.method = GF2X_MOD_PLAIN; if (F.method == GF2X_MOD_SPECIAL) { if (!F.stab_cnt) F.stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG]; long *stab_cnt = F.stab_cnt; if (!stab_cnt) Error("out of memory"); if (!F.stab1) F.stab1 = NTL_NEW_OP _ntl_ulong[2*NTL_BITS_PER_LONG]; _ntl_ulong *stab1 = F.stab1; if (!stab1) Error("out of memory"); stab1[posb<<1] = f.xrep[0]; stab1[(posb<<1)+1] = 0; stab_cnt[posb] = -sb+1; for (i = 1; i < NTL_BITS_PER_LONG; i++) { long kk0 = ((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG; long kk1 = ((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG; stab1[kk1<<1] = stab1[kk0<<1] << 1; stab1[(kk1<<1)+1] = (stab1[(kk0<<1)+1] << 1) | (stab1[kk0<<1] >> (NTL_BITS_PER_LONG-1)); if (kk1 < posb) stab_cnt[kk1] = -sb; else stab_cnt[kk1] = -sb+1; } } else if (F.method == GF2X_MOD_PLAIN) { vec_GF2X& stab = F.stab; stab.SetLength(NTL_BITS_PER_LONG); if (!F.stab_ptr) F.stab_ptr = NTL_NEW_OP _ntl_ulong_ptr[NTL_BITS_PER_LONG]; _ntl_ulong **stab_ptr = F.stab_ptr; if (!stab_ptr) Error("out of memory"); if (!F.stab_cnt) F.stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG]; long *stab_cnt = F.stab_cnt; if (!stab_cnt) Error("out of memory"); stab[posb] = f; for (i = 1; i < NTL_BITS_PER_LONG; i++) MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG], stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]); for (i = 0; i < NTL_BITS_PER_LONG; i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1; } } else if (F.method == GF2X_MOD_MUL) { GF2X P1, P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); F.f0 = f0; } } GF2XModulus::GF2XModulus() { n = -1; method = GF2X_MOD_PLAIN; stab_ptr = 0; stab_cnt = 0; stab1 = 0; } // The following two routines are total spaghetti...unfortunately, // cleaning them up would require too much re-coding in other // places. GF2XModulus::GF2XModulus(const GF2XModulus& F) : f(F.f), n(F.n), sn(F.sn), posn(F.posn), k3(F.k3), k2(F.k2), k1(F.k1), size(F.size), msk(F.msk), method(F.method), stab(F.stab), h0(F.h0), f0(F.f0), stab_cnt(0), stab_ptr(0), stab1(0), tracevec(F.tracevec) { if (method == GF2X_MOD_SPECIAL) { long i; stab1 = NTL_NEW_OP _ntl_ulong[2*NTL_BITS_PER_LONG]; if (!stab1) Error("GF2XModulus: out of memory"); for (i = 0; i < 2*NTL_BITS_PER_LONG; i++) stab1[i] = F.stab1[i]; stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG]; if (!stab_cnt) Error("GF2XModulus: out of memory"); for (i = 0; i < NTL_BITS_PER_LONG; i++) stab_cnt[i] = F.stab_cnt[i]; } else if (method == GF2X_MOD_PLAIN) { long i; if (F.stab_cnt) { stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG]; if (!stab_cnt) Error("GF2XModulus: out of memory"); for (i = 0; i < NTL_BITS_PER_LONG; i++) stab_cnt[i] = F.stab_cnt[i]; } if (F.stab_ptr) { stab_ptr = NTL_NEW_OP _ntl_ulong_ptr[NTL_BITS_PER_LONG]; if (!stab_ptr) Error("GF2XModulus: out of memory"); for (i = 0; i < NTL_BITS_PER_LONG; i++) { WordVector& st = stab[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = -k+1; } } } } GF2XModulus& GF2XModulus::operator=(const GF2XModulus& F) { if (this == &F) return *this; f=F.f; n=F.n; sn=F.sn; posn=F.posn; k3=F.k3; k2=F.k2; k1=F.k1; size=F.size; msk=F.msk; method=F.method; stab=F.stab; h0=F.h0; f0 = F.f0; tracevec=F.tracevec; if (method == GF2X_MOD_SPECIAL) { long i; if (!stab1) stab1 = NTL_NEW_OP _ntl_ulong[2*NTL_BITS_PER_LONG]; if (!stab1) Error("GF2XModulus: out of memory"); for (i = 0; i < 2*NTL_BITS_PER_LONG; i++) stab1[i] = F.stab1[i]; if (!stab_cnt) stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG]; if (!stab_cnt) Error("GF2XModulus: out of memory"); for (i = 0; i < NTL_BITS_PER_LONG; i++) stab_cnt[i] = F.stab_cnt[i]; } else if (method == GF2X_MOD_PLAIN) { long i; if (F.stab_cnt) { if (!stab_cnt) stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG]; if (!stab_cnt) Error("GF2XModulus: out of memory"); for (i = 0; i < NTL_BITS_PER_LONG; i++) stab_cnt[i] = F.stab_cnt[i]; } if (F.stab_ptr) { if (!stab_ptr) stab_ptr = NTL_NEW_OP _ntl_ulong_ptr[NTL_BITS_PER_LONG]; if (!stab_ptr) Error("GF2XModulus: out of memory"); for (i = 0; i < NTL_BITS_PER_LONG; i++) { WordVector& st = stab[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = -k+1; } } } return *this; } GF2XModulus::~GF2XModulus() { delete [] stab_ptr; delete [] stab_cnt; delete [] stab1; } GF2XModulus::GF2XModulus(const GF2X& ff) { n = -1; method = GF2X_MOD_PLAIN; stab_ptr = 0; stab_cnt = 0; stab1 = 0; build(*this, ff); } void UseMulRem21(GF2X& r, const GF2X& a, const GF2XModulus& F) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); add(r, r, P1); } void UseMulDivRem21(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); add(r, r, P1); q = P2; } void UseMulDiv21(GF2X& q, const GF2X& a, const GF2XModulus& F) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); add(P2, P2, P1); q = P2; } void UseMulRemX1(GF2X& r, const GF2X& aa, const GF2XModulus& F) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); clear(buf); a = aa; long n = F.n; long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); UseMulRem21(buf, buf, F); a_len -= amt; } r = buf; } void UseMulDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, const GF2XModulus& F) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long n = F.n; long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); UseMulDivRem21(qbuf, buf, buf, F); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } r = buf; q = qq; } void UseMulDivX1(GF2X& q, const GF2X& aa, const GF2XModulus& F) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long n = F.n; long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); UseMulDivRem21(qbuf, buf, buf, F); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } q = qq; } static void TrinomReduce(GF2X& x, const GF2X& a, long n, long k) { long wn = n / NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long wdiff = (n-k)/NTL_BITS_PER_LONG; long bdiff = (n-k) - wdiff*NTL_BITS_PER_LONG; long m = a.xrep.length()-1; if (wn > m) { x = a; return; } NTL_GF2XRegister(r); r = a; _ntl_ulong *p = r.xrep.elts(); _ntl_ulong *pp; _ntl_ulong w; if (bn == 0) { if (bdiff == 0) { // bn == 0 && bdiff == 0 while (m >= wn) { w = p[m]; p[m-wdiff] ^= w; p[m-wn] ^= w; m--; } } else { // bn == 0 && bdiff != 0 while (m >= wn) { w = p[m]; pp = &p[m-wdiff]; *pp ^= (w >> bdiff); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff)); p[m-wn] ^= w; m--; } } } else { if (bdiff == 0) { // bn != 0 && bdiff == 0 while (m > wn) { w = p[m]; p[m-wdiff] ^= w; pp = &p[m-wn]; *pp ^= (w >> bn); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn)); m--; } w = (p[m] >> bn) << bn;; p[m-wdiff] ^= w; p[0] ^= (w >> bn); p[m] &= ((1UL< wn) { w = p[m]; pp = &p[m-wdiff]; *pp ^= (w >> bdiff);; *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff)); pp = &p[m-wn]; *pp ^= (w >> bn); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn)); m--; } w = (p[m] >> bn) << bn;; p[m-wdiff] ^= (w >> bdiff); if (m-wdiff-1 >= 0) p[m-wdiff-1] ^= (w << (NTL_BITS_PER_LONG-bdiff)); p[0] ^= (w >> bn); p[m] &= ((1UL<= 0 && p[wn] == 0) wn--; r.xrep.QuickSetLength(wn+1); x = r; } static void PentReduce(GF2X& x, const GF2X& a, long n, long k3, long k2, long k1) { long wn = n / NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long m = a.xrep.length()-1; if (wn > m) { x = a; return; } long wdiff1 = (n-k1)/NTL_BITS_PER_LONG; long bdiff1 = (n-k1) - wdiff1*NTL_BITS_PER_LONG; long wdiff2 = (n-k2)/NTL_BITS_PER_LONG; long bdiff2 = (n-k2) - wdiff2*NTL_BITS_PER_LONG; long wdiff3 = (n-k3)/NTL_BITS_PER_LONG; long bdiff3 = (n-k3) - wdiff3*NTL_BITS_PER_LONG; NTL_GF2XRegister(r); r = a; _ntl_ulong *p = r.xrep.elts(); _ntl_ulong *pp; _ntl_ulong w; while (m > wn) { w = p[m]; if (bn == 0) p[m-wn] ^= w; else { pp = &p[m-wn]; *pp ^= (w >> bn); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn)); } if (bdiff1 == 0) p[m-wdiff1] ^= w; else { pp = &p[m-wdiff1]; *pp ^= (w >> bdiff1); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff1)); } if (bdiff2 == 0) p[m-wdiff2] ^= w; else { pp = &p[m-wdiff2]; *pp ^= (w >> bdiff2); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff2)); } if (bdiff3 == 0) p[m-wdiff3] ^= w; else { pp = &p[m-wdiff3]; *pp ^= (w >> bdiff3); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff3)); } m--; } w = (p[m] >> bn) << bn; p[0] ^= (w >> bn); if (bdiff1 == 0) p[m-wdiff1] ^= w; else { p[m-wdiff1] ^= (w >> bdiff1); if (m-wdiff1-1 >= 0) p[m-wdiff1-1] ^= (w << (NTL_BITS_PER_LONG-bdiff1)); } if (bdiff2 == 0) p[m-wdiff2] ^= w; else { p[m-wdiff2] ^= (w >> bdiff2); if (m-wdiff2-1 >= 0) p[m-wdiff2-1] ^= (w << (NTL_BITS_PER_LONG-bdiff2)); } if (bdiff3 == 0) p[m-wdiff3] ^= w; else { p[m-wdiff3] ^= (w >> bdiff3); if (m-wdiff3-1 >= 0) p[m-wdiff3-1] ^= (w << (NTL_BITS_PER_LONG-bdiff3)); } if (bn != 0) p[m] &= ((1UL<= 0 && p[wn] == 0) wn--; r.xrep.QuickSetLength(wn+1); x = r; } static void RightShiftAdd(GF2X& c, const GF2X& a, long n) { if (n < 0) { Error("RightShiftAdd: negative shamt"); } if (n == 0) { add(c, c, a); return; } long sa = a.xrep.length(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (wn >= sa) { return; } long sc = c.xrep.length(); long i; if (sa-wn > sc) c.xrep.SetLength(sa-wn); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); for (i = sc; i < sa-wn; i++) cp[i] = 0; if (bn == 0) { for (i = 0; i < sa-wn; i++) cp[i] ^= ap[i+wn]; } else { for (i = 0; i < sa-wn-1; i++) cp[i] ^= (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn)); cp[sa-wn-1] ^= ap[sa-1] >> bn; } c.normalize(); } static void TriDiv21(GF2X& q, const GF2X& a, long n, long k) { NTL_GF2XRegister(P1); RightShift(P1, a, n); if (k != 1) RightShiftAdd(P1, P1, n-k); q = P1; } static void TriDivRem21(GF2X& q, GF2X& r, const GF2X& a, long n, long k) { NTL_GF2XRegister(Q); TriDiv21(Q, a, n, k); TrinomReduce(r, a, n, k); q = Q; } static void PentDiv21(GF2X& q, const GF2X& a, long n, long k3, long k2, long k1) { if (deg(a) < n) { clear(q); return; } NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); RightShift(P1, a, n); RightShift(P2, P1, n-k3); RightShiftAdd(P2, P1, n-k2); if (k1 != 1) { RightShiftAdd(P2, P1, n-k1); } add(P2, P2, P1); q = P2; } static void PentDivRem21(GF2X& q, GF2X& r, const GF2X& a, long n, long k3, long k2, long k1) { NTL_GF2XRegister(Q); PentDiv21(Q, a, n, k3, k2, k1); PentReduce(r, a, n, k3, k2, k1); q = Q; } static void TriDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, long n, long k) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); TriDivRem21(qbuf, buf, buf, n, k); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } r = buf; q = qq; } static void TriDivX1(GF2X& q, const GF2X& aa, long n, long k) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); TriDivRem21(qbuf, buf, buf, n, k); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } q = qq; } static void PentDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, long n, long k3, long k2, long k1) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); PentDivRem21(qbuf, buf, buf, n, k3, k2, k1); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } r = buf; q = qq; } static void PentDivX1(GF2X& q, const GF2X& aa, long n, long k3, long k2, long k1) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); PentDivRem21(qbuf, buf, buf, n, k3, k2, k1); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } q = qq; } void rem(GF2X& r, const GF2X& a, const GF2XModulus& F) { long n = F.n; if (n < 0) Error("rem: uninitialized modulus"); if (F.method == GF2X_MOD_TRI) { TrinomReduce(r, a, n, F.k3); return; } if (F.method == GF2X_MOD_PENT) { PentReduce(r, a, n, F.k3, F.k2, F.k1); return; } long da = deg(a); if (da < n) { r = a; } else if (F.method == GF2X_MOD_MUL) { if (da <= 2*(n-1)) UseMulRem21(r, a, F); else UseMulRemX1(r, a, F); } else if (F.method == GF2X_MOD_SPECIAL) { long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; while (1) { if (atop[0] & (1UL << posa)) { stab_top = &F.stab1[posa << 1]; i = F.stab_cnt[posa]; atop[i] ^= stab_top[0]; atop[i+1] ^= stab_top[1]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } } long sn = F.size; r.xrep.SetLength(sn); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sn; i++) rp[i] = ap[i]; } r.xrep[sn-1] &= F.msk; r.normalize(); } else { long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; while (1) { if (atop[0] & (1UL << posa)) { stab_top = F.stab_ptr[posa]; for (i = F.stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } } long sn = F.size; r.xrep.SetLength(sn); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sn; i++) rp[i] = ap[i]; } r.normalize(); } GF2X_rembuf.release(); } void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F) { long da = deg(a); long n = F.n; if (n < 0) Error("DivRem: uninitialized modulus"); if (da < n) { r = a; clear(q); } else if (F.method == GF2X_MOD_TRI) { if (da <= 2*(n-1)) TriDivRem21(q, r, a, F.n, F.k3); else TriDivRemX1(q, r, a, F.n, F.k3); } else if (F.method == GF2X_MOD_PENT) { if (da <= 2*(n-1)) PentDivRem21(q, r, a, F.n, F.k3, F.k2, F.k1); else PentDivRemX1(q, r, a, F.n, F.k3, F.k2, F.k1); } else if (F.method == GF2X_MOD_MUL) { if (da <= 2*(n-1)) UseMulDivRem21(q, r, a, F); else UseMulDivRemX1(q, r, a, F); } else if (F.method == GF2X_MOD_SPECIAL) { long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); long dq = da - n; long sq = dq/NTL_BITS_PER_LONG + 1; long posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *qtop = &qp[sq-1]; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = &F.stab1[posa << 1]; i = F.stab_cnt[posa]; atop[i] ^= stab_top[0]; atop[i+1] ^= stab_top[1]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } long sn = F.size; r.xrep.SetLength(sn); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sn; i++) rp[i] = ap[i]; } r.xrep[sn-1] &= F.msk; r.normalize(); } else { long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); long dq = da - n; long sq = dq/NTL_BITS_PER_LONG + 1; long posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *qtop = &qp[sq-1]; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = F.stab_ptr[posa]; for (i = F.stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } long sn = F.size; r.xrep.SetLength(sn); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sn; i++) rp[i] = ap[i]; } r.normalize(); } GF2X_rembuf.release(); } void div(GF2X& q, const GF2X& a, const GF2XModulus& F) { long da = deg(a); long n = F.n; if (n < 0) Error("div: uninitialized modulus"); if (da < n) { clear(q); } else if (F.method == GF2X_MOD_TRI) { if (da <= 2*(n-1)) TriDiv21(q, a, F.n, F.k3); else TriDivX1(q, a, F.n, F.k3); } else if (F.method == GF2X_MOD_PENT) { if (da <= 2*(n-1)) PentDiv21(q, a, F.n, F.k3, F.k2, F.k1); else PentDivX1(q, a, F.n, F.k3, F.k2, F.k1); } else if (F.method == GF2X_MOD_MUL) { if (da <= 2*(n-1)) UseMulDiv21(q, a, F); else UseMulDivX1(q, a, F); } else if (F.method == GF2X_MOD_SPECIAL) { long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); long dq = da - n; long sq = dq/NTL_BITS_PER_LONG + 1; long posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *qtop = &qp[sq-1]; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = &F.stab1[posa << 1]; i = F.stab_cnt[posa]; atop[i] ^= stab_top[0]; atop[i+1] ^= stab_top[1]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } } else { long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); long dq = da - n; long sq = dq/NTL_BITS_PER_LONG + 1; long posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *qtop = &qp[sq-1]; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = F.stab_ptr[posa]; for (i = F.stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } } GF2X_rembuf.release(); } void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2XModulus& F) { if (F.n < 0) Error("MulMod: uninitialized modulus"); NTL_GF2XRegister(t); mul(t, a, b); rem(c, t, F); } void SqrMod(GF2X& c, const GF2X& a, const GF2XModulus& F) { if (F.n < 0) Error("SqrMod: uninitialized modulus"); NTL_GF2XRegister(t); sqr(t, a); rem(c, t, F); } // we need these two versions to prevent a GF2XModulus // from being constructed. void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2X& f) { NTL_GF2XRegister(t); mul(t, a, b); rem(c, t, f); } void SqrMod(GF2X& c, const GF2X& a, const GF2X& f) { NTL_GF2XRegister(t); sqr(t, a); rem(c, t, f); } static long OptWinSize(long n) // finds k that minimizes n/(k+1) + 2^{k-1} { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/(double(k+2)) + double(1L << k); if (v_new >= v) break; v = v_new; k++; } return k; } void PowerMod(GF2X& h, const GF2X& g, const ZZ& e, const GF2XModulus& F) // h = g^e mod f using "sliding window" algorithm { if (deg(g) >= F.n) Error("PowerMod: bad args"); if (e == 0) { set(h); return; } if (e == 1) { h = g; return; } if (e == -1) { InvMod(h, g, F); return; } if (e == 2) { SqrMod(h, g, F); return; } if (e == -2) { SqrMod(h, g, F); InvMod(h, h, F); return; } long n = NumBits(e); GF2X res; res.SetMaxLength(F.n); set(res); long i; if (n < 16) { // plain square-and-multiply algorithm for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, g, F); } if (e < 0) InvMod(res, res, F); h = res; return; } long k = OptWinSize(n); k = min(k, 9); vec_GF2X v; v.SetLength(1L << (k-1)); v[0] = g; if (k > 1) { GF2X t; SqrMod(t, g, F); for (i = 1; i < (1L << (k-1)); i++) MulMod(v[i], v[i-1], t, F); } long val; long cnt; long m; val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | bit(e, i); if (val == 0) SqrMod(res, res, F); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { SqrMod(res, res, F); m = m >> 1; } MulMod(res, res, v[val >> 1], F); while (cnt > 0) { SqrMod(res, res, F); cnt--; } val = 0; } } if (e < 0) InvMod(res, res, F); h = res; } void PowerXMod(GF2X& hh, const ZZ& e, const GF2XModulus& F) { if (F.n < 0) Error("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; GF2X h; h.SetMaxLength(F.n+1); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) { MulByX(h, h); if (coeff(h, F.n) != 0) add(h, h, F.f); } } if (e < 0) InvMod(h, h, F); hh = h; } void UseMulRem(GF2X& r, const GF2X& a, const GF2X& b) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); add(P1, P1, a); r = P1; } void UseMulDivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); add(P1, P1, a); r = P1; q = P2; } void UseMulDiv(GF2X& q, const GF2X& a, const GF2X& b) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); q = P2; } const long GF2X_DIV_CROSS = 100; void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sb < GF2X_DIV_CROSS || sa-sb < GF2X_DIV_CROSS) PlainDivRem(q, r, a, b); else if (sa < 4*sb) UseMulDivRem(q, r, a, b); else { GF2XModulus B; build(B, b); DivRem(q, r, a, B); } } void div(GF2X& q, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sb < GF2X_DIV_CROSS || sa-sb < GF2X_DIV_CROSS) PlainDiv(q, a, b); else if (sa < 4*sb) UseMulDiv(q, a, b); else { GF2XModulus B; build(B, b); div(q, a, B); } } void rem(GF2X& r, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sb < GF2X_DIV_CROSS || sa-sb < GF2X_DIV_CROSS) PlainRem(r, a, b); else if (sa < 4*sb) UseMulRem(r, a, b); else { GF2XModulus B; build(B, b); rem(r, a, B); } } static inline void swap(_ntl_ulong_ptr& a, _ntl_ulong_ptr& b) { _ntl_ulong_ptr t; t = a; a = b; b = t; } static void BaseGCD(GF2X& d, const GF2X& a_in, const GF2X& b_in) { NTL_GF2XRegister(a); NTL_GF2XRegister(b); if (IsZero(a_in)) { d = b_in; return; } if (IsZero(b_in)) { d = a_in; return; } a.xrep.SetMaxLength(a_in.xrep.length()+1); b.xrep.SetMaxLength(b_in.xrep.length()+1); a = a_in; b = b_in; _ntl_ulong *ap = a.xrep.elts(); _ntl_ulong *bp = b.xrep.elts(); long da = deg(a); long wa = da/NTL_BITS_PER_LONG; long ba = da - wa*NTL_BITS_PER_LONG; long db = deg(b); long wb = db/NTL_BITS_PER_LONG; long bb = db - wb*NTL_BITS_PER_LONG; long parity = 0; for (;;) { if (da < db) { swap(ap, bp); swap(da, db); swap(wa, wb); swap(ba, bb); parity = 1 - parity; } // da >= db if (db == -1) break; ShiftAdd(ap, bp, wb+1, da-db); _ntl_ulong msk = 1UL << ba; _ntl_ulong aa = ap[wa]; while ((aa & msk) == 0) { da--; msk = msk >> 1; ba--; if (!msk) { wa--; ba = NTL_BITS_PER_LONG-1; msk = 1UL << (NTL_BITS_PER_LONG-1); if (wa < 0) break; aa = ap[wa]; } } } a.normalize(); b.normalize(); if (!parity) { d = a; } else { d = b; } } void OldGCD(GF2X& d, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sb >= 10 && 2*sa > 3*sb) { NTL_GF2XRegister(r); rem(r, a, b); BaseGCD(d, b, r); } else if (sa >= 10 && 2*sb > 3*sa) { NTL_GF2XRegister(r); rem(r, b, a); BaseGCD(d, a, r); } else { BaseGCD(d, a, b); } } #define XX_STEP(ap,da,wa,ba,rp,sr,bp,db,wb,bb,sp,ss) \ long delta = da-db; \ \ if (delta == 0) { \ long i; \ for (i = wb; i >= 0; i--) ap[i] ^= bp[i]; \ for (i = ss-1; i >= 0; i--) rp[i] ^= sp[i]; \ if (ss > sr) sr = ss; \ } \ else if (delta == 1) { \ long i; \ _ntl_ulong tt, tt1; \ \ tt = bp[wb] >> (NTL_BITS_PER_LONG-1); \ if (tt) ap[wb+1] ^= tt; \ tt = bp[wb]; \ for (i = wb; i >= 1; i--) \ tt1 = bp[i-1], ap[i] ^= (tt << 1) | (tt1 >> (NTL_BITS_PER_LONG-1)), \ tt = tt1; \ ap[0] ^= tt << 1; \ \ if (ss > 0) { \ long t = ss; \ tt = sp[ss-1] >> (NTL_BITS_PER_LONG-1); \ if (tt) rp[ss] ^= tt, t++; \ tt = sp[ss-1]; \ for (i = ss-1; i >= 1; i--) \ tt1=sp[i-1], \ rp[i] ^= (tt << 1) | (tt1 >> (NTL_BITS_PER_LONG-1)), \ tt = tt1; \ rp[0] ^= tt << 1; \ if (t > sr) sr = t; \ } \ } \ else if (delta < NTL_BITS_PER_LONG) { \ long i; \ _ntl_ulong tt, tt1; \ long rdelta = NTL_BITS_PER_LONG-delta; \ \ tt = bp[wb] >> rdelta; \ if (tt) ap[wb+1] ^= tt; \ tt=bp[wb]; \ for (i = wb; i >= 1; i--) \ tt1=bp[i-1], ap[i] ^= (tt << delta) | (tt1 >> rdelta), \ tt=tt1; \ ap[0] ^= tt << delta; \ \ if (ss > 0) { \ long t = ss; \ tt = sp[ss-1] >> rdelta; \ if (tt) rp[ss] ^= tt, t++; \ tt=sp[ss-1]; \ for (i = ss-1; i >= 1; i--) \ tt1=sp[i-1], rp[i] ^= (tt << delta) | (tt1 >> rdelta), \ tt=tt1; \ rp[0] ^= tt << delta; \ if (t > sr) sr = t; \ } \ } \ else { \ ShiftAdd(ap, bp, wb+1, da-db); \ ShiftAdd(rp, sp, ss, da-db); \ long t = ss + (da-db+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; \ if (t > sr) { \ while (t > 0 && rp[t-1] == 0) t--; \ sr = t; \ } \ } \ \ _ntl_ulong msk = 1UL << ba; \ _ntl_ulong aa = ap[wa]; \ \ while ((aa & msk) == 0) { \ da--; \ msk = msk >> 1; \ ba--; \ if (!msk) { \ wa--; \ ba = NTL_BITS_PER_LONG-1; \ msk = 1UL << (NTL_BITS_PER_LONG-1); \ if (wa < 0) break; \ aa = ap[wa]; \ } \ } \ static void XXGCD(GF2X& d, GF2X& r_out, const GF2X& a_in, const GF2X& b_in) { NTL_GF2XRegister(a); NTL_GF2XRegister(b); NTL_GF2XRegister(r); NTL_GF2XRegister(s); if (IsZero(b_in)) { d = a_in; set(r_out); return; } if (IsZero(a_in)) { d = b_in; clear(r_out); return; } a.xrep.SetMaxLength(a_in.xrep.length()+1); b.xrep.SetMaxLength(b_in.xrep.length()+1); long max_sz = max(a_in.xrep.length(), b_in.xrep.length()); r.xrep.SetLength(max_sz+1); s.xrep.SetLength(max_sz+1); _ntl_ulong *rp = r.xrep.elts(); _ntl_ulong *sp = s.xrep.elts(); long i; for (i = 0; i <= max_sz; i++) { rp[i] = sp[i] = 0; } rp[0] = 1; long sr = 1; long ss = 0; a = a_in; b = b_in; _ntl_ulong *ap = a.xrep.elts(); _ntl_ulong *bp = b.xrep.elts(); long da = deg(a); long wa = da/NTL_BITS_PER_LONG; long ba = da - wa*NTL_BITS_PER_LONG; long db = deg(b); long wb = db/NTL_BITS_PER_LONG; long bb = db - wb*NTL_BITS_PER_LONG; long parity = 0; for (;;) { if (da == -1 || db == -1) break; if (da < db || (da == db && parity)) { if (da < db && !parity) parity = 1; XX_STEP(bp,db,wb,bb,sp,ss,ap,da,wa,ba,rp,sr) } else { parity = 0; XX_STEP(ap,da,wa,ba,rp,sr,bp,db,wb,bb,sp,ss) } } a.normalize(); b.normalize(); r.normalize(); s.normalize(); if (db == -1) { d = a; r_out = r; } else { d = b; r_out = s; } } static void BaseXGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b) { if (IsZero(b)) { d = a; set(s); clear(t); } else { NTL_GF2XRegister(t1); NTL_GF2XRegister(b1); b1 = b; XXGCD(d, s, a, b); mul(t1, a, s); add(t1, t1, d); div(t, t1, b1); } } void OldXGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sb >= 10 && 2*sa > 3*sb) { NTL_GF2XRegister(r); NTL_GF2XRegister(q); NTL_GF2XRegister(s1); NTL_GF2XRegister(t1); DivRem(q, r, a, b); BaseXGCD(d, s1, t1, b, r); mul(r, t1, q); add(r, r, s1); // r = s1 - t1*q, but sign doesn't matter s = t1; t = r; } else if (sa >= 10 && 2*sb > 3*sa) { NTL_GF2XRegister(r); NTL_GF2XRegister(q); NTL_GF2XRegister(s1); NTL_GF2XRegister(t1); DivRem(q, r, b, a); BaseXGCD(d, s1, t1, a, r); mul(r, t1, q); add(r, r, s1); // r = s1 - t1*q, but sign doesn't matter t = t1; s = r; } else { BaseXGCD(d, s, t, a, b); } } static void BaseInvMod(GF2X& d, GF2X& s, const GF2X& a, const GF2X& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvMod: bad args"); long sa = a.xrep.length(); long sf = f.xrep.length(); if ((sa >= 10 && 2*sf > 3*sa) || sf > NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) { NTL_GF2XRegister(t); XGCD(d, s, t, a, f); } else { XXGCD(d, s, a, f); } } void InvMod(GF2X& c, const GF2X& a, const GF2X& f) { NTL_GF2XRegister(d); NTL_GF2XRegister(s); BaseInvMod(d, s, a, f); if (!IsOne(d)) Error("InvMod: inverse undefined"); c = s; } long InvModStatus(GF2X& c, const GF2X& a, const GF2X& f) { NTL_GF2XRegister(d); NTL_GF2XRegister(s); BaseInvMod(d, s, a, f); if (!IsOne(d)) { c = d; return 1; } c = s; return 0; } void diff(GF2X& c, const GF2X& a) { RightShift(c, a, 1); // clear odd coeffs long dc = deg(c); long i; for (i = 1; i <= dc; i += 2) SetCoeff(c, i, 0); } void conv(GF2X& c, long a) { if (a & 1) set(c); else clear(c); } void conv(GF2X& c, GF2 a) { if (a == 1) set(c); else clear(c); } void conv(GF2X& x, const vec_GF2& a) { x.xrep = a.rep; x.normalize(); } void conv(vec_GF2& x, const GF2X& a) { VectorCopy(x, a, deg(a)+1); } /* additional legacy conversions for v6 conversion regime */ #ifndef NTL_WIZARD_HACK void conv(GF2X& x, const ZZX& a) { long n = deg(a) + 1; long i; x.SetLength(n); for (i = 0; i < n; i++) conv(x[i], a[i]); x.normalize(); } void conv(ZZX& x, const GF2X& a) { long n = deg(a) + 1; long i; x.rep.SetLength(n); for (i = 0; i < n; i++) x.rep[i] = rep(coeff(a, i)); x.normalize(); } #endif /* ------------------------------------- */ void VectorCopy(vec_GF2& x, const GF2X& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long wa = a.xrep.length(); long wx = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long wmin = min(wa, wx); x.SetLength(n); const _ntl_ulong *ap = a.xrep.elts(); _ntl_ulong *xp = x.rep.elts(); long i; for (i = 0; i < wmin; i++) xp[i] = ap[i]; if (wa < wx) { for (i = wa; i < wx; i++) xp[i] = 0; } else { long p = n % NTL_BITS_PER_LONG; if (p != 0) xp[wx-1] &= (1UL << p) - 1UL; } } void add(GF2X& c, const GF2X& a, long b) { c = a; if (b & 1) { long n = c.xrep.length(); if (n == 0) set(c); else { c.xrep[0] ^= 1; if (n == 1 && !c.xrep[0]) c.xrep.SetLength(0); } } } void add(GF2X& c, const GF2X& a, GF2 b) { add(c, a, rep(b)); } void MulTrunc(GF2X& c, const GF2X& a, const GF2X& b, long n) { NTL_GF2XRegister(t); mul(t, a, b); trunc(c, t, n); } void SqrTrunc(GF2X& c, const GF2X& a, long n) { NTL_GF2XRegister(t); sqr(t, a); trunc(c, t, n); } long divide(GF2X& q, const GF2X& a, const GF2X& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } NTL_GF2XRegister(lq); NTL_GF2XRegister(r); DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const GF2X& a, const GF2X& b) { if (IsZero(b)) return IsZero(a); NTL_GF2XRegister(r); rem(r, a, b); if (!IsZero(r)) return 0; return 1; } /*** modular composition routines and data structures ***/ void InnerProduct(GF2X& x, const GF2X& v, long dv, long low, long high, const vec_GF2X& H, long n, WordVector& t) { long i, j; _ntl_ulong *tp = t.elts(); for (i = 0; i < n; i++) tp[i] = 0; long w_low = low/NTL_BITS_PER_LONG; long b_low = low - w_low*NTL_BITS_PER_LONG; const _ntl_ulong *vp = &v.xrep[w_low]; _ntl_ulong msk = 1UL << b_low; _ntl_ulong vv = *vp; high = min(high, dv); i = low; for (;;) { if (vv & msk) { const WordVector& h = H[i-low].xrep; long m = h.length(); const _ntl_ulong *hp = h.elts(); for (j = 0; j < m; j++) tp[j] ^= hp[j]; } i++; if (i > high) break; msk = msk << 1; if (!msk) { msk = 1UL; vp++; vv = *vp; } } x.xrep = t; x.normalize(); } void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& A, const GF2XModulus& F) { long dg = deg(g); if (dg <= 0) { x = g; return; } GF2X s, t; WordVector scratch(INIT_SIZE, F.size); long m = A.H.length() - 1; long l = (((dg+1)+m-1)/m) - 1; InnerProduct(t, g, dg, l*m, l*m + m - 1, A.H, F.size, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g, dg, i*m, i*m + m - 1, A.H, F.size, scratch); MulMod(t, t, A.H[m], F); add(t, t, s); } x = t; } void build(GF2XArgument& A, const GF2X& h, const GF2XModulus& F, long m) { if (m <= 0 || deg(h) >= F.n) Error("build GF2XArgument: bad args"); if (m > F.n) m = F.n; long i; A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], h, F); } void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F) // x = g(h) mod f { long m = SqrRoot(deg(g)+1); if (m == 0) { clear(x); return; } GF2XArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2, const GF2X& h, const GF2XModulus& F) { long m = SqrRoot(deg(g1) + deg(g2) + 2); if (m == 0) { clear(x1); clear(x2); return; } GF2XArgument A; build(A, h, F, m); GF2X xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(GF2X& x1, GF2X& x2, GF2X& x3, const GF2X& g1, const GF2X& g2, const GF2X& g3, const GF2X& h, const GF2XModulus& F) { long m = SqrRoot(deg(g1) + deg(g2) + deg(g3) + 3); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } GF2XArgument A; build(A, h, F, m); GF2X xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F) { long db = deg(b); if (db >= F.n) Error("build TransMultiplier: bad args"); GF2X t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, d); if (F.method != GF2X_MOD_TRI && F.method != GF2X_MOD_PENT) { // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, d); } if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, db); } void TransMulMod(GF2X& x, const GF2X& a, const GF2XTransMultiplier& B, const GF2XModulus& F) { if (deg(a) >= F.n) Error("TransMulMod: bad args"); NTL_GF2XRegister(t1); NTL_GF2XRegister(t2); NTL_GF2XRegister(t3); mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); if (F.method == GF2X_MOD_TRI) { RightShift(t2, a, F.k3); add(t2, t2, a); } else if (F.method == GF2X_MOD_PENT) { RightShift(t2, a, F.k3); RightShift(t3, a, F.k2); add(t2, t2, t3); RightShift(t3, a, F.k1); add(t2, t2, t3); add(t2, t2, a); } else { mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); } trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); MulByX(t2, t2); add(x, t1, t2); } void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F) { NTL_GF2XRegister(xx); NTL_GF2XRegister(aa); conv(aa, a); TransMulMod(xx, aa, B, F); conv(x, xx); } void ProjectPowers(GF2X& x, const GF2X& a, long k, const GF2XArgument& H, const GF2XModulus& F) { long n = F.n; if (deg(a) >= n || k < 0 || NTL_OVERFLOW(k, 1, 0)) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; GF2XTransMultiplier M; build(M, H.H[m], F); GF2X s; s = a; x.SetMaxLength(k); clear(x); long i; for (i = 0; i <= l; i++) { long m1 = min(m, k-i*m); for (long j = 0; j < m1; j++) SetCoeff(x, i*m+j, InnerProduct(H.H[j].xrep, s.xrep)); if (i < l) TransMulMod(s, s, M, F); } } void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F) { GF2X xx; ProjectPowers(xx, to_GF2X(a), k, H, F); VectorCopy(x, xx, k); } void ProjectPowers(GF2X& x, const GF2X& a, long k, const GF2X& h, const GF2XModulus& F) { if (deg(a) >= F.n || k < 0) Error("ProjectPowers: bad args"); if (k == 0) { clear(x); return; } long m = SqrRoot(k); GF2XArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2X& H, const GF2XModulus& F) { GF2X xx; ProjectPowers(xx, to_GF2X(a), k, H, F); VectorCopy(x, xx, k); } void OldMinPolyInternal(GF2X& h, const GF2X& x, long m) { GF2X a, b, r, s; GF2X a_in, b_in; if (IsZero(x)) { set(h); return; } clear(a_in); SetCoeff(a_in, 2*m); CopyReverse(b_in, x, 2*m-1); a.xrep.SetMaxLength(a_in.xrep.length()+1); b.xrep.SetMaxLength(b_in.xrep.length()+1); long max_sz = max(a_in.xrep.length(), b_in.xrep.length()); r.xrep.SetLength(max_sz+1); s.xrep.SetLength(max_sz+1); _ntl_ulong *rp = r.xrep.elts(); _ntl_ulong *sp = s.xrep.elts(); long i; for (i = 0; i <= max_sz; i++) { rp[i] = sp[i] = 0; } sp[0] = 1; long sr = 0; long ss = 1; a = a_in; b = b_in; _ntl_ulong *ap = a.xrep.elts(); _ntl_ulong *bp = b.xrep.elts(); long da = deg(a); long wa = da/NTL_BITS_PER_LONG; long ba = da - wa*NTL_BITS_PER_LONG; long db = deg(b); long wb = db/NTL_BITS_PER_LONG; long bb = db - wb*NTL_BITS_PER_LONG; long parity = 0; for (;;) { if (da < db) { swap(ap, bp); swap(da, db); swap(wa, wb); swap(ba, bb); parity = 1 - parity; swap(rp, sp); swap(sr, ss); } // da >= db if (db < m) break; ShiftAdd(ap, bp, wb+1, da-db); ShiftAdd(rp, sp, ss, da-db); long t = ss + (da-db+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; if (t > sr) { while (t > 0 && rp[t-1] == 0) t--; sr = t; } _ntl_ulong msk = 1UL << ba; _ntl_ulong aa = ap[wa]; while ((aa & msk) == 0) { da--; msk = msk >> 1; ba--; if (!msk) { wa--; ba = NTL_BITS_PER_LONG-1; msk = 1UL << (NTL_BITS_PER_LONG-1); if (wa < 0) break; aa = ap[wa]; } } } a.normalize(); b.normalize(); r.normalize(); s.normalize(); if (!parity) { h = s; } else { h = r; } } void DoMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m, const GF2X& R) { GF2X x; ProjectPowers(x, R, 2*m, g, F); MinPolyInternal(h, x, m); } void MinPolySeq(GF2X& h, const vec_GF2& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) Error("MinPoly: bad args"); if (a.length() < 2*m) Error("MinPoly: sequence too short"); GF2X x; x.xrep = a.rep; x.normalize(); MinPolyInternal(h, x, m); } void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m) { long n = F.n; if (m < 1 || m > n) Error("ProbMinPoly: bad args"); GF2X R; random(R, n); DoMinPolyMod(h, g, F, m, R); } void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F) { ProbMinPolyMod(h, g, F, F.n); } void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F, long m) { GF2X h, h1; long n = F.n; if (m < 1 || m > n) Error("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ GF2X h2, h3; GF2X R; GF2XTransMultiplier H1; for (;;) { random(R, n); build(H1, h1, F); TransMulMod(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m) { if (m < 1 || m > F.n) Error("IrredPoly: bad args"); GF2X R; set(R); DoMinPolyMod(h, g, F, m, R); } void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F) { IrredPolyMod(h, g, F, F.n); } void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F) { MinPolyMod(hh, g, F, F.n); } void MulByXMod(GF2X& c, const GF2X& a, const GF2XModulus& F) { long da = deg(a); long df = deg(F); if (da >= df) Error("MulByXMod: bad args"); MulByX(c, a); if (da >= 0 && da == df-1) add(c, c, F); } static void MulByXModAux(GF2X& c, const GF2X& a, const GF2X& f) { long da = deg(a); long df = deg(f); if (da >= df) Error("MulByXMod: bad args"); MulByX(c, a); if (da >= 0 && da == df-1) add(c, c, f); } void MulByXMod(GF2X& h, const GF2X& a, const GF2X& f) { if (&h == &f) { GF2X hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void power(GF2X& x, const GF2X& a, long e) { if (e < 0) { Error("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da > (NTL_MAX_LONG-1)/e) Error("overflow in power"); GF2X res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } static void FastTraceVec(vec_GF2& S, const GF2XModulus& f) { long n = deg(f); if (n <= 0) Error("TraceVec: bad args"); GF2X x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); VectorCopy(S, x, n); S.put(0, to_GF2(n)); } static void PlainTraceVec(vec_GF2& S, const GF2X& f) { long n = deg(f); if (n <= 0) Error("TraceVec: bad args"); if (n == 0) { S.SetLength(0); return; } GF2X x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); VectorCopy(S, x, n); S.put(0, to_GF2(n)); } void TraceVec(vec_GF2& S, const GF2X& f) { PlainTraceVec(S, f); } static void ComputeTraceVec(const GF2XModulus& F) { vec_GF2& S = *((vec_GF2 *) &F.tracevec); if (S.length() > 0) return; if (F.method == GF2X_MOD_PLAIN) { PlainTraceVec(S, F.f); } else { FastTraceVec(S, F); } } void TraceMod(ref_GF2 x, const GF2X& a, const GF2XModulus& F) { long n = F.n; if (deg(a) >= n) Error("trace: bad args"); // FIXME: in a thread-safe impl, this needs a mutex if (F.tracevec.length() == 0) ComputeTraceVec(F); project(x, F.tracevec, a); } void TraceMod(ref_GF2 x, const GF2X& a, const GF2X& f) { if (deg(a) >= deg(f) || deg(f) <= 0) Error("trace: bad args"); project(x, TraceVec(f), a); } // New versions of GCD, XGCD, and MinPolyInternal // and support routines class _NTL_GF2XMatrix { private: _NTL_GF2XMatrix(const _NTL_GF2XMatrix&); // disable GF2X elts[2][2]; public: _NTL_GF2XMatrix() { } ~_NTL_GF2XMatrix() { } void operator=(const _NTL_GF2XMatrix&); GF2X& operator() (long i, long j) { return elts[i][j]; } const GF2X& operator() (long i, long j) const { return elts[i][j]; } }; void _NTL_GF2XMatrix::operator=(const _NTL_GF2XMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } static void mul(GF2X& U, GF2X& V, const _NTL_GF2XMatrix& M) // (U, V)^T = M*(U, V)^T { GF2X t1, t2, t3; mul(t1, M(0,0), U); mul(t2, M(0,1), V); add(t3, t1, t2); mul(t1, M(1,0), U); mul(t2, M(1,1), V); add(V, t1, t2); U = t3; } static void mul(_NTL_GF2XMatrix& A, _NTL_GF2XMatrix& B, _NTL_GF2XMatrix& C) // A = B*C, B and C are destroyed { GF2X t1, t2; mul(t1, B(0,0), C(0,0)); mul(t2, B(0,1), C(1,0)); add(A(0,0), t1, t2); mul(t1, B(1,0), C(0,0)); mul(t2, B(1,1), C(1,0)); add(A(1,0), t1, t2); mul(t1, B(0,0), C(0,1)); mul(t2, B(0,1), C(1,1)); add(A(0,1), t1, t2); mul(t1, B(1,0), C(0,1)); mul(t2, B(1,1), C(1,1)); add(A(1,1), t1, t2); long i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { B(i,j).kill(); C(i,j).kill(); } } } static void IterHalfGCD(_NTL_GF2XMatrix& M_out, GF2X& U, GF2X& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; GF2X Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { DivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } static void HalfGCD(_NTL_GF2XMatrix& M_out, const GF2X& U, const GF2X& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; GF2X U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_GF2X_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_GF2XMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } GF2X Q; _NTL_GF2XMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); GF2X t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } static void HalfGCD(GF2X& U, GF2X& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_GF2XMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); GF2X Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(GF2X& d, const GF2X& u, const GF2X& v) { long su = u.xrep.length(); long sv = v.xrep.length(); if (su <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG && sv <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) { OldGCD(d, u, v); return; } GF2X u1, v1; u1 = u; v1 = v; long du1 = deg(u1); long dv1 = deg(v1); if (du1 == dv1) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (du1 < dv1) { swap(u1, v1); du1 = dv1; } // deg(u1) > deg(v1) while (du1 >= NTL_GF2X_GCD_CROSSOVER && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } du1 = deg(u1); } OldGCD(d, u1, v1); } static void XHalfGCD(_NTL_GF2XMatrix& M_out, GF2X& U, GF2X& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_GF2X_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_GF2XMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } GF2X Q; _NTL_GF2XMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); GF2X t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b) { // GF2 w; long sa = a.xrep.length(); long sb = b.xrep.length(); if (sa <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG && sb <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) { OldXGCD(d, s, t, a, b); return; } GF2X U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } _NTL_GF2XMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize // inv(w, LeadCoeff(d)); // mul(d, d, w); // mul(s, s, w); // mul(t, t, w); } void MinPolyInternal(GF2X& h, const GF2X& x, long m) { if (m < NTL_GF2X_BERMASS_CROSSOVER) { OldMinPolyInternal(h, x, m); return; } GF2X a, b; _NTL_GF2XMatrix M; SetCoeff(b, 2*m); CopyReverse(a, x, 2*m-1); HalfGCD(M, b, a, m+1); h = M(1,1); } NTL_END_IMPL ntl-6.2.1/src/GF2XFactoring.c000644 000765 000024 00000075247 12377144456 016150 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL long IterIrredTest(const GF2X& f) { long df = deg(f); if (df <= 0) return 0; if (df == 1) return 1; GF2XModulus F; build(F, f); GF2X h; SetX(h); SqrMod(h, h, F); long i, d, limit, limit_sqr; GF2X g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= df) { add(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { SqrMod(g, g, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } void SquareFreeDecomp(vec_pair_GF2X_long& u, const GF2X& ff) { GF2X f = ff; if (IsZero(f)) Error("SquareFreeDecomp: bad args"); GF2X r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long p, k, d; p = 2; d = deg(r)/p; clear(f); for (k = 0; k <= d; k++) if (coeff(r, k*p) == 1) SetCoeff(f, k); m = m*p; } } while (!finished); } static void AddFactor(vec_pair_GF2X_long& factors, const GF2X& g, long d, long verbose) { if (verbose) cerr << "degree=" << d << ", number=" << deg(g)/d << "\n"; append(factors, cons(g, d)); } static void ProcessTable(GF2X& f, vec_pair_GF2X_long& factors, const GF2XModulus& F, long limit, const vec_GF2X& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; GF2X t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); GF2X t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); } static void TraceMap(GF2X& w, const GF2X& a, long d, const GF2XModulus& F) { GF2X y, z; y = a; z = a; long i; for (i = 1; i < d; i++) { SqrMod(z, z, F); add(y, y, z); } w = y; } const long GF2X_BlockingFactor = 40; void DDF(vec_pair_GF2X_long& factors, const GF2X& ff, long verbose) { GF2X f = ff; if (IsZero(f)) Error("DDF: bad args"); factors.SetLength(0); if (deg(f) == 0) return; if (deg(f) == 1) { AddFactor(factors, f, 1, verbose); return; } long GCDTableSize = GF2X_BlockingFactor; GF2XModulus F; build(F, f); long i, d, limit, old_n; GF2X g, X; vec_GF2X tbl(INIT_SIZE, GCDTableSize); SetX(X); i = 0; SqrMod(g, X, F); d = 1; limit = GCDTableSize; while (2*d <= deg(f)) { old_n = deg(f); add(tbl[i], g, X); i++; if (i == limit) { ProcessTable(f, factors, F, i, tbl, d, verbose); i = 0; } d = d + 1; if (2*d <= deg(f)) { // we need to go further if (deg(f) < old_n) { // f has changed build(F, f); rem(g, g, F); } SqrMod(g, g, F); } } ProcessTable(f, factors, F, i, tbl, d-1, verbose); if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose); } static void EDFSplit(GF2X& f1, GF2X& f2, const GF2X& f, long d) { GF2X a, g; GF2XModulus F; build(F, f); long n = F.n; do { random(a, n); TraceMap(g, a, d, F); } while (deg(g) <= 0); GCD(f1, f, g); div(f2, f, f1); } static void RecEDF(vec_GF2X& factors, const GF2X& f, long d) { if (deg(f) == d) { append(factors, f); return; } GF2X f1, f2; EDFSplit(f1, f2, f, d); RecEDF(factors, f1, d); RecEDF(factors, f2, d); } void EDF(vec_GF2X& factors, const GF2X& ff, long d, long verbose) { GF2X f = ff; if (IsZero(f)) Error("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { // factors are X and X+1 factors.SetLength(2); SetX(factors[0]); SetX(factors[1]); SetCoeff(factors[1], 0); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, d); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_GF2X& factors, const GF2X& ff, long verbose) { GF2X f = ff; if (IsZero(f)) Error("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; vec_pair_GF2X_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } DDF(u, f, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } vec_GF2X v; long i; for (i = 0; i < u.length(); i++) { const GF2X& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF EDF(v, g, d, verbose); append(factors, v); } } } void CanZass(vec_pair_GF2X_long& factors, const GF2X& f, long verbose) { if (IsZero(f)) Error("CanZass: bad args"); double t; vec_pair_GF2X_long sfd; vec_GF2X x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(GF2X& f, const vec_pair_GF2X_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); GF2X g; set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } static void ConvertBits(GF2X& x, _ntl_ulong b) { clear(x); long i; for (i = NTL_BITS_PER_LONG-1; i >= 0; i--) if (b & (1UL << i)) SetCoeff(x, i); } void BuildIrred(GF2X& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } GF2X g; _ntl_ulong i; i = 0; do { ConvertBits(g, 2*i+1); SetCoeff(g, n); i++; } while (!IterIrredTest(g)); f = g; } void BuildRandomIrred(GF2X& f, const GF2X& g) { GF2XModulus G; GF2X h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } static int GF2X_irred_tab[][3] = {{0,0,0}, {0,0,0}, {1,0,0}, {1,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {1,0,0}, {4,3,1}, {1,0,0}, {3,0,0}, {2,0,0}, {3,0,0}, {4,3,1}, {5,0,0}, {1,0,0}, {5,3,1}, {3,0,0}, {3,0,0}, {5,2,1}, {3,0,0}, {2,0,0}, {1,0,0}, {5,0,0}, {4,3,1}, {3,0,0}, {4,3,1}, {5,2,1}, {1,0,0}, {2,0,0}, {1,0,0}, {3,0,0}, {7,3,2}, {10,0,0}, {7,0,0}, {2,0,0}, {9,0,0}, {6,4,1}, {6,5,1}, {4,0,0}, {5,4,3}, {3,0,0}, {7,0,0}, {6,4,3}, {5,0,0}, {4,3,1}, {1,0,0}, {5,0,0}, {5,3,2}, {9,0,0}, {4,3,2}, {6,3,1}, {3,0,0}, {6,2,1}, {9,0,0}, {7,0,0}, {7,4,2}, {4,0,0}, {19,0,0}, {7,4,2}, {1,0,0}, {5,2,1}, {29,0,0}, {1,0,0}, {4,3,1}, {18,0,0}, {3,0,0}, {5,2,1}, {9,0,0}, {6,5,2}, {5,3,1}, {6,0,0}, {10,9,3}, {25,0,0}, {35,0,0}, {6,3,1}, {21,0,0}, {6,5,2}, {6,5,3}, {9,0,0}, {9,4,2}, {4,0,0}, {8,3,1}, {7,4,2}, {5,0,0}, {8,2,1}, {21,0,0}, {13,0,0}, {7,6,2}, {38,0,0}, {27,0,0}, {8,5,1}, {21,0,0}, {2,0,0}, {21,0,0}, {11,0,0}, {10,9,6}, {6,0,0}, {11,0,0}, {6,3,1}, {15,0,0}, {7,6,1}, {29,0,0}, {9,0,0}, {4,3,1}, {4,0,0}, {15,0,0}, {9,7,4}, {17,0,0}, {5,4,2}, {33,0,0}, {10,0,0}, {5,4,3}, {9,0,0}, {5,3,2}, {8,7,5}, {4,2,1}, {5,2,1}, {33,0,0}, {8,0,0}, {4,3,1}, {18,0,0}, {6,2,1}, {2,0,0}, {19,0,0}, {7,6,5}, {21,0,0}, {1,0,0}, {7,2,1}, {5,0,0}, {3,0,0}, {8,3,2}, {17,0,0}, {9,8,2}, {57,0,0}, {11,0,0}, {5,3,2}, {21,0,0}, {8,7,1}, {8,5,3}, {15,0,0}, {10,4,1}, {21,0,0}, {5,3,2}, {7,4,2}, {52,0,0}, {71,0,0}, {14,0,0}, {27,0,0}, {10,9,7}, {53,0,0}, {3,0,0}, {6,3,2}, {1,0,0}, {15,0,0}, {62,0,0}, {9,0,0}, {6,5,2}, {8,6,5}, {31,0,0}, {5,3,2}, {18,0,0}, {27,0,0}, {7,6,3}, {10,8,7}, {9,8,3}, {37,0,0}, {6,0,0}, {15,3,2}, {34,0,0}, {11,0,0}, {6,5,2}, {1,0,0}, {8,5,2}, {13,0,0}, {6,0,0}, {11,3,2}, {8,0,0}, {31,0,0}, {4,2,1}, {3,0,0}, {7,6,1}, {81,0,0}, {56,0,0}, {9,8,7}, {24,0,0}, {11,0,0}, {7,6,5}, {6,5,2}, {6,5,2}, {8,7,6}, {9,0,0}, {7,2,1}, {15,0,0}, {87,0,0}, {8,3,2}, {3,0,0}, {9,4,2}, {9,0,0}, {34,0,0}, {5,3,2}, {14,0,0}, {55,0,0}, {8,7,1}, {27,0,0}, {9,5,2}, {10,9,5}, {43,0,0}, {9,3,1}, {6,0,0}, {7,0,0}, {11,10,8}, {105,0,0}, {6,5,2}, {73,0,0}, {23,0,0}, {7,3,1}, {45,0,0}, {11,0,0}, {8,4,1}, {7,0,0}, {8,6,2}, {5,4,2}, {33,0,0}, {9,8,3}, {32,0,0}, {10,7,3}, {10,9,4}, {113,0,0}, {10,4,1}, {8,7,6}, {26,0,0}, {9,4,2}, {74,0,0}, {31,0,0}, {9,6,1}, {5,0,0}, {7,4,1}, {73,0,0}, {36,0,0}, {8,5,3}, {70,0,0}, {95,0,0}, {8,5,1}, {111,0,0}, {6,4,1}, {11,2,1}, {82,0,0}, {15,14,10}, {35,0,0}, {103,0,0}, {7,4,2}, {15,0,0}, {46,0,0}, {7,2,1}, {52,0,0}, {10,5,2}, {12,0,0}, {71,0,0}, {10,6,2}, {15,0,0}, {7,6,4}, {9,8,4}, {93,0,0}, {9,6,2}, {42,0,0}, {47,0,0}, {8,6,3}, {25,0,0}, {7,6,1}, {53,0,0}, {58,0,0}, {9,3,2}, {23,0,0}, {67,0,0}, {11,10,9}, {63,0,0}, {12,6,3}, {5,0,0}, {5,0,0}, {9,5,2}, {93,0,0}, {35,0,0}, {12,7,5}, {53,0,0}, {10,7,5}, {69,0,0}, {71,0,0}, {11,10,1}, {21,0,0}, {5,3,2}, {12,11,5}, {37,0,0}, {11,6,1}, {33,0,0}, {48,0,0}, {7,3,2}, {5,0,0}, {11,8,4}, {11,6,4}, {5,0,0}, {9,5,2}, {41,0,0}, {1,0,0}, {11,2,1}, {102,0,0}, {7,3,1}, {8,4,2}, {15,0,0}, {10,6,4}, {93,0,0}, {7,5,3}, {9,7,4}, {79,0,0}, {15,0,0}, {10,9,1}, {63,0,0}, {7,4,2}, {45,0,0}, {36,0,0}, {4,3,1}, {31,0,0}, {67,0,0}, {10,3,1}, {51,0,0}, {10,5,2}, {10,3,1}, {34,0,0}, {8,3,1}, {50,0,0}, {99,0,0}, {10,6,2}, {89,0,0}, {2,0,0}, {5,2,1}, {10,7,2}, {7,4,1}, {55,0,0}, {4,3,1}, {16,10,7}, {45,0,0}, {10,8,6}, {125,0,0}, {75,0,0}, {7,2,1}, {22,0,0}, {63,0,0}, {11,10,3}, {103,0,0}, {6,5,2}, {53,0,0}, {34,0,0}, {13,11,6}, {69,0,0}, {99,0,0}, {6,5,1}, {10,9,7}, {11,10,2}, {57,0,0}, {68,0,0}, {5,3,2}, {7,4,1}, {63,0,0}, {8,5,3}, {9,0,0}, {9,6,5}, {29,0,0}, {21,0,0}, {7,3,2}, {91,0,0}, {139,0,0}, {8,3,2}, {111,0,0}, {8,7,2}, {8,6,5}, {16,0,0}, {8,7,5}, {41,0,0}, {43,0,0}, {10,8,5}, {47,0,0}, {5,2,1}, {81,0,0}, {90,0,0}, {12,3,2}, {6,0,0}, {83,0,0}, {8,7,1}, {159,0,0}, {10,9,5}, {9,0,0}, {28,0,0}, {13,10,6}, {7,0,0}, {135,0,0}, {11,6,5}, {25,0,0}, {12,7,6}, {7,6,2}, {26,0,0}, {5,3,2}, {152,0,0}, {171,0,0}, {9,8,5}, {65,0,0}, {13,8,2}, {141,0,0}, {71,0,0}, {5,3,2}, {87,0,0}, {10,4,3}, {12,10,3}, {147,0,0}, {10,7,6}, {13,0,0}, {102,0,0}, {9,5,2}, {107,0,0}, {199,0,0}, {15,5,4}, {7,0,0}, {5,4,2}, {149,0,0}, {25,0,0}, {9,7,2}, {12,0,0}, {63,0,0}, {11,6,5}, {105,0,0}, {10,8,7}, {14,6,1}, {120,0,0}, {13,4,3}, {33,0,0}, {12,11,5}, {12,9,5}, {165,0,0}, {6,2,1}, {65,0,0}, {49,0,0}, {4,3,1}, {7,0,0}, {7,5,2}, {10,6,1}, {81,0,0}, {7,6,4}, {105,0,0}, {73,0,0}, {11,6,4}, {134,0,0}, {47,0,0}, {16,10,1}, {6,5,4}, {15,6,4}, {8,6,1}, {38,0,0}, {18,9,6}, {16,0,0}, {203,0,0}, {12,5,2}, {19,0,0}, {7,6,1}, {73,0,0}, {93,0,0}, {19,18,13}, {31,0,0}, {14,11,6}, {11,6,1}, {27,0,0}, {9,5,2}, {9,0,0}, {1,0,0}, {11,3,2}, {200,0,0}, {191,0,0}, {9,8,4}, {9,0,0}, {16,15,7}, {121,0,0}, {104,0,0}, {15,9,6}, {138,0,0}, {9,6,5}, {9,6,4}, {105,0,0}, {17,16,6}, {81,0,0}, {94,0,0}, {4,3,1}, {83,0,0}, {219,0,0}, {11,6,3}, {7,0,0}, {10,5,3}, {17,0,0}, {76,0,0}, {16,5,2}, {78,0,0}, {155,0,0}, {11,6,5}, {27,0,0}, {5,4,2}, {8,5,4}, {3,0,0}, {15,14,6}, {156,0,0}, {23,0,0}, {13,6,3}, {9,0,0}, {8,7,3}, {69,0,0}, {10,0,0}, {8,5,2}, {26,0,0}, {67,0,0}, {14,7,4}, {21,0,0}, {12,10,2}, {33,0,0}, {79,0,0}, {15,11,2}, {32,0,0}, {39,0,0}, {13,6,2}, {167,0,0}, {6,4,1}, {97,0,0}, {47,0,0}, {11,6,2}, {42,0,0}, {10,7,3}, {10,5,4}, {1,0,0}, {4,3,2}, {161,0,0}, {8,6,2}, {7,5,3}, {94,0,0}, {195,0,0}, {10,5,4}, {9,0,0}, {13,10,4}, {8,6,1}, {16,0,0}, {8,3,1}, {122,0,0}, {8,2,1}, {13,7,4}, {10,5,3}, {16,4,3}, {193,0,0}, {135,0,0}, {19,16,9}, {39,0,0}, {10,8,7}, {10,9,4}, {153,0,0}, {7,6,5}, {73,0,0}, {34,0,0}, {11,9,6}, {71,0,0}, {11,4,2}, {14,7,3}, {163,0,0}, {11,6,1}, {153,0,0}, {28,0,0}, {15,7,6}, {77,0,0}, {67,0,0}, {10,5,2}, {12,8,1}, {10,6,4}, {13,0,0}, {146,0,0}, {13,4,3}, {25,0,0}, {23,22,16}, {12,9,7}, {237,0,0}, {13,7,6}, {85,0,0}, {130,0,0}, {14,13,3}, {88,0,0}, {7,5,2}, {11,6,1}, {35,0,0}, {10,4,3}, {93,0,0}, {9,6,4}, {13,6,3}, {86,0,0}, {19,0,0}, {9,2,1}, {273,0,0}, {14,12,9}, {7,6,1}, {30,0,0}, {9,5,2}, {201,0,0}, {215,0,0}, {6,4,3}, {105,0,0}, {10,7,5}, {165,0,0}, {105,0,0}, {19,13,6}, {31,0,0}, {127,0,0}, {10,4,2}, {81,0,0}, {19,10,4}, {45,0,0}, {211,0,0}, {19,10,3}, {200,0,0}, {295,0,0}, {9,8,5}, {9,0,0}, {12,6,5}, {297,0,0}, {68,0,0}, {11,6,5}, {133,0,0}, {251,0,0}, {13,8,4}, {223,0,0}, {6,5,2}, {7,4,2}, {307,0,0}, {9,2,1}, {101,0,0}, {39,0,0}, {14,10,4}, {217,0,0}, {14,9,1}, {6,5,1}, {16,0,0}, {14,3,2}, {11,0,0}, {119,0,0}, {11,3,2}, {11,6,5}, {11,8,4}, {249,0,0}, {5,0,0}, {13,3,1}, {37,0,0}, {3,0,0}, {14,0,0}, {93,0,0}, {10,8,7}, {33,0,0}, {88,0,0}, {7,5,4}, {38,0,0}, {55,0,0}, {15,4,2}, {11,0,0}, {12,11,4}, {21,0,0}, {107,0,0}, {11,9,8}, {33,0,0}, {10,7,2}, {18,7,3}, {147,0,0}, {5,4,2}, {153,0,0}, {15,0,0}, {11,6,5}, {28,0,0}, {11,7,4}, {6,3,1}, {31,0,0}, {8,4,3}, {15,5,3}, {66,0,0}, {23,16,9}, {11,9,3}, {171,0,0}, {11,6,1}, {209,0,0}, {4,3,1}, {197,0,0}, {13,0,0}, {19,14,6}, {14,0,0}, {79,0,0}, {13,6,2}, {299,0,0}, {15,8,2}, {169,0,0}, {177,0,0}, {23,10,2}, {267,0,0}, {215,0,0}, {15,10,1}, {75,0,0}, {16,4,2}, {37,0,0}, {12,7,1}, {8,3,2}, {17,0,0}, {12,11,8}, {15,8,5}, {15,0,0}, {4,3,1}, {13,12,4}, {92,0,0}, {5,4,3}, {41,0,0}, {23,0,0}, {7,4,1}, {183,0,0}, {16,7,1}, {165,0,0}, {150,0,0}, {9,6,4}, {9,0,0}, {231,0,0}, {16,10,4}, {207,0,0}, {9,6,5}, {5,0,0}, {180,0,0}, {4,3,2}, {58,0,0}, {147,0,0}, {8,6,2}, {343,0,0}, {8,7,2}, {11,6,1}, {44,0,0}, {13,8,6}, {5,0,0}, {347,0,0}, {18,16,8}, {135,0,0}, {9,8,3}, {85,0,0}, {90,0,0}, {13,11,1}, {258,0,0}, {351,0,0}, {10,6,4}, {19,0,0}, {7,6,1}, {309,0,0}, {18,0,0}, {13,10,3}, {158,0,0}, {19,0,0}, {12,10,1}, {45,0,0}, {7,6,1}, {233,0,0}, {98,0,0}, {11,6,5}, {3,0,0}, {83,0,0}, {16,14,9}, {6,5,3}, {9,7,4}, {22,19,9}, {168,0,0}, {19,17,4}, {120,0,0}, {14,5,2}, {17,15,6}, {7,0,0}, {10,8,6}, {185,0,0}, {93,0,0}, {15,14,7}, {29,0,0}, {375,0,0}, {10,8,3}, {13,0,0}, {17,16,2}, {329,0,0}, {68,0,0}, {13,9,6}, {92,0,0}, {12,10,3}, {7,6,3}, {17,10,3}, {5,2,1}, {9,6,1}, {30,0,0}, {9,7,3}, {253,0,0}, {143,0,0}, {7,4,1}, {9,4,1}, {12,10,4}, {53,0,0}, {25,0,0}, {9,7,1}, {217,0,0}, {15,13,9}, {14,9,2}, {75,0,0}, {8,7,2}, {21,0,0}, {7,0,0}, {14,3,2}, {15,0,0}, {159,0,0}, {12,10,8}, {29,0,0}, {10,3,1}, {21,0,0}, {333,0,0}, {11,8,2}, {52,0,0}, {119,0,0}, {16,9,7}, {123,0,0}, {15,11,2}, {17,0,0}, {9,0,0}, {11,6,4}, {38,0,0}, {255,0,0}, {12,10,7}, {189,0,0}, {4,3,1}, {17,10,7}, {49,0,0}, {13,5,2}, {149,0,0}, {15,0,0}, {14,7,5}, {10,9,2}, {8,6,5}, {61,0,0}, {54,0,0}, {11,5,1}, {144,0,0}, {47,0,0}, {11,10,7}, {105,0,0}, {2,0,0}, {105,0,0}, {136,0,0}, {11,4,1}, {253,0,0}, {111,0,0}, {13,10,5}, {159,0,0}, {10,7,1}, {7,5,3}, {29,0,0}, {19,10,3}, {119,0,0}, {207,0,0}, {17,15,4}, {35,0,0}, {14,0,0}, {349,0,0}, {6,3,2}, {21,10,6}, {1,0,0}, {75,0,0}, {9,5,2}, {145,0,0}, {11,7,6}, {301,0,0}, {378,0,0}, {13,3,1}, {352,0,0}, {12,7,4}, {12,8,1}, {149,0,0}, {6,5,4}, {12,9,8}, {11,0,0}, {15,7,5}, {78,0,0}, {99,0,0}, {17,16,12}, {173,0,0}, {8,7,1}, {13,9,8}, {147,0,0}, {19,18,10}, {127,0,0}, {183,0,0}, {12,4,1}, {31,0,0}, {11,8,6}, {173,0,0}, {12,0,0}, {7,5,3}, {113,0,0}, {207,0,0}, {18,15,5}, {1,0,0}, {13,7,6}, {21,0,0}, {35,0,0}, {12,7,2}, {117,0,0}, {123,0,0}, {12,10,2}, {143,0,0}, {14,4,1}, {15,9,7}, {204,0,0}, {7,5,1}, {91,0,0}, {4,2,1}, {8,6,3}, {183,0,0}, {12,10,7}, {77,0,0}, {36,0,0}, {14,9,6}, {221,0,0}, {7,6,5}, {16,14,13}, {31,0,0}, {16,15,7}, {365,0,0}, {403,0,0}, {10,3,2}, {11,4,3}, {31,0,0}, {10,9,4}, {177,0,0}, {16,6,1}, {22,6,5}, {417,0,0}, {15,13,12}, {217,0,0}, {207,0,0}, {7,5,4}, {10,7,1}, {11,6,1}, {45,0,0}, {24,0,0}, {12,11,9}, {77,0,0}, {21,20,13}, {9,6,5}, {189,0,0}, {8,3,2}, {13,12,10}, {260,0,0}, {16,9,7}, {168,0,0}, {131,0,0}, {7,6,3}, {305,0,0}, {10,9,6}, {13,9,4}, {143,0,0}, {12,9,3}, {18,0,0}, {15,8,5}, {20,9,6}, {103,0,0}, {15,4,2}, {201,0,0}, {36,0,0}, {9,5,2}, {31,0,0}, {11,7,2}, {6,2,1}, {7,0,0}, {13,6,4}, {9,8,7}, {19,0,0}, {17,10,6}, {15,0,0}, {9,3,1}, {178,0,0}, {8,7,6}, {12,6,5}, {177,0,0}, {230,0,0}, {24,9,3}, {222,0,0}, {3,0,0}, {16,13,12}, {121,0,0}, {10,4,2}, {161,0,0}, {39,0,0}, {17,15,13}, {62,0,0}, {223,0,0}, {15,12,2}, {65,0,0}, {12,6,3}, {101,0,0}, {59,0,0}, {5,4,3}, {17,0,0}, {5,3,2}, {13,8,3}, {10,9,7}, {12,8,2}, {5,4,3}, {75,0,0}, {19,17,8}, {55,0,0}, {99,0,0}, {10,7,4}, {115,0,0}, {9,8,6}, {385,0,0}, {186,0,0}, {15,6,3}, {9,4,1}, {12,10,5}, {10,8,1}, {135,0,0}, {5,2,1}, {317,0,0}, {7,0,0}, {19,6,1}, {294,0,0}, {35,0,0}, {13,12,6}, {119,0,0}, {98,0,0}, {93,0,0}, {68,0,0}, {21,15,3}, {108,0,0}, {75,0,0}, {12,6,5}, {411,0,0}, {12,7,2}, {13,7,2}, {21,0,0}, {15,10,8}, {412,0,0}, {439,0,0}, {10,7,6}, {41,0,0}, {13,9,6}, {8,5,2}, {10,0,0}, {15,7,2}, {141,0,0}, {159,0,0}, {13,12,10}, {291,0,0}, {10,9,1}, {105,0,0}, {24,0,0}, {11,2,1}, {198,0,0}, {27,0,0}, {6,3,1}, {439,0,0}, {10,3,1}, {49,0,0}, {168,0,0}, {13,11,9}, {463,0,0}, {10,9,3}, {13,9,8}, {15,8,3}, {18,16,8}, {15,14,11}, {7,0,0}, {19,9,8}, {12,6,3}, {7,4,3}, {15,14,5}, {8,6,3}, {10,9,7}, {361,0,0}, {230,0,0}, {15,9,6}, {24,0,0}, {407,0,0}, {16,7,2}, {189,0,0}, {62,0,0}, {189,0,0}, {112,0,0}, {22,21,10}, {91,0,0}, {79,0,0}, {12,10,5}, {23,0,0}, {7,6,1}, {57,0,0}, {139,0,0}, {24,15,6}, {14,0,0}, {83,0,0}, {16,9,1}, {35,0,0}, {9,7,4}, {117,0,0}, {65,0,0}, {21,9,6}, {21,0,0}, {195,0,0}, {23,11,10}, {327,0,0}, {17,14,3}, {417,0,0}, {13,0,0}, {15,8,6}, {107,0,0}, {19,10,6}, {18,15,3}, {59,0,0}, {12,10,4}, {9,7,5}, {283,0,0}, {13,9,6}, {62,0,0}, {427,0,0}, {14,7,3}, {8,7,4}, {15,8,3}, {105,0,0}, {27,0,0}, {7,3,1}, {103,0,0}, {551,0,0}, {10,6,1}, {6,4,1}, {11,6,4}, {129,0,0}, {9,0,0}, {9,4,2}, {277,0,0}, {31,0,0}, {13,12,5}, {141,0,0}, {12,7,3}, {357,0,0}, {7,2,1}, {11,9,7}, {227,0,0}, {131,0,0}, {7,6,3}, {23,0,0}, {20,17,3}, {13,4,1}, {90,0,0}, {15,3,2}, {241,0,0}, {75,0,0}, {13,6,1}, {307,0,0}, {8,7,3}, {245,0,0}, {66,0,0}, {15,11,2}, {365,0,0}, {18,16,11}, {11,10,1}, {19,0,0}, {8,6,1}, {189,0,0}, {133,0,0}, {12,7,2}, {114,0,0}, {27,0,0}, {6,5,1}, {15,5,2}, {17,14,5}, {133,0,0}, {476,0,0}, {11,9,3}, {16,0,0}, {375,0,0}, {15,8,6}, {25,0,0}, {17,11,6}, {77,0,0}, {87,0,0}, {5,3,2}, {134,0,0}, {171,0,0}, {13,8,4}, {75,0,0}, {8,3,1}, {233,0,0}, {196,0,0}, {9,8,7}, {173,0,0}, {15,14,12}, {13,6,5}, {281,0,0}, {9,8,2}, {405,0,0}, {114,0,0}, {15,9,6}, {171,0,0}, {287,0,0}, {8,4,2}, {43,0,0}, {4,2,1}, {513,0,0}, {273,0,0}, {11,10,6}, {118,0,0}, {243,0,0}, {14,7,1}, {203,0,0}, {9,5,2}, {257,0,0}, {302,0,0}, {27,25,9}, {393,0,0}, {91,0,0}, {12,10,6}, {413,0,0}, {15,14,9}, {18,16,1}, {255,0,0}, {12,9,7}, {234,0,0}, {167,0,0}, {16,13,10}, {27,0,0}, {15,6,2}, {433,0,0}, {105,0,0}, {25,10,2}, {151,0,0}, {427,0,0}, {13,9,8}, {49,0,0}, {10,6,4}, {153,0,0}, {4,0,0}, {17,7,5}, {54,0,0}, {203,0,0}, {16,15,1}, {16,14,7}, {13,6,1}, {25,0,0}, {14,0,0}, {15,5,3}, {187,0,0}, {15,13,10}, {13,10,5}, {97,0,0}, {11,10,9}, {19,10,4}, {589,0,0}, {31,30,2}, {289,0,0}, {9,6,4}, {11,8,6}, {21,0,0}, {7,4,1}, {7,4,2}, {77,0,0}, {5,3,2}, {119,0,0}, {7,0,0}, {9,5,2}, {345,0,0}, {17,10,8}, {333,0,0}, {17,0,0}, {16,9,7}, {168,0,0}, {15,13,4}, {11,10,1}, {217,0,0}, {18,11,10}, {189,0,0}, {216,0,0}, {12,7,5}, {229,0,0}, {231,0,0}, {12,9,3}, {223,0,0}, {10,9,1}, {153,0,0}, {470,0,0}, {23,16,6}, {99,0,0}, {10,4,3}, {9,8,4}, {12,10,1}, {14,9,6}, {201,0,0}, {38,0,0}, {15,14,2}, {198,0,0}, {399,0,0}, {14,11,5}, {75,0,0}, {11,10,1}, {77,0,0}, {16,12,8}, {20,17,15}, {326,0,0}, {39,0,0}, {14,12,9}, {495,0,0}, {8,3,2}, {333,0,0}, {476,0,0}, {15,14,2}, {164,0,0}, {19,0,0}, {12,4,2}, {8,6,3}, {13,12,3}, {12,11,5}, {129,0,0}, {12,9,3}, {52,0,0}, {10,8,3}, {17,16,2}, {337,0,0}, {12,9,3}, {397,0,0}, {277,0,0}, {21,11,3}, {73,0,0}, {11,6,1}, {7,5,4}, {95,0,0}, {11,3,2}, {617,0,0}, {392,0,0}, {8,3,2}, {75,0,0}, {315,0,0}, {15,6,4}, {125,0,0}, {6,5,2}, {15,9,7}, {348,0,0}, {15,6,1}, {553,0,0}, {6,3,2}, {10,9,7}, {553,0,0}, {14,10,4}, {237,0,0}, {39,0,0}, {17,14,6}, {371,0,0}, {255,0,0}, {8,4,1}, {131,0,0}, {14,6,1}, {117,0,0}, {98,0,0}, {5,3,2}, {56,0,0}, {655,0,0}, {9,5,2}, {239,0,0}, {11,8,4}, {1,0,0}, {134,0,0}, {15,9,5}, {88,0,0}, {10,5,3}, {10,9,4}, {181,0,0}, {15,11,2}, {609,0,0}, {52,0,0}, {19,18,10}, {100,0,0}, {7,6,3}, {15,8,2}, {183,0,0}, {18,7,6}, {10,9,2}, {130,0,0}, {11,5,1}, {12,0,0}, {219,0,0}, {13,10,7}, {11,0,0}, {19,9,4}, {129,0,0}, {3,0,0}, {17,15,5}, {300,0,0}, {17,13,9}, {14,6,5}, {97,0,0}, {13,8,3}, {601,0,0}, {55,0,0}, {8,3,1}, {92,0,0}, {127,0,0}, {12,11,2}, {81,0,0}, {15,10,8}, {13,2,1}, {47,0,0}, {14,13,6}, {194,0,0}, {383,0,0}, {25,14,11}, {125,0,0}, {20,19,16}, {429,0,0}, {282,0,0}, {10,9,6}, {342,0,0}, {5,3,2}, {15,9,4}, {33,0,0}, {9,4,2}, {49,0,0}, {15,0,0}, {11,6,2}, {28,0,0}, {103,0,0}, {18,17,8}, {27,0,0}, {11,6,5}, {33,0,0}, {17,0,0}, {11,10,6}, {387,0,0}, {363,0,0}, {15,10,9}, {83,0,0}, {7,6,4}, {357,0,0}, {13,12,4}, {14,13,7}, {322,0,0}, {395,0,0}, {16,5,1}, {595,0,0}, {13,10,3}, {421,0,0}, {195,0,0}, {11,3,2}, {13,0,0}, {16,12,3}, {14,3,1}, {315,0,0}, {26,10,5}, {297,0,0}, {52,0,0}, {9,4,2}, {314,0,0}, {243,0,0}, {16,14,9}, {185,0,0}, {12,5,3}, {13,5,2}, {575,0,0}, {12,9,3}, {39,0,0}, {311,0,0}, {13,5,2}, {181,0,0}, {20,18,14}, {49,0,0}, {25,0,0}, {11,4,1}, {77,0,0}, {17,11,10}, {15,14,8}, {21,0,0}, {17,10,5}, {69,0,0}, {49,0,0}, {11,10,2}, {32,0,0}, {411,0,0}, {21,16,3}, {11,7,4}, {22,10,3}, {85,0,0}, {140,0,0}, {9,8,6}, {252,0,0}, {279,0,0}, {9,5,2}, {307,0,0}, {17,10,4}, {13,12,9}, {94,0,0}, {13,11,4}, {49,0,0}, {17,11,10}, {16,12,5}, {25,0,0}, {6,5,2}, {12,5,1}, {80,0,0}, {8,3,2}, {246,0,0}, {11,5,2}, {11,10,2}, {599,0,0}, {18,12,10}, {189,0,0}, {278,0,0}, {10,9,3}, {399,0,0}, {299,0,0}, {13,10,6}, {277,0,0}, {13,10,6}, {69,0,0}, {220,0,0}, {13,10,3}, {229,0,0}, {18,11,10}, {16,15,1}, {27,0,0}, {18,9,3}, {473,0,0}, {373,0,0}, {18,17,7}, {60,0,0}, {207,0,0}, {13,9,8}, {22,20,13}, {25,18,7}, {225,0,0}, {404,0,0}, {21,6,2}, {46,0,0}, {6,2,1}, {17,12,6}, {75,0,0}, {4,2,1}, {365,0,0}, {445,0,0}, {11,7,1}, {44,0,0}, {10,8,5}, {12,5,2}, {63,0,0}, {17,4,2}, {189,0,0}, {557,0,0}, {19,12,2}, {252,0,0}, {99,0,0}, {10,8,5}, {65,0,0}, {14,9,3}, {9,0,0}, {119,0,0}, {8,5,2}, {339,0,0}, {95,0,0}, {12,9,7}, {7,0,0}, {13,10,2}, {77,0,0}, {127,0,0}, {21,10,7}, {319,0,0}, {667,0,0}, {17,10,3}, {501,0,0}, {18,12,9}, {9,8,5}, {17,0,0}, {20,9,2}, {341,0,0}, {731,0,0}, {7,6,5}, {647,0,0}, {10,4,2}, {121,0,0}, {20,0,0}, {21,19,13}, {574,0,0}, {399,0,0}, {15,10,7}, {85,0,0}, {16,8,3}, {169,0,0}, {15,0,0}, {12,7,5}, {568,0,0}, {10,7,1}, {18,2,1}, {3,0,0}, {14,3,2}, {13,7,3}, {643,0,0}, {14,11,1}, {548,0,0}, {783,0,0}, {14,11,1}, {317,0,0}, {7,6,4}, {153,0,0}, {87,0,0}, {15,13,1}, {231,0,0}, {11,5,3}, {18,13,7}, {771,0,0}, {30,20,11}, {15,6,3}, {103,0,0}, {13,4,3}, {182,0,0}, {211,0,0}, {17,6,1}, {27,0,0}, {13,12,10}, {15,14,10}, {17,0,0}, {13,11,5}, {69,0,0}, {11,5,1}, {18,6,1}, {603,0,0}, {10,4,2}, {741,0,0}, {668,0,0}, {17,15,3}, {147,0,0}, {227,0,0}, {15,10,9}, {37,0,0}, {16,6,1}, {173,0,0}, {427,0,0}, {7,5,1}, {287,0,0}, {231,0,0}, {20,15,10}, {18,9,1}, {14,12,5}, {16,5,1}, {310,0,0}, {18,13,1}, {434,0,0}, {579,0,0}, {18,13,8}, {45,0,0}, {12,8,3}, {16,9,5}, {53,0,0}, {19,15,10}, {16,0,0}, {17,6,5}, {17,10,1}, {37,0,0}, {17,10,9}, {21,13,7}, {99,0,0}, {17,9,6}, {176,0,0}, {271,0,0}, {18,17,13}, {459,0,0}, {21,17,10}, {6,5,2}, {202,0,0}, {5,4,3}, {90,0,0}, {755,0,0}, {15,7,2}, {363,0,0}, {8,4,2}, {129,0,0}, {20,0,0}, {11,6,2}, {135,0,0}, {15,8,7}, {14,13,2}, {10,4,3}, {24,13,10}, {19,14,11}, {31,0,0}, {15,8,6}, {758,0,0}, {16,11,5}, {16,5,1}, {359,0,0}, {23,18,17}, {501,0,0}, {29,0,0}, {15,6,3}, {201,0,0}, {459,0,0}, {12,10,7}, {225,0,0}, {22,17,13}, {24,22,5}, {161,0,0}, {14,11,3}, {52,0,0}, {19,17,6}, {21,14,12}, {93,0,0}, {13,10,3}, {201,0,0}, {178,0,0}, {15,12,5}, {250,0,0}, {7,6,4}, {17,13,6}, {221,0,0}, {13,11,8}, {17,14,9}, {113,0,0}, {17,14,10}, {300,0,0}, {39,0,0}, {18,13,3}, {261,0,0}, {15,14,8}, {753,0,0}, {8,4,3}, {11,10,5}, {94,0,0}, {15,13,1}, {10,4,2}, {14,11,10}, {8,6,2}, {461,0,0}, {418,0,0}, {19,14,6}, {403,0,0}, {267,0,0}, {10,9,2}, {259,0,0}, {20,4,3}, {869,0,0}, {173,0,0}, {19,18,2}, {369,0,0}, {255,0,0}, {22,12,9}, {567,0,0}, {20,11,7}, {457,0,0}, {482,0,0}, {6,3,2}, {775,0,0}, {19,17,6}, {6,4,3}, {99,0,0}, {15,14,8}, {6,5,2}, {165,0,0}, {8,3,2}, {13,12,10}, {25,21,17}, {17,14,9}, {105,0,0}, {17,15,14}, {10,3,2}, {250,0,0}, {25,6,5}, {327,0,0}, {279,0,0}, {13,6,5}, {371,0,0}, {15,9,4}, {117,0,0}, {486,0,0}, {10,9,3}, {217,0,0}, {635,0,0}, {30,27,17}, {457,0,0}, {16,6,2}, {57,0,0}, {439,0,0}, {23,21,6}, {214,0,0}, {20,13,6}, {20,16,1}, {819,0,0}, {15,11,8}, {593,0,0}, {190,0,0}, {17,14,3}, {114,0,0}, {21,18,3}, {10,5,2}, {12,9,5}, {8,6,3}, {69,0,0}, {312,0,0}, {22,5,2}, {502,0,0}, {843,0,0}, {15,10,3}, {747,0,0}, {6,5,2}, {101,0,0}, {123,0,0}, {19,16,9}, {521,0,0}, {171,0,0}, {16,7,2}, {12,6,5}, {22,21,20}, {545,0,0}, {163,0,0}, {23,18,1}, {479,0,0}, {495,0,0}, {13,6,5}, {11,0,0}, {17,5,2}, {18,8,1}, {684,0,0}, {7,5,1}, {9,0,0}, {18,11,3}, {22,20,13}, {273,0,0}, {4,3,2}, {381,0,0}, {51,0,0}, {18,13,7}, {518,0,0}, {9,5,1}, {14,12,3}, {243,0,0}, {21,17,2}, {53,0,0}, {836,0,0}, {21,10,2}, {66,0,0}, {12,10,7}, {13,9,8}, {339,0,0}, {16,11,5}, {901,0,0}, {180,0,0}, {16,13,3}, {49,0,0}, {6,3,2}, {15,4,1}, {16,13,6}, {18,15,12}, {885,0,0}, {39,0,0}, {11,9,4}, {688,0,0}, {16,15,7}, {13,10,6}, {13,0,0}, {25,23,12}, {149,0,0}, {260,0,0}, {11,9,1}, {53,0,0}, {11,0,0}, {12,4,2}, {9,7,5}, {11,8,1}, {121,0,0}, {261,0,0}, {10,5,2}, {199,0,0}, {20,4,3}, {17,9,2}, {13,9,4}, {12,8,7}, {253,0,0}, {174,0,0}, {15,4,2}, {370,0,0}, {9,6,1}, {16,10,9}, {669,0,0}, {20,10,9}, {833,0,0}, {353,0,0}, {17,13,2}, {29,0,0}, {371,0,0}, {9,8,5}, {8,7,1}, {19,8,7}, {12,11,10}, {873,0,0}, {26,11,2}, {12,9,1}, {10,7,2}, {13,6,1}, {235,0,0}, {26,24,19}, {733,0,0}, {778,0,0}, {12,11,1}, {344,0,0}, {931,0,0}, {16,6,4}, {945,0,0}, {21,19,14}, {18,13,11}, {67,0,0}, {20,15,10}, {462,0,0}, {14,5,1}, {10,9,6}, {18,11,10}, {16,9,7}, {477,0,0}, {105,0,0}, {11,3,2}, {468,0,0}, {23,16,15}, {16,15,6}, {327,0,0}, {23,10,4}, {357,0,0}, {25,0,0}, {17,16,7}, {31,0,0}, {7,5,2}, {16,7,6}, {277,0,0}, {14,13,6}, {413,0,0}, {103,0,0}, {15,10,1}, {231,0,0}, {747,0,0}, {5,2,1}, {113,0,0}, {20,10,7}, {15,9,6}, {11,0,0}, {27,22,18}, {91,0,0}, {51,0,0}, {18,13,12}, {603,0,0}, {10,7,3}, {9,0,0}, {121,0,0}, {15,14,6}, {17,0,0}, {16,11,2}, {23,15,6}, {279,0,0}, {16,12,6}, {89,0,0}, {371,0,0}, {17,15,2}, {771,0,0}, {99,0,0}, {7,6,3}, {21,0,0}, {10,7,5}, {801,0,0}, {26,0,0}, {25,19,14}, {175,0,0}, {10,7,2}, {20,5,4}, {12,11,1}, {22,5,1}, {165,0,0}, {841,0,0}, {25,19,17}, {238,0,0}, {11,8,6}, {22,21,4}, {33,0,0}, {8,7,6}, {14,9,2}, {113,0,0}, {13,11,5}, {311,0,0}, {891,0,0}, {20,16,14}, {555,0,0}, {23,14,8}, {133,0,0}, {546,0,0}, {6,3,2}, {103,0,0}, {15,0,0}, {10,7,3}, {307,0,0}, {14,10,1}, {15,12,2}, {367,0,0}, {13,10,6}, {169,0,0}, {22,21,11}, {12,10,8}, {441,0,0}, {17,12,7}, {917,0,0}, {205,0,0}, {26,23,13}, {54,0,0}, {459,0,0}, {17,15,4}, {19,15,4}, {5,4,2}, {9,7,6}, {42,0,0}, {21,15,7}, {330,0,0}, {20,7,3}, {20,7,2}, {81,0,0}, {19,14,1}, {349,0,0}, {165,0,0}, {40,35,9}, {274,0,0}, {475,0,0}, {11,10,3}, {93,0,0}, {12,7,4}, {13,12,2}, {386,0,0}, {7,6,2}, {881,0,0}, {143,0,0}, {9,8,4}, {71,0,0}, {19,18,3}, {16,11,6}, {155,0,0}, {7,2,1}, {735,0,0}, {16,8,7}, {9,7,4}, {45,0,0}, {7,6,4}, {12,11,3}, {3,0,0}, {19,14,13} }; static long FindTrinom(long n) { if (n < 2) Error("tri--bad n"); long k; for (k = 1; k <= n/2; k++) if (IterIrredTest(1 + GF2X(k,1) + GF2X(n,1))) return k; return 0; } static long FindPent(long n, long& kk2, long& kk1) { if (n < 4) Error("pent--bad n"); long k1, k2, k3; for (k3 = 3; k3 < n; k3++) for (k2 = 2; k2 < k3; k2++) for (k1 = 1; k1 < k2; k1++) if (IterIrredTest(1+GF2X(k1,1)+GF2X(k2,1)+GF2X(k3,1)+GF2X(n,1))) { kk2 = k2; kk1 = k1; return k3; } return 0; } void BuildSparseIrred(GF2X& f, long n) { if (n <= 0) Error("SparseIrred: n <= 0"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildSparseIrred"); if (n == 1) { SetX(f); return; } if (n <= 2048) { if (GF2X_irred_tab[n][1] == 0) { clear(f); SetCoeff(f, n); SetCoeff(f, GF2X_irred_tab[n][0]); SetCoeff(f, 0); } else { clear(f); SetCoeff(f, n); SetCoeff(f, GF2X_irred_tab[n][0]); SetCoeff(f, GF2X_irred_tab[n][1]); SetCoeff(f, GF2X_irred_tab[n][2]); SetCoeff(f, 0); } return; } long k3, k2, k1; k3 = FindTrinom(n); if (k3) { clear(f); SetCoeff(f, n); SetCoeff(f, k3); SetCoeff(f, 0); return; } k3 = FindPent(n, k2, k1); if (k3) { clear(f); SetCoeff(f, n); SetCoeff(f, k3); SetCoeff(f, k2); SetCoeff(f, k1); SetCoeff(f, 0); return; } // the following is probably of only theoretical value... // it is reasonable to conjecture that for all n >= 2, // there is either an irreducible trinomial or pentanomial // of degree n. BuildIrred(f, n); } NTL_END_IMPL ntl-6.2.1/src/GF2XTest.c000644 000765 000024 00000003411 12377144457 015134 0ustar00shoupstaff000000 000000 #include NTL_CLIENT struct wd { int amt; wd(int x) { amt = x; } }; #define WD(x,y) wd(x) << (y) ostream& operator<<(ostream& s, const wd& w) { s.width(w.amt); return s; } int main() { long n; GF2X a, b, c, c1, ss, ss1, tt, tt1; double t; long iter, i; cout << WD(12,"n") << WD(12,"OldGCD") << WD(12,"GCD") << WD(12,"OldXGCD") << WD(12, "XGCD") << "\n"; cout.precision(3); cout.setf(ios::scientific); for (n = 32; n <= (1L << 18); n = n << 3) { random(a, n); random(b, n); OldGCD(c, a, b); GCD(c1, a, b); OldXGCD(c, ss, tt, a, b); XGCD(c1, ss1, tt1, a, b); if (c1 != c || ss1 != ss || tt1 != tt) { cerr << "**** GF2XTest FAILED!\n"; return 1; } cout << WD(12,n); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) OldGCD(c, a, b); t = GetTime()-t; } while (t < 0.5); cout << WD(12,t/iter); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) GCD(c, a, b); t = GetTime()-t; } while (t < 0.5); cout << WD(12,t/iter); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) OldXGCD(c, ss, tt, a, b); t = GetTime()-t; } while (t < 0.5); cout << WD(12,t/iter); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) XGCD(c, ss, tt, a, b); t = GetTime()-t; } while (t < 0.5); cout << WD(12,t/iter); cout << "\n"; } return 0; } ntl-6.2.1/src/GF2XTimeTest.c000644 000765 000024 00000004260 12377144457 015756 0ustar00shoupstaff000000 000000 #include #include NTL_CLIENT double clean_data(double *t) { double x, y, z; long i, ix, iy, n; x = t[0]; ix = 0; y = t[0]; iy = 0; for (i = 1; i < 5; i++) { if (t[i] < x) { x = t[i]; ix = i; } if (t[i] > y) { y = t[i]; iy = i; } } z = 0; n = 0; for (i = 0; i < 5; i++) { if (i != ix && i != iy) z+= t[i], n++; } z = z/n; return z; } void print_flag() { #ifdef NTL_GF2X_ALTCODE printf("NTL_GF2X_ALTCODE "); #endif #ifdef NTL_GF2X_ALTCODE1 printf("NTL_GF2X_ALTCODE1 "); #endif #ifdef NTL_GF2X_NOINLINE printf("NTL_GF2X_NOINLINE "); #endif printf("\n"); } int main() { long n, i, j, iter, s, k; double t; for (i = 0; i < 10000; i++) { GF2X a, b, c, d; long da = RandomBnd(5*NTL_BITS_PER_LONG); long db = RandomBnd(5*NTL_BITS_PER_LONG); long dc = RandomBnd(5*NTL_BITS_PER_LONG); long dd = RandomBnd(5*NTL_BITS_PER_LONG); random(a, da); random(b, db); random(c, dc); random(d, dd); if ((a + b)*(c + d) != c*a + d*a + c*b + d*b) { printf("999999999999999 "); print_flag(); return 0; } } n = 16; s = 56; GF2X *a = new GF2X[s]; GF2X *b = new GF2X[s]; GF2X c; for (k = 0; k < s; k++) { random(a[k], (n + (k % 7))*NTL_BITS_PER_LONG); random(b[k], (n + (k % 8))*NTL_BITS_PER_LONG); } for (k = 0; k < s; k++) mul(c, a[k], b[k]); iter = 1; do { t = GetTime(); for (i = 0; i < iter; i++) { for (j = 0; j < 1; j++) for (k = 0; k < s; k++) mul(c, a[k], b[k]); } t = GetTime() - t; iter = 2*iter; } while(t < 1); iter = iter/2; iter = long((2/t)*iter) + 1; double tvec[5]; long w; for (w = 0; w < 5; w++) { t = GetTime(); for (i = 0; i < iter; i++) { for (j = 0; j < 1; j++) for (k = 0; k < s; k++) mul(c, a[k], b[k]); } t = GetTime() - t; tvec[w] = t; } t = clean_data(tvec); t = floor((t/iter)*1e14); if (t < 0 || t >= 1e15) printf("999999999999999 "); else printf("%015.0f ", t); printf(" [%ld] ", iter); print_flag(); return 0; } ntl-6.2.1/src/GF2XVec.c000644 000765 000024 00000002650 12377144456 014735 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void GF2XVec::SetSize(long n, long d) { if (n < 0 || d <= 0) Error("bad args to GF2XVec::SetSize()"); if (v) Error("illegal GF2XVec initialization"); len = n; bsize = d; if (n == 0) return; v = (GF2X*) NTL_MALLOC(n, sizeof(GF2X), 0); if (!v) Error("out of memory in GF2XVec::SetSize()"); long i = 0; long m; long j; while (i < n) { m = WV_BlockConstructAlloc(v[i].xrep, d, n-i); for (j = 1; j < m; j++) WV_BlockConstructSet(v[i].xrep, v[i+j].xrep, j); i += m; } } void GF2XVec::kill() { long n = len; len = 0; bsize = 0; if (n == 0) return; long i = 0; long m; while (i < n) { m = WV_BlockDestroy(v[i].xrep); i += m; } free(v); v = 0; } GF2XVec& GF2XVec::operator=(const GF2XVec& a) { if (this == &a) return *this; kill(); SetSize(a.len, a.bsize); long i; for (i = 0; i < a.len; i++) v[i] = (a.v)[i]; return *this; } GF2XVec::GF2XVec(const GF2XVec& a) { v = 0; len = 0; bsize = 0; SetSize(a.len, a.bsize); long i; for (i = 0; i < a.len; i++) v[i] = (a.v)[i]; } void GF2XVec::swap_impl(GF2XVec& x, GF2XVec& y) { GF2X* t1; long t2; t1 = x.v; x.v = y.v; y.v = t1; t2 = x.len; x.len = y.len; y.len = t2; t2 = x.bsize; x.bsize = y.bsize; y.bsize = t2; } NTL_END_IMPL ntl-6.2.1/src/G_LLL_FP.c000644 000765 000024 00000101671 12377144456 015052 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL static inline void CheckFinite(double *p) { if (!IsFinite(p)) Error("G_LLL_FP: numbers too big...use G_LLL_XD"); } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } #define TR_BND (NTL_FDOUBLE_PRECISION/2.0) // Just to be safe!! static double max_abs(double *v, long n) { long i; double res, t; res = 0; for (i = 1; i <= n; i++) { t = fabs(v[i]); if (t > res) res = t; } return res; } static void RowTransformStart(double *a, long *in_a, long& in_float, long n) { long i; long inf = 1; for (i = 1; i <= n; i++) { in_a[i] = (a[i] < TR_BND && a[i] > -TR_BND); inf = inf & in_a[i]; } in_float = inf; } static void RowTransformFinish(vec_ZZ& A, double *a, long *in_a) { long n = A.length(); long i; for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); } else { conv(a[i], A(i)); CheckFinite(&a[i]); } } } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1, double *a, double *b, long *in_a, double& max_a, double max_b, long& in_float) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; double mu; conv(mu, MU1); CheckFinite(&mu); long n = A.length(); long i; if (in_float) { double mu_abs = fabs(mu); if (mu_abs > 0 && max_b > 0 && (mu_abs >= TR_BND || max_b >= TR_BND)) { in_float = 0; } else { max_a += mu_abs*max_b; if (max_a >= TR_BND) in_float = 0; } } if (in_float) { if (mu == 1) { for (i = 1; i <= n; i++) a[i] -= b[i]; return; } if (mu == -1) { for (i = 1; i <= n; i++) a[i] += b[i]; return; } if (mu == 0) return; for (i = 1; i <= n; i++) a[i] -= mu*b[i]; return; } MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < TR_BND && b[i] > -TR_BND) { a[i] -= b[i]; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } sub(A(i), A(i), B(i)); } } return; } if (MU == -1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < TR_BND && b[i] > -TR_BND) { a[i] += b[i]; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } add(A(i), A(i), B(i)); } } return; } if (MU == 0) return; double b_bnd = fabs(TR_BND/mu) - 1; if (b_bnd < 0) b_bnd = 0; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < b_bnd && b[i] > -b_bnd) { a[i] -= b[i]*mu; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } MulSubFrom(A(i), B(i), mu1); } } } } else { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } class GivensCache_FP { public: GivensCache_FP(long m, long n); ~GivensCache_FP(); void flush(); void selective_flush(long l); void swap(long l); void swap(); void touch(); void incr(); long sz; double **buf; long *bl; long *bv; long bp; }; GivensCache_FP::GivensCache_FP(long m, long n) { sz = min(m, n)/10; if (sz < 2) sz = 2; else if (sz > 20) sz = 20; typedef double *doubleptr; long i; buf = NTL_NEW_OP doubleptr[sz]; if (!buf) Error("out of memory"); for (i = 0; i < sz; i++) if (!(buf[i] = NTL_NEW_OP double[n+1])) Error("out of memory"); bl = NTL_NEW_OP long[sz]; if (!bl) Error("out of memory"); for (i = 0; i < sz; i++) bl[0] = 0; bv = NTL_NEW_OP long[sz]; if (!bv) Error("out of memory"); for (i = 0; i < sz; i++) bv[0] = 0; bp = 0; } GivensCache_FP::~GivensCache_FP() { long i; for (i = 0; i < sz; i++) delete [] buf[i]; delete [] buf; delete [] bl; delete [] bv; } void GivensCache_FP::flush() { long i; for (i = 0; i < sz; i++) bl[i] = 0; } void GivensCache_FP::selective_flush(long l) { long i; for (i = 0; i < sz; i++) if (bl[i] && bv[i] >= l) bl[i] = 0; } void GivensCache_FP::swap(long l) { long k = bl[bp]; long i; i = 0; while (i < sz && bl[i] != l) i++; if (i < sz) { bl[bp] = l; bl[i] = k; } else bl[bp] = l; selective_flush(l); } void GivensCache_FP::swap() { swap(bl[bp] - 1); } void GivensCache_FP::touch() { long k = bl[bp]; bl[bp] = 0; selective_flush(k); } void GivensCache_FP::incr() { long k = bl[bp]; long k1 = k+1; long i; i = 0; while (i < sz && bl[i] != k1) i++; if (i < sz) { bp = i; return; } i = 0; while (i < sz && bl[i] != 0) i++; if (i < sz) { bp = i; return; } long max_val = 0; long max_index = 0; for (i = 0; i < sz; i++) { long t = labs(bl[i]-k1); if (t > max_val) { max_val = t; max_index = i; } } bp = max_index; bl[max_index] = 0; } static void GivensComputeGS(double **B1, double **mu, double **aux, long k, long n, GivensCache_FP& cache) { long i, j; double c, s, a, b, t; double *p = mu[k]; double *pp = cache.buf[cache.bp]; if (!cache.bl[cache.bp]) { for (j = 1; j <= n; j++) pp[j] = B1[k][j]; long backoff; backoff = k/4; if (backoff < 2) backoff = 2; else if (backoff > cache.sz + 2) backoff = cache.sz + 2; long ub = k-(backoff-1); for (i = 1; i < ub; i++) { double *cptr = mu[i]; double *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*pp[j-1] - s*pp[j]; b = s*pp[j-1] + c*pp[j]; pp[j-1] = a; pp[j] = b; } pp[i] = pp[i]/mu[i][i]; } cache.bl[cache.bp] = k; cache.bv[cache.bp] = k-backoff; } for (j = 1; j <= n; j++) p[j] = pp[j]; for (i = max(cache.bv[cache.bp]+1, 1); i < k; i++) { double *cptr = mu[i]; double *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*p[j-1] - s*p[j]; b = s*p[j-1] + c*p[j]; p[j-1] = a; p[j] = b; } p[i] = p[i]/mu[i][i]; } for (j = n; j > k; j--) { a = p[j-1]; b = p[j]; if (b == 0) { c = 1; s = 0; } else if (fabs(b) > fabs(a)) { t = -a/b; s = 1/sqrt(1 + t*t); c = s*t; } else { t = -b/a; c = 1/sqrt(1 + t*t); s = c*t; } p[j-1] = c*a - s*b; p[j] = c; aux[k][j] = s; } if (k > n+1) Error("G_LLL_FP: internal error"); if (k > n) p[k] = 0; for (i = 1; i <= k; i++) CheckFinite(&p[i]); } NTL_THREAD_LOCAL static double red_fudge = 0; NTL_THREAD_LOCAL static long log_red = 0; NTL_THREAD_LOCAL static long verbose = 0; NTL_THREAD_LOCAL static unsigned long NumSwaps = 0; NTL_THREAD_LOCAL static double StartTime = 0; NTL_THREAD_LOCAL static double LastTime = 0; static void G_LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- G_LLL_FP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static void init_red_fudge() { long i; log_red = long(0.50*NTL_DOUBLE_PRECISION); red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { red_fudge = red_fudge * 2; log_red--; cerr << "G_LLL_FP: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) Error("G_LLL_FP: too much loss of precision...stop!"); } #if 0 static void print_mus(double **mu, long k) { long i; for (i = k-1; i >= 1; i--) cerr << mu[k][i] << " "; cerr << "\n"; } #endif static long ll_G_LLL_FP(mat_ZZ& B, mat_ZZ* U, double delta, long deep, LLLCheckFct check, double **B1, double **mu, double **aux, long m, long init_k, long &quit, GivensCache_FP& cache) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; double mu1; double t1; ZZ T1; double *tp; double half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long in_vec_mem; in_vec_mem.SetLength(n+1); long *in_vec = in_vec_mem.elts(); double *max_b; max_b = NTL_NEW_OP double [m+1]; if (!max_b) Error("out of memory in lll_G_LLL_FP"); for (i = 1; i <= m; i++) max_b[i] = max_abs(B1[i], n); long in_float; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; long swap_cnt = 0; cache.flush(); while (k <= m) { if (k > max_k) { max_k = k; swap_cnt = 0; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_LLLStatus(max_k, tt, m, B); } GivensComputeGS(B1, mu, aux, k, n, cache); if (swap_cnt > 200000) { cerr << "G_LLL_FP: swap loop?\n"; swap_cnt = 0; } counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; long sz=0, new_sz; do { // size reduction counter++; if ((counter & 127) == 0) { new_sz = 0; for (j = 1; j <= n; j++) new_sz += NumBits(B(k,j)); if ((counter >> 7) == 1 || new_sz < sz) { sz = new_sz; } else { cerr << "G_LLL_FP: warning--infinite loop? (" << k << ")\n"; } } Fc1 = 0; for (j = k-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); Fc1 = 1; RowTransformStart(B1[k], in_vec, in_float, n); } mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-0.5); else mu1 = floor(mu1+0.5); double *mu_k = mu[k]; double *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) mu_k[i] -= mu1*mu_j[i]; } mu_k[j] -= mu1; conv(MU, mu1); RowTransform(B(k), B(j), MU, B1[k], B1[j], in_vec, max_b[k], max_b[j], in_float); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { RowTransformFinish(B(k), B1[k], in_vec); max_b[k] = max_abs(B1[k], n); cache.touch(); GivensComputeGS(B1, mu, aux, k, n, cache); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(B(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; t1 = max_b[i]; max_b[i] = max_b[i+1]; max_b[i+1] = t1; if (U) swap((*U)(i), (*U)(i+1)); } cache.flush(); m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions Error("sorry...deep insertions not implemented"); } // end deep insertions // test G_LLL reduction condition if (k > 1 && sqrt(delta - mu[k][k-1]*mu[k][k-1])*fabs(mu[k-1][k-1]) > fabs(mu[k][k])) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; t1 = max_b[k]; max_b[k] = max_b[k-1]; max_b[k-1] = t1; if (U) swap((*U)(k), (*U)(k-1)); cache.swap(); k--; NumSwaps++; swap_cnt++; // cout << "-\n"; } else { cache.incr(); k++; // cout << "+\n"; } } if (verbose) { G_LLLStatus(m+1, GetTime(), m, B); } delete [] max_b; return m; } static long G_LLL_FP(mat_ZZ& B, mat_ZZ* U, double delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; ZZ MU; ZZ T1; init_red_fudge(); if (U) ident(*U, m); double **B1; // approximates B typedef double *doubleptr; B1 = NTL_NEW_OP doubleptr[m+1]; if (!B1) Error("G_LLL_FP: out of memory"); for (i = 1; i <= m; i++) { B1[i] = NTL_NEW_OP double[n+1]; if (!B1[i]) Error("G_LLL_FP: out of memory"); } double **mu; mu = NTL_NEW_OP doubleptr[m+1]; if (!mu) Error("G_LLL_FP: out of memory"); for (i = 1; i <= m; i++) { mu[i] = NTL_NEW_OP double[n+2]; if (!mu[i]) Error("G_LLL_FP: out of memory"); } double **aux; aux = NTL_NEW_OP doubleptr[m+1]; if (!aux) Error("G_LLL_FP: out of memory"); for (i = 1; i <= m; i++) { aux[i] = NTL_NEW_OP double[n+1]; if (!aux[i]) Error("G_LLL_FP: out of memory"); } for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_FP cache(m, n); new_m = ll_G_LLL_FP(B, U, delta, deep, check, B1, mu, aux, m, 1, quit, cache); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } // clean-up for (i = 1; i <= m+dep; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m+dep; i++) { delete [] mu[i]; } delete [] mu; for (i = 1; i <= m+dep; i++) { delete [] aux[i]; } delete [] aux; return m; } long G_LLL_FP(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_LLL_FP: bad delta"); if (deep < 0) Error("G_LLL_FP: bad deep"); return G_LLL_FP(B, 0, delta, deep, check); } long G_LLL_FP(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_LLL_FP: bad delta"); if (deep < 0) Error("G_LLL_FP: bad deep"); return G_LLL_FP(B, &U, delta, deep, check); } NTL_THREAD_LOCAL static vec_double G_BKZConstant; static void ComputeG_BKZConstant(long beta, long p) { const double c_PI = 3.14159265358979323846264338328; const double LogPI = 1.14472988584940017414342735135; G_BKZConstant.SetLength(beta-1); vec_double Log; Log.SetLength(beta); long i, j, k; double x, y; for (j = 1; j <= beta; j++) Log(j) = log(double(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/double(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/double(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/double(i))*Log(2); y = exp(y); G_BKZConstant(i) = x*y/c_PI; } } NTL_THREAD_LOCAL static vec_double G_BKZThresh; static void ComputeG_BKZThresh(double *c, long beta) { G_BKZThresh.SetLength(beta-1); long i; double x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); G_BKZThresh(i) = exp(x/double(i))*G_BKZConstant(i); if (!IsFinite(&G_BKZThresh(i))) G_BKZThresh(i) = 0; } } static void G_BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- G_BKZ_FP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long G_BKZ_FP(mat_ZZ& BB, mat_ZZ* UU, double delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; double t1; ZZ T1; double *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); double **B1; // approximates B typedef double *doubleptr; B1 = NTL_NEW_OP doubleptr[m+2]; if (!B1) Error("G_BKZ_FP: out of memory"); for (i = 1; i <= m+1; i++) { B1[i] = NTL_NEW_OP double[n+1]; if (!B1[i]) Error("G_BKZ_FP: out of memory"); } double **mu; mu = NTL_NEW_OP doubleptr[m+2]; if (!mu) Error("G_LLL_FP: out of memory"); for (i = 1; i <= m+1; i++) { mu[i] = NTL_NEW_OP double[n+2]; if (!mu[i]) Error("G_BKZ_FP: out of memory"); } double **aux; aux = NTL_NEW_OP doubleptr[m+2]; if (!aux) Error("G_LLL_FP: out of memory"); for (i = 1; i <= m+1; i++) { aux[i] = NTL_NEW_OP double[n+1]; if (!aux[i]) Error("G_BKZ_FP: out of memory"); } double *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP double[m+2]; if (!c) Error("G_BKZ_FP: out of memory"); double cbar; double *ctilda; ctilda = NTL_NEW_OP double[m+2]; if (!ctilda) Error("G_BKZ_FP: out of memory"); double *vvec; vvec = NTL_NEW_OP double[m+2]; if (!vvec) Error("G_BKZ_FP: out of memory"); double *yvec; yvec = NTL_NEW_OP double[m+2]; if (!yvec) Error("G_BKZ_FP: out of memory"); double *uvec; uvec = NTL_NEW_OP double[m+2]; if (!uvec) Error("G_BKZ_FP: out of memory"); double *utildavec; utildavec = NTL_NEW_OP double[m+2]; if (!utildavec) Error("G_BKZ_FP: out of memory"); long *Deltavec; Deltavec = NTL_NEW_OP long[m+2]; if (!Deltavec) Error("G_BKZ_FP: out of memory"); long *deltavec; deltavec = NTL_NEW_OP long[m+2]; if (!deltavec) Error("G_BKZ_FP: out of memory"); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; double eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_FP cache(m, n); m = ll_G_LLL_FP(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) { c[i] = mu[i][i]*mu[i][i]; CheckFinite(&c[i]); } if (prune > 0) ComputeG_BKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; ForceToMem(&ctilda[t]); // prevents an infinite loop if (prune > 0 && t > jj) { eta = G_BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) t1 += utildavec[i]*mu[i][t]; yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta - 8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("G_BKZ_FP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } // cerr << "special case\n"; new_m = ll_G_LLL_FP(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) Error("G_BKZ_FP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } if (IsZero(B(jj))) Error("G_BKZ_FP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_FP(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) Error("G_BKZ_FP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_FP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_FP: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_FP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_FP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_FP: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } for (i = 1; i <= m_orig+1; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m_orig+1; i++) { delete [] mu[i]; } delete [] mu; for (i = 1; i <= m_orig+1; i++) { delete [] aux[i]; } delete [] aux; delete [] c; delete [] ctilda; delete [] vvec; delete [] yvec; delete [] uvec; delete [] utildavec; delete [] Deltavec; delete [] deltavec; return m; } long G_BKZ_FP(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_FP: bad delta"); if (beta < 2) Error("G_BKZ_FP: bad block size"); return G_BKZ_FP(BB, &UU, delta, beta, prune, check); } long G_BKZ_FP(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_FP: bad delta"); if (beta < 2) Error("G_BKZ_FP: bad block size"); return G_BKZ_FP(BB, 0, delta, beta, prune, check); } NTL_END_IMPL ntl-6.2.1/src/G_LLL_QP.c000644 000765 000024 00000132500 12377144456 015060 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL static inline void CheckFinite(double *p) { if (!IsFinite(p)) Error("G_LLL_QP: numbers too big...use G_LLL_XD"); } static inline void CheckFinite(quad_float *p) { if (!IsFinite(p)) Error("G_LLL_QP: numbers too big...use G_LLL_XD"); } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } #define TR_BND (NTL_FDOUBLE_PRECISION/2.0) // Just to be safe!! static double max_abs(quad_float *v, long n) { long i; double res, t; res = 0; for (i = 1; i <= n; i++) { t = fabs(v[i].hi); if (t > res) res = t; } return res; } static void RowTransformStart(quad_float *a, long *in_a, long& in_float, long n) { long i; long inf = 1; for (i = 1; i <= n; i++) { in_a[i] = (a[i].hi < TR_BND && a[i].hi > -TR_BND); inf = inf & in_a[i]; } in_float = inf; } static void RowTransformFinish(vec_ZZ& A, quad_float *a, long *in_a) { long n = A.length(); long i; for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); } else { conv(a[i], A(i)); CheckFinite(&a[i]); } } } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1, quad_float *a, quad_float *b, long *in_a, double& max_a, double max_b, long& in_float) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; double mu; long n = A.length(); long i; conv(mu, MU1); CheckFinite(&mu); if (in_float) { double mu_abs = fabs(mu); if (mu_abs > 0 && max_b > 0 && (mu_abs >= TR_BND || max_b >= TR_BND)) { in_float = 0; } else { max_a += mu_abs*max_b; if (max_a >= TR_BND) in_float = 0; } } if (in_float) { if (mu == 1) { for (i = 1; i <= n; i++) a[i].hi -= b[i].hi; return; } if (mu == -1) { for (i = 1; i <= n; i++) a[i].hi += b[i].hi; return; } if (mu == 0) return; for (i = 1; i <= n; i++) a[i].hi -= mu*b[i].hi; return; } MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < TR_BND && b[i].hi > -TR_BND) { a[i].hi -= b[i].hi; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } sub(A(i), A(i), B(i)); } } return; } if (MU == -1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < TR_BND && b[i].hi > -TR_BND) { a[i].hi += b[i].hi; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } add(A(i), A(i), B(i)); } } return; } if (MU == 0) return; double b_bnd = fabs(TR_BND/mu) - 1; if (b_bnd < 0) b_bnd = 0; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < b_bnd && b[i].hi > -b_bnd) { a[i].hi -= b[i].hi*mu; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } MulSubFrom(A(i), B(i), mu1); } } } } else { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } class GivensCache_QP { public: GivensCache_QP(long m, long n); ~GivensCache_QP(); void flush(); void selective_flush(long l); void swap(long l); void swap(); void touch(); void incr(); long sz; quad_float **buf; long *bl; long *bv; long bp; }; GivensCache_QP::GivensCache_QP(long m, long n) { sz = min(m, n)/10; if (sz < 2) sz = 2; else if (sz > 20) sz = 20; typedef quad_float *quad_floatptr; long i; buf = NTL_NEW_OP quad_floatptr[sz]; if (!buf) Error("out of memory"); for (i = 0; i < sz; i++) if (!(buf[i] = NTL_NEW_OP quad_float[n+1])) Error("out of memory"); bl = NTL_NEW_OP long[sz]; if (!bl) Error("out of memory"); for (i = 0; i < sz; i++) bl[0] = 0; bv = NTL_NEW_OP long[sz]; if (!bv) Error("out of memory"); for (i = 0; i < sz; i++) bv[0] = 0; bp = 0; } GivensCache_QP::~GivensCache_QP() { long i; for (i = 0; i < sz; i++) delete [] buf[i]; delete [] buf; delete [] bl; delete [] bv; } void GivensCache_QP::flush() { long i; for (i = 0; i < sz; i++) bl[i] = 0; } void GivensCache_QP::selective_flush(long l) { long i; for (i = 0; i < sz; i++) if (bl[i] && bv[i] >= l) bl[i] = 0; } void GivensCache_QP::swap(long l) { long k = bl[bp]; long i; i = 0; while (i < sz && bl[i] != l) i++; if (i < sz) { bl[bp] = l; bl[i] = k; } else bl[bp] = l; selective_flush(l); } void GivensCache_QP::swap() { swap(bl[bp] - 1); } void GivensCache_QP::touch() { long k = bl[bp]; bl[bp] = 0; selective_flush(k); } void GivensCache_QP::incr() { long k = bl[bp]; long k1 = k+1; long i; i = 0; while (i < sz && bl[i] != k1) i++; if (i < sz) { bp = i; return; } i = 0; while (i < sz && bl[i] != 0) i++; if (i < sz) { bp = i; return; } long max_val = 0; long max_index = 0; for (i = 0; i < sz; i++) { long t = labs(bl[i]-k1); if (t > max_val) { max_val = t; max_index = i; } } bp = max_index; bl[max_index] = 0; } static void GivensComputeGS(quad_float **B1, quad_float **mu, quad_float **aux, long k, long n, GivensCache_QP& cache) { long i, j; quad_float c, s, a, b, t; quad_float *p = mu[k]; quad_float *pp = cache.buf[cache.bp]; if (!cache.bl[cache.bp]) { for (j = 1; j <= n; j++) pp[j] = B1[k][j]; long backoff; backoff = k/4; if (backoff < 2) backoff = 2; else if (backoff > cache.sz + 2) backoff = cache.sz + 2; long ub = k-(backoff-1); for (i = 1; i < ub; i++) { quad_float *cptr = mu[i]; quad_float *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*pp[j-1] - s*pp[j]; b = s*pp[j-1] + c*pp[j]; pp[j-1] = a; pp[j] = b; } pp[i] = pp[i]/mu[i][i]; } cache.bl[cache.bp] = k; cache.bv[cache.bp] = k-backoff; } for (j = 1; j <= n; j++) p[j] = pp[j]; for (i = max(cache.bv[cache.bp]+1, 1); i < k; i++) { quad_float *cptr = mu[i]; quad_float *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*p[j-1] - s*p[j]; b = s*p[j-1] + c*p[j]; p[j-1] = a; p[j] = b; } p[i] = p[i]/mu[i][i]; } for (j = n; j > k; j--) { a = p[j-1]; b = p[j]; if (b == 0) { c = 1; s = 0; } else if (fabs(b) > fabs(a)) { t = -a/b; s = 1/sqrt(1 + t*t); c = s*t; } else { t = -b/a; c = 1/sqrt(1 + t*t); s = c*t; } p[j-1] = c*a - s*b; p[j] = c; aux[k][j] = s; } if (k > n+1) Error("G_LLL_QP: internal error"); if (k > n) p[k] = 0; for (i = 1; i <= k; i++) CheckFinite(&p[i]); } NTL_THREAD_LOCAL static quad_float red_fudge = to_quad_float(0); NTL_THREAD_LOCAL static long log_red = 0; NTL_THREAD_LOCAL static long verbose = 0; NTL_THREAD_LOCAL static unsigned long NumSwaps = 0; NTL_THREAD_LOCAL static double StartTime = 0; NTL_THREAD_LOCAL static double LastTime = 0; static void G_LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- G_LLL_QP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static void init_red_fudge() { long i; // initial log_red should be <= NTL_DOUBLE_PRECISION-2, // to help ensure stability in G_BKZ_QP1 log_red = NTL_DOUBLE_PRECISION-2; red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { red_fudge = red_fudge * 2; log_red--; cerr << "G_LLL_QP: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) Error("G_LLL_QP: too much loss of precision...stop!"); } static long ll_G_LLL_QP(mat_ZZ& B, mat_ZZ* U, quad_float delta, long deep, LLLCheckFct check, quad_float **B1, quad_float **mu, quad_float **aux, long m, long init_k, long &quit, GivensCache_QP& cache) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; quad_float mu1; quad_float t1; double dt1; ZZ T1; quad_float *tp; quad_float half = to_quad_float(0.5); quad_float half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long in_vec_mem; in_vec_mem.SetLength(n+1); long *in_vec = in_vec_mem.elts(); double *max_b; max_b = NTL_NEW_OP double [m+1]; if (!max_b) Error("out of memory in lll_G_LLL_QP"); for (i = 1; i <= m; i++) max_b[i] = max_abs(B1[i], n); long in_float; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; cache.flush(); while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_LLLStatus(max_k, tt, m, B); } GivensComputeGS(B1, mu, aux, k, n, cache); counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "G_LLL_QP: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = k-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); Fc1 = 1; RowTransformStart(B1[k], in_vec, in_float, n); } mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-half); else mu1 = floor(mu1+half); quad_float *mu_k = mu[k]; quad_float *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) mu_k[i] -= mu1*mu_j[i]; } // cout << j << " " << mu[k][j] << " " << mu1 << "\n"; mu_k[j] -= mu1; conv(MU, mu1); RowTransform(B(k), B(j), MU, B1[k], B1[j], in_vec, max_b[k], max_b[j], in_float); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { RowTransformFinish(B(k), B1[k], in_vec); max_b[k] = max_abs(B1[k], n); cache.touch(); GivensComputeGS(B1, mu, aux, k, n, cache); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(B(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; dt1 = max_b[i]; max_b[i] = max_b[i+1]; max_b[i+1] = dt1; if (U) swap((*U)(i), (*U)(i+1)); } cache.flush(); m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions Error("sorry...deep insertions not implemented"); } // end deep insertions // test LLL reduction condition if (k > 1 && sqrt(delta - mu[k][k-1]*mu[k][k-1])*fabs(mu[k-1][k-1]) > fabs(mu[k][k])) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; dt1 = max_b[k]; max_b[k] = max_b[k-1]; max_b[k-1] = dt1; if (U) swap((*U)(k), (*U)(k-1)); cache.swap(); k--; NumSwaps++; // cout << "- " << k << "\n"; } else { cache.incr(); k++; // cout << "+ " << k << "\n"; } } if (verbose) { G_LLLStatus(m+1, GetTime(), m, B); } delete [] max_b; return m; } static long G_LLL_QP(mat_ZZ& B, mat_ZZ* U, quad_float delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; quad_float s; ZZ MU; quad_float mu1; quad_float t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); quad_float **B1; // approximates B typedef quad_float *quad_floatptr; B1 = NTL_NEW_OP quad_floatptr[m+1]; if (!B1) Error("G_LLL_QP: out of memory"); for (i = 1; i <= m; i++) { B1[i] = NTL_NEW_OP quad_float[n+1]; if (!B1[i]) Error("G_LLL_QP: out of memory"); } quad_float **mu; mu = NTL_NEW_OP quad_floatptr[m+1]; if (!mu) Error("G_LLL_QP: out of memory"); for (i = 1; i <= m; i++) { mu[i] = NTL_NEW_OP quad_float[n+2]; if (!mu[i]) Error("G_LLL_QP: out of memory"); } quad_float **aux; aux = NTL_NEW_OP quad_floatptr[m+1]; if (!aux) Error("G_LLL_QP: out of memory"); for (i = 1; i <= m; i++) { aux[i] = NTL_NEW_OP quad_float[n+1]; if (!aux[i]) Error("G_LLL_QP: out of memory"); } for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_QP cache(m, n); new_m = ll_G_LLL_QP(B, U, delta, deep, check, B1, mu, aux, m, 1, quit, cache); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } // clean-up for (i = 1; i <= m+dep; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m+dep; i++) { delete [] mu[i]; } delete [] mu; for (i = 1; i <= m+dep; i++) { delete [] aux[i]; } delete [] aux; return m; } long G_LLL_QP(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_LLL_QP: bad delta"); if (deep < 0) Error("G_LLL_QP: bad deep"); return G_LLL_QP(B, 0, to_quad_float(delta), deep, check); } long G_LLL_QP(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_LLL_QP: bad delta"); if (deep < 0) Error("G_LLL_QP: bad deep"); return G_LLL_QP(B, &U, to_quad_float(delta), deep, check); } NTL_THREAD_LOCAL static vec_quad_float G_BKZConstant; static void ComputeG_BKZConstant(long beta, long p) { const quad_float c_PI = to_quad_float("3.141592653589793238462643383279502884197"); const quad_float LogPI = to_quad_float("1.144729885849400174143427351353058711647"); G_BKZConstant.SetLength(beta-1); vec_quad_float Log; Log.SetLength(beta); long i, j, k; quad_float x, y; for (j = 1; j <= beta; j++) Log(j) = log(to_quad_float(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/to_quad_float(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/to_quad_float(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/to_quad_float(i))*Log(2); y = exp(y); G_BKZConstant(i) = x*y/c_PI; } } NTL_THREAD_LOCAL static vec_quad_float G_BKZThresh; static void ComputeG_BKZThresh(quad_float *c, long beta) { G_BKZThresh.SetLength(beta-1); long i; quad_float x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); G_BKZThresh(i) = exp(x/to_quad_float(i))*G_BKZConstant(i); if (!IsFinite(&G_BKZThresh(i))) G_BKZThresh(i) = 0; } } static void G_BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- G_BKZ_QP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long G_BKZ_QP(mat_ZZ& BB, mat_ZZ* UU, quad_float delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; quad_float t1; ZZ T1; quad_float *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); quad_float **B1; // approximates B typedef quad_float *quad_floatptr; B1 = NTL_NEW_OP quad_floatptr[m+2]; if (!B1) Error("G_BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { B1[i] = NTL_NEW_OP quad_float[n+1]; if (!B1[i]) Error("G_BKZ_QP: out of memory"); } quad_float **mu; mu = NTL_NEW_OP quad_floatptr[m+2]; if (!mu) Error("G_BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { mu[i] = NTL_NEW_OP quad_float[n+2]; if (!mu[i]) Error("G_BKZ_QP: out of memory"); } quad_float **aux; aux = NTL_NEW_OP quad_floatptr[m+2]; if (!aux) Error("G_BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { aux[i] = NTL_NEW_OP quad_float[n+1]; if (!aux[i]) Error("G_BKZ_QP: out of memory"); } quad_float *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP quad_float[m+2]; if (!c) Error("G_BKZ_QP: out of memory"); quad_float cbar; quad_float *ctilda; ctilda = NTL_NEW_OP quad_float[m+2]; if (!ctilda) Error("G_BKZ_QP: out of memory"); quad_float *vvec; vvec = NTL_NEW_OP quad_float[m+2]; if (!vvec) Error("G_BKZ_QP: out of memory"); quad_float *yvec; yvec = NTL_NEW_OP quad_float[m+2]; if (!yvec) Error("G_BKZ_QP: out of memory"); quad_float *uvec; uvec = NTL_NEW_OP quad_float[m+2]; if (!uvec) Error("G_BKZ_QP: out of memory"); quad_float *utildavec; utildavec = NTL_NEW_OP quad_float[m+2]; if (!utildavec) Error("G_BKZ_QP: out of memory"); long *Deltavec; Deltavec = NTL_NEW_OP long[m+2]; if (!Deltavec) Error("G_BKZ_QP: out of memory"); long *deltavec; deltavec = NTL_NEW_OP long[m+2]; if (!deltavec) Error("G_BKZ_QP: out of memory"); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; quad_float eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_QP cache(m, n); m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) { c[i] = mu[i][i]*mu[i][i]; CheckFinite(&c[i]); } if (prune > 0) ComputeG_BKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; if (prune > 0 && t > jj) { eta = G_BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*mu[i][t]; } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta-8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("G_BKZ_QP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } // cerr << "special case\n"; new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) Error("G_BKZ_QP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } if (IsZero(B(jj))) Error("G_BKZ_QP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_QP(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) Error("G_BKZ_QP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_QP: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_QP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_QP: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } for (i = 1; i <= m_orig+1; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m_orig+1; i++) { delete [] mu[i]; } delete [] mu; for (i = 1; i <= m_orig+1; i++) { delete [] aux[i]; } delete [] aux; delete [] c; delete [] ctilda; delete [] vvec; delete [] yvec; delete [] uvec; delete [] utildavec; delete [] Deltavec; delete [] deltavec; return m; } long G_BKZ_QP(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_QP: bad delta"); if (beta < 2) Error("G_BKZ_QP: bad block size"); return G_BKZ_QP(BB, &UU, to_quad_float(delta), beta, prune, check); } long G_BKZ_QP(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_QP: bad delta"); if (beta < 2) Error("G_BKZ_QP: bad block size"); return G_BKZ_QP(BB, 0, to_quad_float(delta), beta, prune, check); } static long G_BKZ_QP1(mat_ZZ& BB, mat_ZZ* UU, quad_float delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; ZZ T1; quad_float *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); quad_float **B1; // approximates B typedef quad_float *quad_floatptr; B1 = NTL_NEW_OP quad_floatptr[m+2]; if (!B1) Error("G_BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { B1[i] = NTL_NEW_OP quad_float[n+1]; if (!B1[i]) Error("G_BKZ_QP: out of memory"); } quad_float **mu; mu = NTL_NEW_OP quad_floatptr[m+2]; if (!mu) Error("G_BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { mu[i] = NTL_NEW_OP quad_float[n+2]; if (!mu[i]) Error("G_BKZ_QP: out of memory"); } quad_float **aux; aux = NTL_NEW_OP quad_floatptr[m+2]; if (!aux) Error("G_BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { aux[i] = NTL_NEW_OP quad_float[n+1]; if (!aux[i]) Error("G_BKZ_QP: out of memory"); } quad_float *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP quad_float[m+2]; if (!c) Error("G_BKZ_QP: out of memory"); double cbar; double *ctilda; ctilda = NTL_NEW_OP double[m+2]; if (!ctilda) Error("G_BKZ_QP: out of memory"); double *vvec; vvec = NTL_NEW_OP double[m+2]; if (!vvec) Error("G_BKZ_QP: out of memory"); double *yvec; yvec = NTL_NEW_OP double[m+2]; if (!yvec) Error("G_BKZ_QP: out of memory"); double *uvec; uvec = NTL_NEW_OP double[m+2]; if (!uvec) Error("G_BKZ_QP: out of memory"); double *utildavec; utildavec = NTL_NEW_OP double[m+2]; if (!utildavec) Error("G_BKZ_QP: out of memory"); long *Deltavec; Deltavec = NTL_NEW_OP long[m+2]; if (!Deltavec) Error("G_BKZ_QP: out of memory"); long *deltavec; deltavec = NTL_NEW_OP long[m+2]; if (!deltavec) Error("G_BKZ_QP: out of memory"); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; double eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_QP cache(m, n); m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) { c[i] = mu[i][i]*mu[i][i]; CheckFinite(&c[i]); } if (prune > 0) ComputeG_BKZThresh(&c[jj], kk-jj+1); cbar = to_double(c[jj]); utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*to_double(c[t]); ForceToMem(&ctilda[t]); // prevents an infinite loop if (prune > 0 && t > jj) { eta = to_double(G_BKZThresh(t-jj)); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { double t1; t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*to_double(mu[i][t]); } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); quad_float t1; if ((delta-8*red_fudge)*c[jj] > cbar*(1+64/NTL_FDOUBLE_PRECISION)) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("G_BKZ_QP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } // cerr << "special case\n"; new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) Error("G_BKZ_QP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } if (IsZero(B(jj))) Error("G_BKZ_QP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_QP(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) Error("G_BKZ_QP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_QP: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_QP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_QP: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } for (i = 1; i <= m_orig+1; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m_orig+1; i++) { delete [] mu[i]; } delete [] mu; for (i = 1; i <= m_orig+1; i++) { delete [] aux[i]; } delete [] aux; delete [] c; delete [] ctilda; delete [] vvec; delete [] yvec; delete [] uvec; delete [] utildavec; delete [] Deltavec; delete [] deltavec; return m; } long G_BKZ_QP1(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_QP: bad delta"); if (beta < 2) Error("G_BKZ_QP: bad block size"); return G_BKZ_QP1(BB, &UU, to_quad_float(delta), beta, prune, check); } long G_BKZ_QP1(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_QP: bad delta"); if (beta < 2) Error("G_BKZ_QP: bad block size"); return G_BKZ_QP1(BB, 0, to_quad_float(delta), beta, prune, check); } NTL_END_IMPL ntl-6.2.1/src/G_LLL_RR.c000644 000765 000024 00000064644 12377144456 015100 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } class GivensCache_RR { public: GivensCache_RR(long m, long n); ~GivensCache_RR(); void flush(); void selective_flush(long l); void swap(long l); void swap(); void touch(); void incr(); long sz; mat_RR buf; long *bl; long *bv; long bp; }; GivensCache_RR::GivensCache_RR(long m, long n) { sz = min(m, n)/10; if (sz < 2) sz = 2; else if (sz > 20) sz = 20; typedef double *doubleptr; long i; buf.SetDims(sz, n); bl = NTL_NEW_OP long[sz]; if (!bl) Error("out of memory"); for (i = 0; i < sz; i++) bl[0] = 0; bv = NTL_NEW_OP long[sz]; if (!bv) Error("out of memory"); for (i = 0; i < sz; i++) bv[0] = 0; bp = 0; } GivensCache_RR::~GivensCache_RR() { delete [] bl; delete [] bv; } void GivensCache_RR::flush() { long i; for (i = 0; i < sz; i++) bl[i] = 0; } void GivensCache_RR::selective_flush(long l) { long i; for (i = 0; i < sz; i++) if (bl[i] && bv[i] >= l) bl[i] = 0; } void GivensCache_RR::swap(long l) { long k = bl[bp]; long i; i = 0; while (i < sz && bl[i] != l) i++; if (i < sz) { bl[bp] = l; bl[i] = k; } else bl[bp] = l; selective_flush(l); } void GivensCache_RR::swap() { swap(bl[bp] - 1); } void GivensCache_RR::touch() { long k = bl[bp]; bl[bp] = 0; selective_flush(k); } void GivensCache_RR::incr() { long k = bl[bp]; long k1 = k+1; long i; i = 0; while (i < sz && bl[i] != k1) i++; if (i < sz) { bp = i; return; } i = 0; while (i < sz && bl[i] != 0) i++; if (i < sz) { bp = i; return; } long max_val = 0; long max_index = 0; for (i = 0; i < sz; i++) { long t = labs(bl[i]-k1); if (t > max_val) { max_val = t; max_index = i; } } bp = max_index; bl[max_index] = 0; } static void GivensComputeGS(mat_RR& B1, mat_RR& mu, mat_RR& aux, long k, long n, GivensCache_RR& cache) { long i, j; RR c, s, a, b, t; RR T1, T2; vec_RR& p = mu(k); vec_RR& pp = cache.buf[cache.bp]; if (!cache.bl[cache.bp]) { for (j = 1; j <= n; j++) pp(j) = B1(k,j); long backoff; backoff = k/4; if (backoff < 2) backoff = 2; else if (backoff > cache.sz + 2) backoff = cache.sz + 2; long ub = k-(backoff-1); for (i = 1; i < ub; i++) { vec_RR& cptr = mu(i); vec_RR& sptr = aux(i); for (j = n; j > i; j--) { c = cptr(j); s = sptr(j); // a = c*pp(j-1) - s*pp(j); mul(T1, c, pp(j-1)); mul(T2, s, pp(j)); sub(a, T1, T2); // b = s*pp(j-1) + c*pp(j); mul(T1, s, pp(j-1)); mul(T2, c, pp(j)); add(b, T1, T2); pp(j-1) = a; pp(j) = b; } div(pp(i), pp(i), mu(i,i)); } cache.bl[cache.bp] = k; cache.bv[cache.bp] = k-backoff; } for (j = 1; j <= n; j++) p(j) = pp(j); for (i = max(cache.bv[cache.bp]+1, 1); i < k; i++) { vec_RR& cptr = mu(i); vec_RR& sptr = aux(i); for (j = n; j > i; j--) { c = cptr(j); s = sptr(j); // a = c*p(j-1) - s*p(j); mul(T1, c, p(j-1)); mul(T2, s, p(j)); sub(a, T1, T2); // b = s*p(j-1) + c*p(j); mul(T1, s, p(j-1)); mul(T2, c, p(j)); add(b, T1, T2); p(j-1) = a; p(j) = b; } div(p(i), p(i), mu(i,i)); } for (j = n; j > k; j--) { a = p(j-1); b = p(j); if (b == 0) { c = 1; s = 0; } else { abs(T1, b); abs(T2, a); if (T1 > T2) { // t = -a/b; div(T1, a, b); negate(t, T1); // s = 1/sqrt(1 + t*t); sqr(T1, t); add(T1, T1, 1); SqrRoot(T1, T1); inv(s, T1); // c = s*t; mul(c, s, t); } else { // t = -b/a; div(T1, b, a); negate(t, T1); // c = 1/sqrt(1 + t*t); sqr(T1, t); add(T1, T1, 1); SqrRoot(T1, T1); inv(c, T1); // s = c*t; mul(s, c, t); } } // p(j-1) = c*a - s*b; mul(T1, c, a); mul(T2, s, b); sub(p(j-1), T1, T2); p(j) = c; aux(k,j) = s; } if (k > n+1) Error("G_LLL_RR: internal error"); if (k > n) p(k) = 0; } NTL_THREAD_LOCAL static RR red_fudge; NTL_THREAD_LOCAL static long log_red = 0; static void init_red_fudge() { log_red = long(0.50*RR::precision()); power2(red_fudge, -log_red); } static void inc_red_fudge() { mul(red_fudge, red_fudge, 2); log_red--; cerr << "G_LLL_RR: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) Error("G_LLL_RR: can not continue...sorry"); } NTL_THREAD_LOCAL static long verbose = 0; NTL_THREAD_LOCAL static unsigned long NumSwaps = 0; NTL_THREAD_LOCAL static double StartTime = 0; NTL_THREAD_LOCAL static double LastTime = 0; static void G_LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- G_LLL_RR status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static long ll_G_LLL_RR(mat_ZZ& B, mat_ZZ* U, const RR& delta, long deep, LLLCheckFct check, mat_RR& B1, mat_RR& mu, mat_RR& aux, long m, long init_k, long &quit, GivensCache_RR& cache) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; RR mu1, t1, t2, cc; ZZ T1; quit = 0; k = init_k; long counter; long trigger_index; long small_trigger; long cnt; RR half; conv(half, 0.5); RR half_plus_fudge; add(half_plus_fudge, half, red_fudge); long max_k = 0; double tt; cache.flush(); while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_LLLStatus(max_k, tt, m, B); } GivensComputeGS(B1, mu, aux, k, n, cache); counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "G_LLL_XD: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = k-1; j >= 1; j--) { abs(t1, mu(k,j)); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); add(half_plus_fudge, half, red_fudge); cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu(k,j); if (sign(mu1) >= 0) { sub(mu1, mu1, half); ceil(mu1, mu1); } else { add(mu1, mu1, half); floor(mu1, mu1); } if (mu1 == 1) { for (i = 1; i <= j-1; i++) sub(mu(k,i), mu(k,i), mu(j,i)); } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) add(mu(k,i), mu(k,i), mu(j,i)); } else { for (i = 1; i <= j-1; i++) { mul(t2, mu1, mu(j,i)); sub(mu(k,i), mu(k,i), t2); } } conv(MU, mu1); sub(mu(k,j), mu(k,j), mu1); RowTransform(B(k), B(j), MU); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1(k, i), B(k, i)); cache.touch(); GivensComputeGS(B1, mu, aux, k, n, cache); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(B(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); swap(B1(i), B1(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } cache.flush(); m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions Error("sorry...deep insertions not implemented"); } // end deep insertions // test G_LLL reduction condition if (k <= 1) { cache.incr(); k++; } else { sqr(t1, mu(k,k-1)); sub(t1, delta, t1); sqr(t2, mu(k-1,k-1)); mul(t1, t1, t2); sqr(t2, mu(k, k)); if (t1 > t2) { // swap rows k, k-1 swap(B(k), B(k-1)); swap(B1(k), B1(k-1)); if (U) swap((*U)(k), (*U)(k-1)); cache.swap(); k--; NumSwaps++; } else { cache.incr(); k++; } } } if (verbose) { G_LLLStatus(m+1, GetTime(), m, B); } return m; } static long G_LLL_RR(mat_ZZ& B, mat_ZZ* U, const RR& delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; RR s; ZZ MU; RR mu1; RR t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); mat_RR B1; // approximates B B1.SetDims(m, n); mat_RR mu; mu.SetDims(m, n+1); mat_RR aux; aux.SetDims(m, n); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); GivensCache_RR cache(m, n); new_m = ll_G_LLL_RR(B, U, delta, deep, check, B1, mu, aux, m, 1, quit, cache); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long G_LLL_RR(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_LLL_RR: bad delta"); if (deep < 0) Error("G_LLL_RR: bad deep"); RR Delta; conv(Delta, delta); return G_LLL_RR(B, 0, Delta, deep, check); } long G_LLL_RR(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_LLL_RR: bad delta"); if (deep < 0) Error("G_LLL_RR: bad deep"); RR Delta; conv(Delta, delta); return G_LLL_RR(B, &U, Delta, deep, check); } NTL_THREAD_LOCAL static vec_RR G_BKZConstant; static void ComputeG_BKZConstant(long beta, long p) { RR c_PI; ComputePi(c_PI); RR LogPI = log(c_PI); G_BKZConstant.SetLength(beta-1); vec_RR Log; Log.SetLength(beta); long i, j, k; RR x, y; for (j = 1; j <= beta; j++) Log(j) = log(to_RR(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x += Log(j); x = exp(x/k); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x += Log(j); x += 0.5*LogPI - 2*(k+1)*Log(2); x = exp(2*x/i); } // Second, we compute y = 2^{2*p/i} y = exp(-(2*p/to_RR(i))*Log(2)); G_BKZConstant(i) = x*y/c_PI; } } NTL_THREAD_LOCAL static vec_RR G_BKZThresh; static void ComputeG_BKZThresh(RR *c, long beta) { G_BKZThresh.SetLength(beta-1); long i; RR x; RR t1; x = 0; for (i = 1; i <= beta-1; i++) { log(t1, c[i-1]); add(x, x, t1); div(t1, x, i); exp(t1, t1); mul(G_BKZThresh(i), t1, G_BKZConstant(i)); } } static void G_BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- G_BKZ_RR status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long G_BKZ_RR(mat_ZZ& BB, mat_ZZ* UU, const RR& delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; RR t1, t2; ZZ T1; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); mat_RR B1; B1.SetDims(m+1, n); mat_RR mu; mu.SetDims(m+1, n+1); mat_RR aux; aux.SetDims(m+1, n); vec_RR c; c.SetLength(m+1); RR cbar; vec_RR ctilda; ctilda.SetLength(m+1); vec_RR vvec; vvec.SetLength(m+1); vec_RR yvec; yvec.SetLength(m+1); vec_RR uvec; uvec.SetLength(m+1); vec_RR utildavec; utildavec.SetLength(m+1); vec_long Deltavec; Deltavec.SetLength(m+1); vec_long deltavec; deltavec.SetLength(m+1); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); // cerr << "\n"; // cerr << "first G_LLL\n"; GivensCache_RR cache(m, n); m = ll_G_LLL_RR(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } long clean = 1; if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) sqr(c(i), mu(i,i)); if (prune > 0) ComputeG_BKZThresh(&c(jj), kk-jj+1); cbar = c(jj); conv(utildavec(jj), 1); conv(uvec(jj), 1); conv(yvec(jj), 0); conv(vvec(jj), 0); Deltavec(jj) = 0; s = t = jj; deltavec(jj) = 1; for (i = jj+1; i <= kk+1; i++) { conv(ctilda(i), 0); conv(uvec(i), 0); conv(utildavec(i), 0); conv(yvec(i), 0); Deltavec(i) = 0; conv(vvec(i), 0); deltavec(i) = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } add(t1, yvec(t), utildavec(t)); sqr(t1, t1); mul(t1, t1, c(t)); add(ctilda(t), ctilda(t+1), t1); if (prune > 0 && t > jj) sub(t1, cbar, G_BKZThresh(t-jj)); else t1 = cbar; if (ctilda(t) jj) { t--; clear(t1); for (i = t+1; i <= s; i++) { mul(t2, utildavec(i), mu(i,t)); add(t1, t1, t2); } yvec(t) = t1; negate(t1, t1); if (sign(t1) >= 0) { sub(t1, t1, 0.5); ceil(t1, t1); } else { add(t1, t1, 0.5); floor(t1, t1); } utildavec(t) = t1; vvec(t) = t1; Deltavec(t) = 0; negate(t1, t1); if (t1 < yvec(t)) deltavec(t) = -1; else deltavec(t) = 1; } else { cbar = ctilda(jj); for (i = jj; i <= kk; i++) { uvec(i) = utildavec(i); } } } else { t++; s = max(s, t); if (t < s) Deltavec(t) = -Deltavec(t); if (Deltavec(t)*deltavec(t) >= 0) Deltavec(t) += deltavec(t); add(utildavec(t), vvec(t), Deltavec(t)); } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); mul(t1, red_fudge, -8); add(t1, t1, delta); mul(t1, t1, c(jj)); if (t1 > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec(i) != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("G_BKZ_RR: internal error"); if (s > 0) { // special case // cerr << "special case\n"; NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); if (U) swap((*U)(i-1), (*U)(i)); } new_m = ll_G_LLL_RR(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) Error("G_BKZ_RR: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec(i) == 0) continue; conv(MU, uvec(i)); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); if (U) swap((*U)(i-1), (*U)(i)); } for (i = 1; i <= n; i++) conv(B1(jj, i), B(jj, i)); if (IsZero(B(jj))) Error("G_BKZ_RR: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_RR(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) Error("G_BKZ_RR: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); if (U) swap((*U)(i-1), (*U)(i)); } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_RR(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_RR: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_RR // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_RR(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_RR: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long G_BKZ_RR(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_RR: bad delta"); if (beta < 2) Error("G_BKZ_RR: bad block size"); RR Delta; conv(Delta, delta); return G_BKZ_RR(BB, &UU, Delta, beta, prune, check); } long G_BKZ_RR(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_RR: bad delta"); if (beta < 2) Error("G_BKZ_RR: bad block size"); RR Delta; conv(Delta, delta); return G_BKZ_RR(BB, 0, Delta, beta, prune, check); } NTL_END_IMPL ntl-6.2.1/src/G_LLL_XD.c000644 000765 000024 00000070025 12377144456 015056 0ustar00shoupstaff000000 000000 #include #include #include #include #include NTL_START_IMPL static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } class GivensCache_XD { public: GivensCache_XD(long m, long n); ~GivensCache_XD(); void flush(); void selective_flush(long l); void swap(long l); void swap(); void touch(); void incr(); long sz; xdouble **buf; long *bl; long *bv; long bp; }; GivensCache_XD::GivensCache_XD(long m, long n) { sz = min(m, n)/10; if (sz < 2) sz = 2; else if (sz > 20) sz = 20; typedef xdouble *xdoubleptr; long i; buf = NTL_NEW_OP xdoubleptr[sz]; if (!buf) Error("out of memory"); for (i = 0; i < sz; i++) if (!(buf[i] = NTL_NEW_OP xdouble[n+1])) Error("out of memory"); bl = NTL_NEW_OP long[sz]; if (!bl) Error("out of memory"); for (i = 0; i < sz; i++) bl[0] = 0; bv = NTL_NEW_OP long[sz]; if (!bv) Error("out of memory"); for (i = 0; i < sz; i++) bv[0] = 0; bp = 0; } GivensCache_XD::~GivensCache_XD() { long i; for (i = 0; i < sz; i++) delete [] buf[i]; delete [] buf; delete [] bl; delete [] bv; } void GivensCache_XD::flush() { long i; for (i = 0; i < sz; i++) bl[i] = 0; } void GivensCache_XD::selective_flush(long l) { long i; for (i = 0; i < sz; i++) if (bl[i] && bv[i] >= l) bl[i] = 0; } void GivensCache_XD::swap(long l) { long k = bl[bp]; long i; i = 0; while (i < sz && bl[i] != l) i++; if (i < sz) { bl[bp] = l; bl[i] = k; } else bl[bp] = l; selective_flush(l); } void GivensCache_XD::swap() { swap(bl[bp] - 1); } void GivensCache_XD::touch() { long k = bl[bp]; bl[bp] = 0; selective_flush(k); } void GivensCache_XD::incr() { long k = bl[bp]; long k1 = k+1; long i; i = 0; while (i < sz && bl[i] != k1) i++; if (i < sz) { bp = i; return; } i = 0; while (i < sz && bl[i] != 0) i++; if (i < sz) { bp = i; return; } long max_val = 0; long max_index = 0; for (i = 0; i < sz; i++) { long t = labs(bl[i]-k1); if (t > max_val) { max_val = t; max_index = i; } } bp = max_index; bl[max_index] = 0; } static void GivensComputeGS(xdouble **B1, xdouble **mu, xdouble **aux, long k, long n, GivensCache_XD& cache) { long i, j; xdouble c, s, a, b, t; xdouble *p = mu[k]; xdouble *pp = cache.buf[cache.bp]; if (!cache.bl[cache.bp]) { for (j = 1; j <= n; j++) pp[j] = B1[k][j]; long backoff; backoff = k/4; if (backoff < 2) backoff = 2; else if (backoff > cache.sz + 2) backoff = cache.sz + 2; long ub = k-(backoff-1); for (i = 1; i < ub; i++) { xdouble *cptr = mu[i]; xdouble *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*pp[j-1] - s*pp[j]; b = s*pp[j-1] + c*pp[j]; pp[j-1] = a; pp[j] = b; } pp[i] = pp[i]/mu[i][i]; } cache.bl[cache.bp] = k; cache.bv[cache.bp] = k-backoff; } for (j = 1; j <= n; j++) p[j] = pp[j]; for (i = max(cache.bv[cache.bp]+1, 1); i < k; i++) { xdouble *cptr = mu[i]; xdouble *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*p[j-1] - s*p[j]; b = s*p[j-1] + c*p[j]; p[j-1] = a; p[j] = b; } p[i] = p[i]/mu[i][i]; } for (j = n; j > k; j--) { a = p[j-1]; b = p[j]; if (b == 0) { c = 1; s = 0; } else if (fabs(b) > fabs(a)) { t = -a/b; s = 1/sqrt(1 + t*t); c = s*t; } else { t = -b/a; c = 1/sqrt(1 + t*t); s = c*t; } p[j-1] = c*a - s*b; p[j] = c; aux[k][j] = s; } if (k > n+1) Error("G_LLL_XD: internal error"); if (k > n) p[k] = 0; } NTL_THREAD_LOCAL static xdouble red_fudge = to_xdouble(0); NTL_THREAD_LOCAL static long log_red = 0; static void init_red_fudge() { long i; log_red = long(0.50*NTL_DOUBLE_PRECISION); red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { red_fudge = red_fudge * 2; log_red--; cerr << "G_LLL_XD: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) Error("G_LLL_XD: can not continue...sorry"); } NTL_THREAD_LOCAL static long verbose = 0; NTL_THREAD_LOCAL static unsigned long NumSwaps = 0; NTL_THREAD_LOCAL static double StartTime = 0; NTL_THREAD_LOCAL static double LastTime = 0; static void G_LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- G_LLL_XD status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static long ll_G_LLL_XD(mat_ZZ& B, mat_ZZ* U, xdouble delta, long deep, LLLCheckFct check, xdouble **B1, xdouble **mu, xdouble **aux, long m, long init_k, long &quit, GivensCache_XD& cache) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; xdouble mu1; xdouble t1; ZZ T1; xdouble *tp; xdouble half = to_xdouble(0.5); xdouble half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; cache.flush(); while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_LLLStatus(max_k, tt, m, B); } GivensComputeGS(B1, mu, aux, k, n, cache); counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "G_LLL_XD: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = k-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-half); else mu1 = floor(mu1+half); xdouble *mu_k = mu[k]; xdouble *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) MulSub(mu_k[i], mu_k[i], mu1, mu_j[i]); } mu_k[j] -= mu1; conv(MU, mu1); // cout << j << " " << MU << "\n"; RowTransform(B(k), B(j), MU); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1[k][i], B(k, i)); cache.touch(); GivensComputeGS(B1, mu, aux, k, n, cache); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(B(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; if (U) swap((*U)(i), (*U)(i+1)); } cache.flush(); m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions Error("sorry...deep insertions not implemented"); } // end deep insertions // test G_LLL reduction condition if (k > 1 && (delta - mu[k][k-1]*mu[k][k-1])*(mu[k-1][k-1])*(mu[k-1][k-1]) > (mu[k][k])*(mu[k][k])) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; if (U) swap((*U)(k), (*U)(k-1)); cache.swap(); k--; NumSwaps++; // cout << "- " << k << "\n"; } else { cache.incr(); k++; // cout << "+ " << k << "\n"; } } if (verbose) { G_LLLStatus(m+1, GetTime(), m, B); } return m; } static long G_LLL_XD(mat_ZZ& B, mat_ZZ* U, xdouble delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; xdouble s; ZZ MU; xdouble mu1; xdouble t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); xdouble **B1; // approximates B typedef xdouble *xdoubleptr; B1 = NTL_NEW_OP xdoubleptr[m+1]; if (!B1) Error("G_LLL_XD: out of memory"); for (i = 1; i <= m; i++) { B1[i] = NTL_NEW_OP xdouble[n+1]; if (!B1[i]) Error("G_LLL_XD: out of memory"); } xdouble **mu; mu = NTL_NEW_OP xdoubleptr[m+1]; if (!mu) Error("G_LLL_XD: out of memory"); for (i = 1; i <= m; i++) { mu[i] = NTL_NEW_OP xdouble[n+2]; if (!mu[i]) Error("G_LLL_XD: out of memory"); } xdouble **aux; aux = NTL_NEW_OP xdoubleptr[m+1]; if (!aux) Error("G_LLL_XD: out of memory"); for (i = 1; i <= m; i++) { aux[i] = NTL_NEW_OP xdouble[n+1]; if (!aux[i]) Error("G_LLL_XD: out of memory"); } for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1[i][j], B(i, j)); GivensCache_XD cache(m, n); new_m = ll_G_LLL_XD(B, U, delta, deep, check, B1, mu, aux, m, 1, quit, cache); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } // clean-up for (i = 1; i <= m+dep; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m+dep; i++) { delete [] mu[i]; } delete [] mu; for (i = 1; i <= m+dep; i++) { delete [] aux[i]; } delete [] aux; return m; } long G_LLL_XD(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_LLL_XD: bad delta"); if (deep < 0) Error("G_LLL_XD: bad deep"); return G_LLL_XD(B, 0, to_xdouble(delta), deep, check); } long G_LLL_XD(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_LLL_XD: bad delta"); if (deep < 0) Error("G_LLL_XD: bad deep"); return G_LLL_XD(B, &U, to_xdouble(delta), deep, check); } NTL_THREAD_LOCAL static vec_xdouble G_BKZConstant; static void ComputeG_BKZConstant(long beta, long p) { const double c_PI = 3.14159265358979323846264338328; const double LogPI = 1.14472988584940017414342735135; G_BKZConstant.SetLength(beta-1); vec_double Log; Log.SetLength(beta); long i, j, k; double x, y; for (j = 1; j <= beta; j++) Log(j) = log(double(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/double(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/double(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/double(i))*Log(2); y = exp(y); G_BKZConstant(i) = x*y/c_PI; } } NTL_THREAD_LOCAL static vec_xdouble G_BKZThresh; static void ComputeG_BKZThresh(xdouble *c, long beta) { G_BKZThresh.SetLength(beta-1); long i; double x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); G_BKZThresh(i) = xexp(x/double(i))*G_BKZConstant(i); } } static void G_BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- G_BKZ_XD status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long G_BKZ_XD(mat_ZZ& BB, mat_ZZ* UU, xdouble delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; xdouble t1; ZZ T1; xdouble *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); xdouble **B1; // approximates B typedef xdouble *xdoubleptr; B1 = NTL_NEW_OP xdoubleptr[m+2]; if (!B1) Error("G_BKZ_XD: out of memory"); for (i = 1; i <= m+1; i++) { B1[i] = NTL_NEW_OP xdouble[n+1]; if (!B1[i]) Error("G_BKZ_XD: out of memory"); } xdouble **mu; mu = NTL_NEW_OP xdoubleptr[m+2]; if (!mu) Error("G_BKZ_XD: out of memory"); for (i = 1; i <= m+1; i++) { mu[i] = NTL_NEW_OP xdouble[n+2]; if (!mu[i]) Error("G_BKZ_XD: out of memory"); } xdouble **aux; aux = NTL_NEW_OP xdoubleptr[m+2]; if (!aux) Error("G_BKZ_XD: out of memory"); for (i = 1; i <= m+1; i++) { aux[i] = NTL_NEW_OP xdouble[n+1]; if (!aux[i]) Error("G_BKZ_XD: out of memory"); } xdouble *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP xdouble[m+2]; if (!c) Error("G_BKZ_XD: out of memory"); xdouble cbar; xdouble *ctilda; ctilda = NTL_NEW_OP xdouble[m+2]; if (!ctilda) Error("G_BKZ_XD: out of memory"); xdouble *vvec; vvec = NTL_NEW_OP xdouble[m+2]; if (!vvec) Error("G_BKZ_XD: out of memory"); xdouble *yvec; yvec = NTL_NEW_OP xdouble[m+2]; if (!yvec) Error("G_BKZ_XD: out of memory"); xdouble *uvec; uvec = NTL_NEW_OP xdouble[m+2]; if (!uvec) Error("G_BKZ_XD: out of memory"); xdouble *utildavec; utildavec = NTL_NEW_OP xdouble[m+2]; if (!utildavec) Error("G_BKZ_XD: out of memory"); long *Deltavec; Deltavec = NTL_NEW_OP long[m+2]; if (!Deltavec) Error("G_BKZ_XD: out of memory"); long *deltavec; deltavec = NTL_NEW_OP long[m+2]; if (!deltavec) Error("G_BKZ_XD: out of memory"); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; xdouble eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1[i][j], B(i, j)); // cerr << "\n"; // cerr << "first G_LLL\n"; GivensCache_XD cache(m, n); m = ll_G_LLL_XD(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } long clean = 1; if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) c[i] = mu[i][i]*mu[i][i]; if (prune > 0) ComputeG_BKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; if (prune > 0 && t > jj) { eta = G_BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*mu[i][t]; } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta-8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("G_BKZ_XD: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } // cerr << "special case\n"; new_m = ll_G_LLL_XD(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) Error("G_BKZ_XD: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } for (i = 1; i <= n; i++) conv(B1[jj][i], B(jj, i)); if (IsZero(B(jj))) Error("G_BKZ_XD: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_XD(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) Error("G_BKZ_XD: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_XD(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_XD: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_XD // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_XD(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) Error("G_BKZ_XD: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } for (i = 1; i <= m_orig+1; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m_orig+1; i++) { delete [] mu[i]; } delete [] mu; for (i = 1; i <= m_orig+1; i++) { delete [] aux[i]; } delete [] aux; delete [] c; delete [] ctilda; delete [] vvec; delete [] yvec; delete [] uvec; delete [] utildavec; delete [] Deltavec; delete [] deltavec; return m; } long G_BKZ_XD(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_XD: bad delta"); if (beta < 2) Error("G_BKZ_XD: bad block size"); return G_BKZ_XD(BB, &UU, to_xdouble(delta), beta, prune, check); } long G_BKZ_XD(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("G_BKZ_XD: bad delta"); if (beta < 2) Error("G_BKZ_XD: bad block size"); return G_BKZ_XD(BB, 0, to_xdouble(delta), beta, prune, check); } NTL_END_IMPL ntl-6.2.1/src/GetTime1.c000644 000765 000024 00000000645 12377144456 015212 0ustar00shoupstaff000000 000000 #include #include #include // FIXME: it would be nice to have a per-thread // timing function, but it seems very difficult // to get a cross-platform solution to this. double _ntl_GetTime() { struct rusage used; getrusage(RUSAGE_SELF, &used); return (used.ru_utime.tv_sec + used.ru_stime.tv_sec + (used.ru_utime.tv_usec + used.ru_stime.tv_usec) / 1e6); } ntl-6.2.1/src/GetTime2.c000644 000765 000024 00000000626 12377144456 015212 0ustar00shoupstaff000000 000000 #include #include #include // some (old?) Solaris systems don't seem // to supply a getrusage prototype extern "C" int getrusage(int, struct rusage*); double _ntl_GetTime() { struct rusage used; getrusage(RUSAGE_SELF, &used); return (used.ru_utime.tv_sec + used.ru_stime.tv_sec + (used.ru_utime.tv_usec + used.ru_stime.tv_usec) / 1e6); } ntl-6.2.1/src/GetTime3.c000644 000765 000024 00000000473 12377144456 015213 0ustar00shoupstaff000000 000000 #include #include #include #include double _ntl_GetTime() { struct rusage used; syscall(SYS_getrusage, RUSAGE_SELF, &used); return (used.ru_utime.tv_sec + used.ru_stime.tv_sec + (used.ru_utime.tv_usec + used.ru_stime.tv_usec) / 1e6); } ntl-6.2.1/src/GetTime4.c000644 000765 000024 00000001547 12377144457 015220 0ustar00shoupstaff000000 000000 #include #include #include // FIXME: this is the GetTime that ends up getting used // on Windows. However, it returns the wall time, not CPU time. // We could perhaps switch to using GetProcessTimes. // See: http://nadeausoftware.com/articles/2012/03/c_c_tip_how_measure_cpu_time_benchmarking // NOTE: in this version, because clock_t can overflow fairly // quickly (in less than an hour on some systems), we provide // a partial work-around, by tracking the differences between calls double _ntl_GetTime() { NTL_THREAD_LOCAL static clock_t last_clock = 0; NTL_THREAD_LOCAL static double acc = 0; clock_t this_clock; double delta; this_clock = clock(); delta = (this_clock - last_clock)/((double)CLOCKS_PER_SEC); if (delta < 0) delta = 0; acc += delta; last_clock = this_clock; return acc; } ntl-6.2.1/src/GetTime5.c000644 000765 000024 00000000101 12377144457 015202 0ustar00shoupstaff000000 000000 #include double _ntl_GetTime() { return 0; } ntl-6.2.1/src/HNF.c000644 000765 000024 00000004532 12377144456 014205 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL // This implements a variation of an algorithm in // [P. Domich, R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987]. // I started with the description in Henri Cohen's book, but had to modify // that because Cohen does not actually keep the numbers reduced modulo // the determinant, which leads to larger than necessary numbers. // This modifiaction was put in place in v3.9b. static void EuclUpdate(vec_ZZ& u, vec_ZZ& v, const ZZ& a, const ZZ& b, const ZZ& c, const ZZ& d, const ZZ& M) { long m = u.length(); long i; ZZ M1; RightShift(M1, M, 1); ZZ t1, t2, t3; for (i = 1; i <= m; i++) { mul(t1, u(i), a); mul(t2, v(i), b); add(t1, t1, t2); rem(t1, t1, M); if (t1 > M1) sub(t1, t1, M); t3 = t1; mul(t1, u(i), c); mul(t2, v(i), d); add(t1, t1, t2); rem(t1, t1, M); if (t1 > M1) sub(t1, t1, M); u(i) = t3; v(i) = t1; } } static void FixDiag(vec_ZZ& u, const ZZ& a, const vec_ZZ& v, const ZZ& M, long m) { long i; ZZ t1; for (i = 1; i <= m; i++) { mul(t1, a, v(i)); rem(u(i), t1, M); } } static void ReduceW(vec_ZZ& u, const ZZ& a, const vec_ZZ& v, const ZZ& M, long m) { long i; ZZ t1, t2; for (i = 1; i <= m; i++) { mul(t1, a, v(i)); sub(t2, u(i), t1); rem(u(i), t2, M); } } void HNF(mat_ZZ& W, const mat_ZZ& A_in, const ZZ& D_in) { mat_ZZ A = A_in; long n = A.NumRows(); long m = A.NumCols(); ZZ D = D_in; if (D < 0) negate(D, D); if (n == 0 || m == 0 || D == 0) Error("HNF: bad input"); W.SetDims(m, m); clear(W); long i, j, k; ZZ d, u, v, c1, c2; k = n; for (i = m; i >= 1; i--) { for (j = k-1; j >= 1; j--) { if (A(j, i) != 0) { XGCD(d, u, v, A(k, i), A(j, i)); div(c1, A(k, i), d); div(c2, A(j, i), d); negate(c2, c2); EuclUpdate(A(j), A(k), c1, c2, v, u, D); } } XGCD(d, u, v, A(k, i), D); FixDiag(W(i), u, A(k), D, i); if (W(i, i) == 0) W(i, i) = D; for (j = i+1; j <= m; j++) { div(c1, W(j, i), W(i, i)); ReduceW(W(j), c1, W(i), D, i); } div(D, D, d); k--; } } NTL_END_IMPL ntl-6.2.1/src/InitSettings.c000644 000765 000024 00000003662 12377144457 016222 0ustar00shoupstaff000000 000000 #include #if (defined(NTL_STD_CXX) || defined(NTL_PSTD_NHF)) #include using namespace std; #else #include #endif #define make_string_aux(x) #x #define make_string(x) make_string_aux(x) int main() { #ifdef NTL_STD_CXX cout << "NTL_STD_CXX=1\n"; #else cout << "NTL_STD_CXX=0\n"; #endif #ifdef NTL_PSTD_NNS cout << "NTL_PSTD_NNS=1\n"; #else cout << "NTL_PSTD_NNS=0\n"; #endif #ifdef NTL_PSTD_NHF cout << "NTL_PSTD_NHF=1\n"; #else cout << "NTL_PSTD_NHF=0\n"; #endif #ifdef NTL_PSTD_NTN cout << "NTL_PSTD_NTN=1\n"; #else cout << "NTL_PSTD_NTN=0\n"; #endif #ifdef NTL_GMP_LIP cout << "NTL_GMP_LIP=1\n"; #else cout << "NTL_GMP_LIP=0\n"; #endif #ifdef NTL_GF2X_LIB cout << "NTL_GF2X_LIB=1\n"; #else cout << "NTL_GF2X_LIB=0\n"; #endif #ifdef NTL_LONG_LONG_TYPE cout << "FLAG_LONG_LONG_TYPE=1\n"; cout << "NTL_LONG_LONG_TYPE=" make_string(NTL_LONG_LONG_TYPE) "\n"; #else cout << "FLAG_LONG_LONG_TYPE=0\n"; cout << "NTL_LONG_LONG_TYPE=long long\n"; #endif #ifdef NTL_UNSIGNED_LONG_LONG_TYPE cout << "FLAG_UNSIGNED_LONG_LONG_TYPE=1\n"; cout << "NTL_UNSIGNED_LONG_LONG_TYPE=" make_string(NTL_UNSIGNED_LONG_LONG_TYPE) "\n"; #else cout << "FLAG_UNSIGNED_LONG_LONG_TYPE=0\n"; cout << "NTL_UNSIGNED_LONG_LONG_TYPE=unsigned long long\n"; #endif #ifdef NTL_X86_FIX cout << "NTL_X86_FIX=1\n"; #else cout << "NTL_X86_FIX=0\n"; #endif #ifdef NTL_NO_X86_FIX cout << "NTL_NO_X86_FIX=1\n"; #else cout << "NTL_NO_X86_FIX=0\n"; #endif #ifdef NTL_NO_INIT_TRANS cout << "NTL_NO_INIT_TRANS=1\n"; #else cout << "NTL_NO_INIT_TRANS=0\n"; #endif #ifdef NTL_CLEAN_INT cout << "NTL_CLEAN_INT=1\n"; #else cout << "NTL_CLEAN_INT=0\n"; #endif #ifdef NTL_CLEAN_PTR cout << "NTL_CLEAN_PTR=1\n"; #else cout << "NTL_CLEAN_PTR=0\n"; #endif #ifdef NTL_RANGE_CHECK cout << "NTL_RANGE_CHECK=1\n"; #else cout << "NTL_RANGE_CHECK=0\n"; #endif return 0; } ntl-6.2.1/src/LLL.c000644 000765 000024 00000031350 12377144456 014213 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL static void ExactDiv(ZZ& qq, const ZZ& a, const ZZ& b) { NTL_ZZRegister(q); NTL_ZZRegister(r); DivRem(q, r, a, b); if (!IsZero(r)) { cerr << "a = " << a << "\n"; cerr << "b = " << b << "\n"; Error("ExactDiv: nonzero remainder"); } qq = q; } static void BalDiv(ZZ& q, const ZZ& a, const ZZ& d) // rounds a/d to nearest integer, breaking ties // by rounding towards zero. Assumes d > 0. { NTL_ZZRegister(r); DivRem(q, r, a, d); add(r, r, r); long cmp = compare(r, d); if (cmp > 0 || (cmp == 0 && q < 0)) add(q, q, 1); } static void MulAddDiv(ZZ& c, const ZZ& c1, const ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 + y*c2)/z { NTL_ZZRegister(t1); NTL_ZZRegister(t2); mul(t1, x, c1); mul(t2, y, c2); add(t1, t1, t2); ExactDiv(c, t1, z); } static void MulSubDiv(ZZ& c, const ZZ& c1, const ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 - y*c2)/z { NTL_ZZRegister(t1); NTL_ZZRegister(t2); mul(t1, x, c1); mul(t2, y, c2); sub(t1, t1, t2); ExactDiv(c, t1, z); } #if 0 static void MulSubDiv(vec_ZZ& c, const vec_ZZ& c1, const vec_ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 + y*c2)/z { long n = c1.length(); if (c2.length() != n) Error("MulSubDiv: length mismatch"); c.SetLength(n); long i; for (i = 1; i <= n; i++) MulSubDiv(c(i), c1(i), c2(i), x, y, z); } #endif static void RowTransform(vec_ZZ& c1, vec_ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& u, const ZZ& v) // (c1, c2) = (x*c1 + y*c2, u*c1 + v*c2) { long n = c1.length(); if (c2.length() != n) Error("MulSubDiv: length mismatch"); NTL_ZZRegister(t1); NTL_ZZRegister(t2); NTL_ZZRegister(t3); NTL_ZZRegister(t4); long i; for (i = 1; i <= n; i++) { mul(t1, x, c1(i)); mul(t2, y, c2(i)); add(t1, t1, t2); mul(t3, u, c1(i)); mul(t4, v, c2(i)); add(t3, t3, t4); c1(i) = t1; c2(i) = t3; } } static void RowTransform(ZZ& c1, ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& u, const ZZ& v) // (c1, c2) = (x*c1 + y*c2, u*c1 + v*c2) { NTL_ZZRegister(t1); NTL_ZZRegister(t2); NTL_ZZRegister(t3); NTL_ZZRegister(t4); mul(t1, x, c1); mul(t2, y, c2); add(t1, t1, t2); mul(t3, u, c1); mul(t4, v, c2); add(t3, t3, t4); c1 = t1; c2 = t3; } static void MulSubFrom(vec_ZZ& c, const vec_ZZ& c2, const ZZ& x) // c = c - x*c2 { long n = c.length(); if (c2.length() != n) Error("MulSubFrom: length mismatch"); long i; for (i = 1; i <= n; i++) MulSubFrom(c(i), c2(i), x); } static void MulSubFrom(vec_ZZ& c, const vec_ZZ& c2, long x) // c = c - x*c2 { long n = c.length(); if (c2.length() != n) Error("MulSubFrom: length mismatch"); long i; for (i = 1; i <= n; i++) MulSubFrom(c(i), c2(i), x); } static long SwapTest(const ZZ& d0, const ZZ& d1, const ZZ& d2, const ZZ& lam, long a, long b) // test if a*d1^2 > b*(d0*d2 + lam^2) { NTL_ZZRegister(t1); NTL_ZZRegister(t2); mul(t1, d0, d2); sqr(t2, lam); add(t1, t1, t2); mul(t1, t1, b); sqr(t2, d1); mul(t2, t2, a); return t2 > t1; } static void reduce(long k, long l, mat_ZZ& B, vec_long& P, vec_ZZ& D, vec_vec_ZZ& lam, mat_ZZ* U) { NTL_ZZRegister(t1); NTL_ZZRegister(r); if (P(l) == 0) return; add(t1, lam(k)(P(l)), lam(k)(P(l))); abs(t1, t1); if (t1 <= D[P(l)]) return; long j; long rr, small_r; BalDiv(r, lam(k)(P(l)), D[P(l)]); if (r.WideSinglePrecision()) { small_r = 1; rr = to_long(r); } else { small_r = 0; } if (small_r) { MulSubFrom(B(k), B(l), rr); if (U) MulSubFrom((*U)(k), (*U)(l), rr); for (j = 1; j <= l-1; j++) if (P(j) != 0) MulSubFrom(lam(k)(P(j)), lam(l)(P(j)), rr); MulSubFrom(lam(k)(P(l)), D[P(l)], rr); } else { MulSubFrom(B(k), B(l), r); if (U) MulSubFrom((*U)(k), (*U)(l), r); for (j = 1; j <= l-1; j++) if (P(j) != 0) MulSubFrom(lam(k)(P(j)), lam(l)(P(j)), r); MulSubFrom(lam(k)(P(l)), D[P(l)], r); } } static long swap(long k, mat_ZZ& B, vec_long& P, vec_ZZ& D, vec_vec_ZZ& lam, mat_ZZ* U, long m, long verbose) // swaps vectors k-1 and k; assumes P(k-1) != 0 // returns 1 if vector k-1 need to be reduced after the swap... // this only occurs in 'case 2' when there are linear dependencies { long i, j; NTL_ZZRegister(t1); NTL_ZZRegister(t2); NTL_ZZRegister(t3); NTL_ZZRegister(e); NTL_ZZRegister(x); NTL_ZZRegister(y); if (P(k) != 0) { if (verbose) cerr << "swap case 1: " << k << "\n"; swap(B(k-1), B(k)); if (U) swap((*U)(k-1), (*U)(k)); for (j = 1; j <= k-2; j++) if (P(j) != 0) swap(lam(k-1)(P(j)), lam(k)(P(j))); for (i = k+1; i <= m; i++) { MulAddDiv(t1, lam(i)(P(k)-1), lam(i)(P(k)), lam(k)(P(k)-1), D[P(k)-2], D[P(k)-1]); MulSubDiv(t2, lam(i)(P(k)-1), lam(i)(P(k)), D[P(k)], lam(k)(P(k)-1), D[P(k)-1]); lam(i)(P(k)-1) = t1; lam(i)(P(k)) = t2; } MulAddDiv(D[P(k)-1], D[P(k)], lam(k)(P(k)-1), D[P(k)-2], lam(k)(P(k)-1), D[P(k)-1]); return 0; } else if (!IsZero(lam(k)(P(k-1)))) { if (verbose) cerr << "swap case 2: " << k << "\n"; XGCD(e, x, y, lam(k)(P(k-1)), D[P(k-1)]); ExactDiv(t1, lam(k)(P(k-1)), e); ExactDiv(t2, D[P(k-1)], e); t3 = t2; negate(t2, t2); RowTransform(B(k-1), B(k), t1, t2, y, x); if (U) RowTransform((*U)(k-1), (*U)(k), t1, t2, y, x); for (j = 1; j <= k-2; j++) if (P(j) != 0) RowTransform(lam(k-1)(P(j)), lam(k)(P(j)), t1, t2, y, x); sqr(t2, t2); ExactDiv(D[P(k-1)], D[P(k-1)], t2); for (i = k+1; i <= m; i++) if (P(i) != 0) { ExactDiv(D[P(i)], D[P(i)], t2); for (j = i+1; j <= m; j++) { ExactDiv(lam(j)(P(i)), lam(j)(P(i)), t2); } } for (i = k+1; i <= m; i++) { ExactDiv(lam(i)(P(k-1)), lam(i)(P(k-1)), t3); } swap(P(k-1), P(k)); return 1; } else { if (verbose) cerr << "swap case 3: " << k << "\n"; swap(B(k-1), B(k)); if (U) swap((*U)(k-1), (*U)(k)); for (j = 1; j <= k-2; j++) if (P(j) != 0) swap(lam(k-1)(P(j)), lam(k)(P(j))); swap(P(k-1), P(k)); return 0; } } static void IncrementalGS(mat_ZZ& B, vec_long& P, vec_ZZ& D, vec_vec_ZZ& lam, long& s, long k) { long n = B.NumCols(); long m = B.NumRows(); NTL_ZZRegister(u); NTL_ZZRegister(t1); NTL_ZZRegister(t2); long i, j; for (j = 1; j <= k-1; j++) { long posj = P(j); if (posj == 0) continue; InnerProduct(u, B(k), B(j)); for (i = 1; i <= posj-1; i++) { mul(t1, D[i], u); mul(t2, lam(k)(i), lam(j)(i)); sub(t1, t1, t2); div(t1, t1, D[i-1]); u = t1; } lam(k)(posj) = u; } InnerProduct(u, B(k), B(k)); for (i = 1; i <= s; i++) { mul(t1, D[i], u); mul(t2, lam(k)(i), lam(k)(i)); sub(t1, t1, t2); div(t1, t1, D[i-1]); u = t1; } if (u == 0) { P(k) = 0; } else { s++; P(k) = s; D[s] = u; } } static long LLL(vec_ZZ& D, mat_ZZ& B, mat_ZZ* U, long a, long b, long verbose) { long m = B.NumRows(); long n = B.NumCols(); long force_reduce = 1; vec_long P; P.SetLength(m); D.SetLength(m+1); D[0] = 1; vec_vec_ZZ lam; lam.SetLength(m); long j; for (j = 1; j <= m; j++) lam(j).SetLength(m); if (U) ident(*U, m); long s = 0; long k = 1; long max_k = 0; while (k <= m) { if (k > max_k) { IncrementalGS(B, P, D, lam, s, k); max_k = k; } if (k == 1) { force_reduce = 1; k++; continue; } if (force_reduce) for (j = k-1; j >= 1; j--) reduce(k, j, B, P, D, lam, U); if (P(k-1) != 0 && (P(k) == 0 || SwapTest(D[P(k)], D[P(k)-1], D[P(k)-2], lam(k)(P(k)-1), a, b))) { force_reduce = swap(k, B, P, D, lam, U, max_k, verbose); k--; } else { force_reduce = 1; k++; } } D.SetLength(s+1); return s; } static long image(ZZ& det, mat_ZZ& B, mat_ZZ* U, long verbose) { long m = B.NumRows(); long n = B.NumCols(); long force_reduce = 1; vec_long P; P.SetLength(m); vec_ZZ D; D.SetLength(m+1); D[0] = 1; vec_vec_ZZ lam; lam.SetLength(m); long j; for (j = 1; j <= m; j++) lam(j).SetLength(m); if (U) ident(*U, m); long s = 0; long k = 1; long max_k = 0; while (k <= m) { if (k > max_k) { IncrementalGS(B, P, D, lam, s, k); max_k = k; } if (k == 1) { force_reduce = 1; k++; continue; } if (force_reduce) for (j = k-1; j >= 1; j--) reduce(k, j, B, P, D, lam, U); if (P(k-1) != 0 && P(k) == 0) { force_reduce = swap(k, B, P, D, lam, U, max_k, verbose); k--; } else { force_reduce = 1; k++; } } det = D[s]; return s; } long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose) { vec_ZZ D; long s; s = LLL(D, B, &U, 3, 4, verbose); det = D[s]; return s; } long LLL(ZZ& det, mat_ZZ& B, long verbose) { vec_ZZ D; long s; s = LLL(D, B, 0, 3, 4, verbose); det = D[s]; return s; } long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose) { if (a <= 0 || b <= 0 || a > b || b/4 >= a) Error("LLL: bad args"); vec_ZZ D; long s; s = LLL(D, B, &U, a, b, verbose); det = D[s]; return s; } long LLL(ZZ& det, mat_ZZ& B, long a, long b, long verbose) { if (a <= 0 || b <= 0 || a > b || b/4 >= a) Error("LLL: bad args"); vec_ZZ D; long s; s = LLL(D, B, 0, a, b, verbose); det = D[s]; return s; } long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, mat_ZZ& U, long verbose) { vec_ZZ D; long s; s = LLL(D, B, &U, 3, 4, verbose); D_out = D; return s; } long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, long verbose) { vec_ZZ D; long s; s = LLL(D, B, 0, 3, 4, verbose); D_out = D; return s; } long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose) { if (a <= 0 || b <= 0 || a > b || b/4 >= a) Error("LLL_plus: bad args"); vec_ZZ D; long s; s = LLL(D, B, &U, a, b, verbose); D_out = D; return s; } long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, long a, long b, long verbose) { if (a <= 0 || b <= 0 || a > b || b/4 >= a) Error("LLL_plus: bad args"); vec_ZZ D; long s; s = LLL(D, B, 0, a, b, verbose); D_out = D; return s; } long image(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose) { return image(det, B, &U, verbose); } long image(ZZ& det, mat_ZZ& B, long verbose) { return image(det, B, 0, verbose); } long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce) { long n = A.NumRows(); long m = A.NumCols(); if (y.length() != m) Error("LatticeSolve: dimension mismatch"); if (reduce < 0 || reduce > 2) Error("LatticeSolve: bad reduce parameter"); if (IsZero(y)) { x.SetLength(n); clear(x); return 1; } mat_ZZ A1, U1; ZZ det2; long im_rank, ker_rank; A1 = A; im_rank = image(det2, A1, U1); ker_rank = n - im_rank; mat_ZZ A2, U2; long new_rank; long i; A2.SetDims(im_rank + 1, m); for (i = 1; i <= im_rank; i++) A2(i) = A1(ker_rank + i); A2(im_rank + 1) = y; new_rank = image(det2, A2, U2); if (new_rank != im_rank || (U2(1)(im_rank+1) != 1 && U2(1)(im_rank+1) != -1)) return 0; vec_ZZ x1; x1.SetLength(im_rank); for (i = 1; i <= im_rank; i++) x1(i) = U2(1)(i); if (U2(1)(im_rank+1) == 1) negate(x1, x1); vec_ZZ x2, tmp; x2.SetLength(n); clear(x2); tmp.SetLength(n); for (i = 1; i <= im_rank; i++) { mul(tmp, U1(ker_rank+i), x1(i)); add(x2, x2, tmp); } if (reduce == 0) { x = x2; return 1; } else if (reduce == 1) { U1.SetDims(ker_rank+1, n); U1(ker_rank+1) = x2; image(det2, U1); x = U1(ker_rank + 1); return 1; } else if (reduce == 2) { U1.SetDims(ker_rank, n); LLL(det2, U1); U1.SetDims(ker_rank+1, n); U1(ker_rank+1) = x2; image(det2, U1); x = U1(ker_rank + 1); return 1; } return 0; } NTL_END_IMPL ntl-6.2.1/src/LLLTest.c000644 000765 000024 00000005254 12377144457 015060 0ustar00shoupstaff000000 000000 #include NTL_CLIENT int main() { mat_ZZ B; long s; #if 1 cin >> B; #else long i, j; long n; cerr << "n: "; cin >> n; long m; cerr << "m: "; cin >> m; long k; cerr << "k: "; cin >> k; B.SetDims(n, m); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) { RandomLen(B(i,j), k); if (RandomBnd(2)) negate(B(i,j), B(i,j)); } #endif mat_ZZ U, B0, B1, B2; B0 = B; double t; ZZ d; B = B0; cerr << "LLL_FP..."; t = GetTime(); s = LLL_FP(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) Error("bad LLLTest (2)"); B = B0; cerr << "LLL_QP..."; t = GetTime(); s = LLL_QP(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) Error("bad LLLTest (2)"); B = B0; cerr << "LLL_XD..."; t = GetTime(); s = LLL_XD(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) Error("bad LLLTest (2)"); B = B0; cerr << "LLL_RR..."; t = GetTime(); s = LLL_RR(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) Error("bad LLLTest (2)"); B = B0; cerr << "G_LLL_FP..."; t = GetTime(); s = G_LLL_FP(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) Error("bad LLLTest (2)"); B = B0; cerr << "G_LLL_QP..."; t = GetTime(); s = G_LLL_QP(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) Error("bad LLLTest (2)"); B = B0; cerr << "G_LLL_XD..."; t = GetTime(); s = G_LLL_XD(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) Error("bad LLLTest (2)"); B = B0; cerr << "G_LLL_RR..."; t = GetTime(); s = G_LLL_RR(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) Error("bad LLLTest (2)"); B = B0; cerr << "LLL..."; t = GetTime(); s = LLL(d, B, U); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) Error("bad LLLTest (1)"); cout << "rank = " << s << "\n"; cout << "det = " << d << "\n"; cout << "B = " << B << "\n"; cout << "U = " << U << "\n"; } ntl-6.2.1/src/LLLTestIn000644 000765 000024 00000001663 12377144457 015126 0ustar00shoupstaff000000 000000 [[927267 -895605 -866862 -733022 647694 -555086 970641 524600 582869 890322] [-749289 -533762 -754674 -564542 874399 888872 860097 -801459 731651 -920001] [-1008354 -839027 -531044 592717 543848 647360 641018 957632 893065 -813238] [-750708 -783256 -868889 -649872 -807570 579545 840467 -734946 -720279 760893] [648723 -1016200 -587545 -1025537 710862 987663 -1047329 -803105 910327 803227] [-824476 -863571 -978793 -550626 -1000451 -780190 734624 -746905 620723 766901] [-900849 -593349 686359 1031502 832388 835860 -1034307 975079 -541187 -935991] [1015281 -971840 -970316 -851433 848978 -656104 -1044347 1014101 760024 -726970] [674372 -809805 713198 896663 590902 -783974 -651080 627852 1008582 -681953] [617949 -803220 -947289 786228 -540550 635343 -641246 536407 731378 -545576] [-800345 -595182 -795484 -711756 1040656 -709216 -585028 1046975 -555068 -834202] [-855857 -955395 -560560 -784720 810320 906673 657648 865224 -871327 -819494] ] ntl-6.2.1/src/LLLTestOut000644 000765 000024 00000036525 12377144457 015334 0ustar00shoupstaff000000 000000 rank = 10 det = 1 B = [[0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 -1 0 0 0 0 0 0] [1 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0 0 1] [0 0 0 0 0 -1 0 0 0 0] [0 1 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 1 0] [0 0 0 0 -1 0 0 0 0 0] [0 0 0 0 0 0 -1 0 0 0] [0 0 1 0 0 0 0 0 0 0] ] U = [[34654477538697060592273730261281361547125354042773753220424839 28642286990591936277350498595925990982433158292923417688624947 -46292844372743573462683566502729081625278709999456220510041506 -46483581193179866866502987050643114999497045917731148961241548 -30819781133464209851049806557946364538588971500372543352093774 55800458369363297482114583398843232983453109850341699695655921 85229498391108473380429143088097764479688244750584949192968451 44215190928961391993560815775038041607000619023229549814555005 -56225191928762141199604234326567899079861735856027790129591349 -2821038261866733485761289760067843518755252876151402111579092 -56600445704851358896081983000177726626583766185875526650047702 0] [-44233997260522469446630760966822805324915027230445793900466469759669698951691849173534141789641880281231629593715630462491 -36559859916000261740784545629542534300396368966718562880888161447225079537906619812511890470709036923023819006565007070077 59089551959891482174305390308903681612869974820305118965879971390764354535195791774074234539014315392027344972399643936881 59333014063258601208900846773024008569829778426598034900594241114874316807176942590203248943103962849505271914727134722286 39339277664920601829814667137981330171852255478171631432913015028631637094451166058502577427743509963087332978102132712013 -71225350891240604745234148163467114628379186495659185673035976466933787742875646533693468838507251113274610193687025645555 -108789445581401845151765240024205495705983252808075763658353787231418340792157910611357034591406063587534375174967882313739 -56437573824080537369952168169996434511863668021220885631961274608555736934676053780501098026581810918251033094164409424562 71767493333928453425105748941069605855746310582760948904765028225255282167945264249214149704451263342227593036109931588710 3600856443670218308994302975953359579968407731026791968117691834796054492519277872560955703914855475043394551433564729451 72246478321798948850577554837322604664167598323834547771479811997403832547905027333681929696255633027929662067742578983231 -2] [125234120541160085842632749926653225634551766876524582006028424843484622194344320904579593839076411029404574664662280 103507306308365590027731941844086431359931849897778184895383663429734212976552474675311287906480625174713280911796070 -167292773232422692290873819302822809788580775243595360607886223586801568934200920219320139539793909807299946571865339 -167982056686068274771198629623975762574405900229864145018321156388563290848293367974047543703500321756056697397808087 -111376320165568563716960194394217204009497051997154016140407042457009356929790310037864769292832069406625894388081734 201651325485357982987177428627741759299902792422495664374922776611537162429093348402370409973362309815950903742012622 308001794667252566229877100719231320739885156000660615371570077973945762030596461023423400653916810871232997557136660 159784563029835496486081864097482073959471110329746088885480563201812998253921876718515499356728955876875677166062989 -203186224798620884720827760514543747892116556820405494415111131126230598240582006841437806531067375712068132709639097 -10194649316046974623147872141714216501808326519648445055647762247398874459348988827542798424154186365421254334752367 -204542314399908507768050204400982686728664993936396150465899930418015991987429643495566957206595889365562455444467236 0] [117406180154362091704893784913336690477979880467536357921992495076718262314767269465800610097261430551877526673389718 97037431965185887559012922676605420319160080674769369497859390855838086773442869902436519430495301700307644470099817 -156835895742912043834505276761716856620216220455948837576689484072169330962930089070645919481870579319266560657936921 -157482094534315194630350944280907639148675019860016386578358064988608494742302353618213409083875091356825096789041568 -104414581695337104199516758593256656150631980061085066179466246604570244774540083398860127033478158546601957820316608 189046816841889857824529919703125611619464894447684183696344378546425154323022711856741408055999939323119404268759879 288749695660499599304687364907411012977880491651500456730556451199679154887314292361559548458418384377876914670459809 149796997111511904474896701860710428924926799189384533547824516206929039299615462035121863019315993952889513336090450 -190485775046834677583737953925886140274939370647060111612422543129207174767287734478778953367518799193141856139551621 -9557417970743614074200161666047379107650857796491658811031063573656186757249092363542271789262571204111436620148956 -191757100300257955899359220207710378426399506731196957340564333479560530939548121099520261804626622451067507554363017 0] [73035797907264384077316534420898282956915523440058269044064282535678431421994628093967682497961029421433604701746016 60364848435842041921117879698021186285922135359173644461033509004761716380394572231043877636205057555599865940090685 -97564155234621410025624133552441192542313207767418081033424528869476009124672806246048273422760088309009090106859677 -97966141265295328644121770542693765239102796551562119163446725510238003071761558904008924488064290659338565068496890 -64954010744968883036471143150709270576924698601509028795560228245970519820743472249545494316271851527539446620380960 117601859559033634910429000337822326308176042912609036185312781464573883941098699959645771741163601648433405334510815 179624823755590045790591952845455863170943141584331059893377778240813361093280915945443353579875938285753970612777449 93185411481466777188891779348289203097498945293920870500561184425467302748245335505487257097601354445268983530933842 -118497003754298087354915781404459045617256582021951448024985932763497472034023641766065231235211080753949336848293425 -5945459144558948732219203680407171785434064224193181813855869279170462463328659377381532461937249106502560576684314 -119287867183815553129800918062743050747458913189589892309216739151776284517086701782854139263494793319089107314952196 0] [22116948787709292451755413138721499937621477015550187399463111658534488617623454723953276983701528060983112260902487883503 18279888762611296054253726594245795436400797306449304779068322746822808728985535458880689650339032888184073615608554247606 -29544709398260946461414597289584781605061386839569616430645469198301621818162658212095774093091114089590446387689367730747 -29666440175613148096203192662539678219828408353830989207759006299227190283963653699949964146180299346173001374982331394381 -19669594505243413030854403906336544072742227946076287665009332770427542418819281578472395975271609929597793052771952543071 35612595189404014827312653100910247613374630671337597217249287386090047934406649015172875467311834692358198989187389340086 54394600207531234648367619575172013285723048867058373569710215719983131117417842202228289979502291925011129071688657031671 28218723318585481974291578652110737060825667769496011305732812951103464900898179952215567584889398988014847614759250794360 -35883665799865709812516319059015872398539390158641006272137020544727087216277289141230835824630860703705756254642536532272 -1800424164415806231290703180738687586416564250163791135791055881961473408487473823233110267368564458618532565323136728831 -36123157754084096828826529108520741951654074068994587072706523674892820260017731262804924516844091386422555031894574423151 1] [22116830653621455269329674626411237231333121413157877260771090397930206762489851361720911243273767451929856187884282420099 18279791123556041909075925908830851637273283657519891437322185361321102197429374012947504573542399361677591327954021371502 -29544551589996855450677963067392157679443869254136780112428394379143628600464138846222444209460236575630890155348516221094 -29666281717143891705467732813339896546766600449693886805102814652828190257890280434650931653681562254063388162197680820711 -19669489443300768597379753476273166132097435607912366511525700482161871454815355005271391361905596831441503184800390074263 35612404970514031549016136713644509491000005266892172786278762489755441637069471908475698692072977516672625660760817076234 54394309667613614734293552419159883065077688642516640977585399882272310759667200151711241849576401159532215686530231917862 28218572592860556325818374992390914765197304496518115725741311657885647833865968211694999732146914273433174919549646744383 -35883474133096111053263329996097477660410794824552359280155328352138246671173363420934053261939427835577472268504909453428 -1800414547742709738055458978930857855143695843843291531147854531034858091518345202288034474984979093416728299123459454532 -36122964808107143226134762730577956091489643889686636199849623829341228699446234605848428967112410571722733085472857110886 1] [-22117023380848843894955719104751852279167260342562341244588102147725396364737486271559605492399277785601823392747228913780 -18279950414618837531655188544852365185646782426105987540363504650824383191861686249521380836424084969138850962998898485395 29544809042775761995817368936080946712630952784433599128802067610816305258634725980815194933097482721350163922600341502889 29666540230685538723626075013853570545506324890393343787760756085260975475088472251726602859990799036817275799602506662984 19669660844267929164645385989468002112503365473200220495440043099758826047967383984559018056033241228116597598658924968576 -35612715298886939004403301768136001873828323263435140242039463785209734933829719734598728561242091983696417681580185647515 -54394783662493448067695136004038168938701712579958850663398255295035974785741328413108159813590100547731798887218500168752 -28218818490988631749969922548235570768825878496731963303347718291272430620287819880244931503557810700026800198748193389337 35883786823579980661651678621121954803899252344219915842875991760372388584339006075992123931085342566207654712588151189674 1800430236649921214222020230653257220323071011803408768411755740005619963761788931207375877012053019259209084139042397341 36123279585525370798189988095931342561802762312080955538308325854210385432477026910734886131837716589106185637551656424490 -1] [-22116877685835941126068449879581093156316879986795531671412000168217514541225745280456471005097220528629797966180975183514 -18279829996171668640949742120910399838099879919574547338299475711813145813260186707165945382249826805516492588696591997373 29544614417519886724816901953107832462425743018308566011804026585174846333167795048305565480828046063653548497688385384853 29666344803530298977494463562348795770610233864730846307314261420540044916775933640669283262407924039189118245372116171405 19669531271158512452686322981022392967127144032423100227199176837691899475722993080263082682695916547821344885330712436262 -35612480701539654614499931031648241565661080952333248717647741863275093121664274944949666893231588209025582316214258320509 -54394425339016952916271602018519968703971602499883549539435640522904050606323006287764747376334638139380788003303543991192 -28218632600642840213799892006870873703561382912197567715772157189133402781631597407814705923821812691958515900204006464272 35883550440559795915562052093985262043386958585867777192193545816411200764645415450152461262139285129456188186138525980991 1800418376387260987382720314694111287225894201886546400181385999479518025757906522437177939966534204299229200706868902782 36123041624856130801420614393353178598187710244588209189547586240441183040056537127889355422639945446034535458974459336466 -1] [153300751389883906614715908684381595158854815019076330345965058748651401702935137858908440184753029760178436175776411 126704669325322889255155789303293256412204062617542426056038953236258878888078642336167657842284239352332104584617386 -204785307133600825926434947310539905959072578028218815433605540749531852825825065706317237736688008547806253849730194 -205629068170192708496023229829517659217250886529629638446491929871144234919221241905465442433196135071898116245497041 -136337233771768195750865800819175426698042373162934615788134775700140045270064573206827216859721165828160770141236872 246844067591877261901801021470632147053267081469760073274846382835180760806891203047811592085222603991006855646882271 377029090378001311022910299866042631109246528636811983342383233064557544085727080326250391921776065889271142719262077 195594407236064424442510470319951889917030725594690088094850130062786363258143173351832535868737612955693003921996835 -248722958240961065994294913864181843189905849244726166540687462459351767490199361396229100579949739182283697568449591 -12479405720685472871472679567692945622700070662844098966857399677574753129862397644704023430096898152822295568524135 -250382965545129219181227396113613345269638584922714186640342543946336771926751766478153625156845831899729315417747166 0] [301145885839173819969703925479551813714060284167821933699853492199176116578711831992112605650315588049932068866510920 248900214369411457257922182414032693208395856920884823652804586240084496340274134344788924927011673597465847882543276 -402282781815934612630097787584272164188824371923361697829784861696748517383064848502033956699176061679884775285097360 -403940276397646163213060821209201385741465514653213934881581120753320425216660197172071260459590844140665355066530515 -267822542713061851602734767163253276833168588548648525325329956594452875903239142834446226474341945519480441271372013 484903529337861454020020797144731410464811339116524622140159263189250033132961385879210654032167035729974891033194678 740640592949588900414058268737287704350900234998920233112817592621562582316034237140851683599274553158342791390570328 384228064756762946206145773822526049238325477857776979702964428605396119140722353068188655960146888718381949083005303 -488594445290871062793246858987640328764845862805397138586352857562752368868285194578505080188543446932519701074818646 -24514698437089807263685819578779252693447679115202653667306007102834836796754613466881439945875757407900806631737462 -491855384102852680467538672897022957290337831412350521756365759325684235785140881811626973421906591392201175156517166 0] [-22117226546116886109763322378844674622546324478431531135520811093364799400159840054921920560371132378642101991444495496654 -18280118332831059537068894499955495779228723067314165021046052970446590296867097673757907471648548586088198965665579492705 29545080439109033006559438795794252035612382706199285879517042079101293622464404015193348065694130279126870635558928144364 29666812745232097070406529987146813886760386808585192821066868530490495570649424591147935348711988942139718240704905610017 19669841528252790593070716736908131779276597652400348575771848510586757775959546738047964468508521533989044678518519608527 -35613042434538279612693088687007121375294759538525284151480712416479855084589328414372756965781242033206739341540434565345 -54395283328773697061562245921178021577369817175915744351482042640890919485397031773763669422211981196377459202217084356977 -28219077706875138457597460806660379260640059631307801018393953494350195313523278187138079380937456827669589568226031170718 35884116449273404444698288136788131834030229653398959030597574377784837675636371229369314291573973612525744122253682274033 1800446775262976035289944018144445300810930029492874702563867024782422136675722395287536367476434895753122371640566089769 36123611411180802892777524434718239367700912623868195289065665696626684802255818207220263750824955164746347612612248556209 -1] ] ntl-6.2.1/src/LLL_FP.c000644 000765 000024 00000110566 12377144456 014607 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL static inline void CheckFinite(double *p) { if (!IsFinite(p)) Error("LLL_FP: numbers too big...use LLL_XD"); } static double InnerProduct(double *a, double *b, long n) { double s; long i; s = 0; for (i = 1; i <= n; i++) s += a[i]*b[i]; return s; } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } #define TR_BND (NTL_FDOUBLE_PRECISION/2.0) // Just to be safe!! static double max_abs(double *v, long n) { long i; double res, t; res = 0; for (i = 1; i <= n; i++) { t = fabs(v[i]); if (t > res) res = t; } return res; } static void RowTransformStart(double *a, long *in_a, long& in_float, long n) { long i; long inf = 1; for (i = 1; i <= n; i++) { in_a[i] = (a[i] < TR_BND && a[i] > -TR_BND); inf = inf & in_a[i]; } in_float = inf; } static void RowTransformFinish(vec_ZZ& A, double *a, long *in_a) { long n = A.length(); long i; for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); } else { conv(a[i], A(i)); CheckFinite(&a[i]); } } } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1, double *a, double *b, long *in_a, double& max_a, double max_b, long& in_float) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; double mu; conv(mu, MU1); CheckFinite(&mu); long n = A.length(); long i; if (in_float) { double mu_abs = fabs(mu); if (mu_abs > 0 && max_b > 0 && (mu_abs >= TR_BND || max_b >= TR_BND)) { in_float = 0; } else { max_a += mu_abs*max_b; if (max_a >= TR_BND) in_float = 0; } } if (in_float) { if (mu == 1) { for (i = 1; i <= n; i++) a[i] -= b[i]; return; } if (mu == -1) { for (i = 1; i <= n; i++) a[i] += b[i]; return; } if (mu == 0) return; for (i = 1; i <= n; i++) a[i] -= mu*b[i]; return; } MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < TR_BND && b[i] > -TR_BND) { a[i] -= b[i]; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } sub(A(i), A(i), B(i)); } } return; } if (MU == -1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < TR_BND && b[i] > -TR_BND) { a[i] += b[i]; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } add(A(i), A(i), B(i)); } } return; } if (MU == 0) return; double b_bnd = fabs(TR_BND/mu) - 1; if (b_bnd < 0) b_bnd = 0; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < b_bnd && b[i] > -b_bnd) { a[i] -= b[i]*mu; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } MulSubFrom(A(i), B(i), mu1); } } } } else { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } static void ComputeGS(mat_ZZ& B, double **B1, double **mu, double *b, double *c, long k, double bound, long st, double *buf) { long n = B.NumCols(); long i, j; double s, t1, y, t; ZZ T1; long test; double *mu_k = mu[k]; if (st < k) { for (i = 1; i < st; i++) buf[i] = mu_k[i]*c[i]; } for (j = st; j <= k-1; j++) { s = InnerProduct(B1[k], B1[j], n); // test = b[k]*b[j] >= NTL_FDOUBLE_PRECISION^2 test = (b[k]/NTL_FDOUBLE_PRECISION >= NTL_FDOUBLE_PRECISION/b[j]); // test = test && s^2 <= b[k]*b[j]/bound, // but we compute it in a strange way to avoid overflow if (test && (y = fabs(s)) != 0) { t = y/b[j]; t1 = b[k]/y; if (t <= 1) test = (t*bound <= t1); else if (t1 >= 1) test = (t <= t1/bound); else test = 0; } if (test) { InnerProduct(T1, B(k), B(j)); conv(s, T1); } double *mu_j = mu[j]; t1 = 0; for (i = 1; i <= j-1; i++) { t1 += mu_j[i]*buf[i]; } mu_k[j] = (buf[j] = (s - t1))/c[j]; } #if (!NTL_EXT_DOUBLE) // Kahan summation double c1; s = c1 = 0; for (j = 1; j <= k-1; j++) { y = mu_k[j]*buf[j] - c1; t = s+y; c1 = t-s; c1 = c1-y; s = t; } #else s = 0; for (j = 1; j <= k-1; j++) s += mu_k[j]*buf[j]; #endif c[k] = b[k] - s; } NTL_THREAD_LOCAL static double red_fudge = 0; NTL_THREAD_LOCAL static long log_red = 0; NTL_THREAD_LOCAL static long verbose = 0; NTL_THREAD_LOCAL double LLLStatusInterval = 900.0; NTL_THREAD_LOCAL char *LLLDumpFile = 0; NTL_THREAD_LOCAL static unsigned long NumSwaps = 0; NTL_THREAD_LOCAL static double RR_GS_time = 0; NTL_THREAD_LOCAL static double StartTime = 0; NTL_THREAD_LOCAL static double LastTime = 0; static void LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- LLL_FP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static void init_red_fudge() { long i; log_red = long(0.50*NTL_DOUBLE_PRECISION); red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { red_fudge = red_fudge * 2; log_red--; cerr << "LLL_FP: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) Error("LLL_FP: too much loss of precision...stop!"); } #if 0 static void print_mus(double **mu, long k) { long i; for (i = k-1; i >= 1; i--) cerr << mu[k][i] << " "; cerr << "\n"; } #endif void ComputeGS(const mat_ZZ& B, mat_RR& B1, mat_RR& mu, vec_RR& b, vec_RR& c, long k, const RR& bound, long st, vec_RR& buf, const RR& bound2); static void RR_GS(mat_ZZ& B, double **B1, double **mu, double *b, double *c, double *buf, long prec, long rr_st, long k, long m_orig, mat_RR& rr_B1, mat_RR& rr_mu, vec_RR& rr_b, vec_RR& rr_c) { double tt; cerr << "LLL_FP: RR refresh " << rr_st << "..." << k << "..."; tt = GetTime(); if (rr_st > k) Error("LLL_FP: can not continue!!!"); long old_p = RR::precision(); RR::SetPrecision(prec); long n = B.NumCols(); rr_B1.SetDims(k, n); rr_mu.SetDims(k, m_orig); rr_b.SetLength(k); rr_c.SetLength(k); vec_RR rr_buf; rr_buf.SetLength(k); long i, j; for (i = rr_st; i <= k; i++) for (j = 1; j <= n; j++) conv(rr_B1(i, j), B(i, j)); for (i = rr_st; i <= k; i++) InnerProduct(rr_b(i), rr_B1(i), rr_B1(i)); RR bound; power2(bound, 2*long(0.15*RR::precision())); RR bound2; power2(bound2, 2*RR::precision()); for (i = rr_st; i <= k; i++) ComputeGS(B, rr_B1, rr_mu, rr_b, rr_c, i, bound, 1, rr_buf, bound2); for (i = rr_st; i <= k; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], rr_B1(i,j)); CheckFinite(&B1[i][j]); } for (i = rr_st; i <= k; i++) for (j = 1; j <= i-1; j++) { conv(mu[i][j], rr_mu(i,j)); } for (i = rr_st; i <= k; i++) { conv(b[i], rr_b(i)); CheckFinite(&b[i]); } for (i = rr_st; i <= k; i++) { conv(c[i], rr_c(i)); CheckFinite(&c[i]); } for (i = 1; i <= k-1; i++) { conv(buf[i], rr_buf[i]); } RR::SetPrecision(old_p); tt = GetTime()-tt; RR_GS_time += tt; cerr << tt << " (" << RR_GS_time << ")\n"; } void ComputeGS(const mat_ZZ& B, mat_RR& mu, vec_RR& c) { long n = B.NumCols(); long k = B.NumRows(); mat_RR B1; vec_RR b; B1.SetDims(k, n); mu.SetDims(k, k); b.SetLength(k); c.SetLength(k); vec_RR buf; buf.SetLength(k); long i, j; for (i = 1; i <= k; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); for (i = 1; i <= k; i++) InnerProduct(b(i), B1(i), B1(i)); RR bound; power2(bound, 2*long(0.15*RR::precision())); RR bound2; power2(bound2, 2*RR::precision()); for (i = 1; i <= k; i++) ComputeGS(B, B1, mu, b, c, i, bound, 1, buf, bound2); } static long ll_LLL_FP(mat_ZZ& B, mat_ZZ* U, double delta, long deep, LLLCheckFct check, double **B1, double **mu, double *b, double *c, long m, long init_k, long &quit) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; double mu1; double t1; ZZ T1; double *tp; static double bound = 0; if (bound == 0) { // we tolerate a 15% loss of precision in computing // inner products in ComputeGS. bound = 1; for (i = 2*long(0.15*NTL_DOUBLE_PRECISION); i > 0; i--) bound = bound * 2; } double half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long st_mem; st_mem.SetLength(m+2); long *st = st_mem.elts(); for (i = 1; i < k; i++) st[i] = i; for (i = k; i <= m+1; i++) st[i] = 1; double *buf; buf = NTL_NEW_OP double [m+1]; if (!buf) Error("out of memory in lll_LLL_FP"); vec_long in_vec_mem; in_vec_mem.SetLength(n+1); long *in_vec = in_vec_mem.elts(); double *max_b; max_b = NTL_NEW_OP double [m+1]; if (!max_b) Error("out of memory in lll_LLL_FP"); for (i = 1; i <= m; i++) max_b[i] = max_abs(B1[i], n); long in_float; long rst; long counter; long start_over; long trigger_index; long small_trigger; long cnt; mat_RR rr_B1; mat_RR rr_mu; vec_RR rr_c; vec_RR rr_b; long m_orig = m; long rr_st = 1; long max_k = 0; long prec = RR::precision(); double tt; long swap_cnt = 0; while (k <= m) { if (k > max_k) { max_k = k; swap_cnt = 0; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) LLLStatus(max_k, tt, m, B); } if (k < rr_st) rr_st = k; if (st[k] == k) rst = 1; else rst = k; if (st[k] < st[k+1]) st[k+1] = st[k]; ComputeGS(B, B1, mu, b, c, k, bound, st[k], buf); CheckFinite(&c[k]); st[k] = k; if (swap_cnt > 200000) { cerr << "LLL_FP: swap loop?\n"; RR_GS(B, B1, mu, b, c, buf, prec, rr_st, k, m_orig, rr_B1, rr_mu, rr_b, rr_c); if (rr_st < st[k+1]) st[k+1] = rr_st; rr_st = k+1; rst = k; swap_cnt = 0; } counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; long thresh = 10; long sz=0, new_sz; long did_rr_gs = 0; do { // size reduction counter++; if ((counter & 127) == 0) { new_sz = 0; for (j = 1; j <= n; j++) new_sz += NumBits(B(k,j)); if ((counter >> 7) == 1 || new_sz < sz) { sz = new_sz; } else { cerr << "LLL_FP: warning--infinite loop?\n"; } } Fc1 = 0; start_over = 0; for (j = rst-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > thresh) { if (log_red <= 15) { while (log_red > 10) inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; if (!did_rr_gs) { RR_GS(B, B1, mu, b, c, buf, prec, rr_st, k, m_orig, rr_B1, rr_mu, rr_b, rr_c); if (rr_st < st[k+1]) st[k+1] = rr_st; rr_st = k+1; did_rr_gs = 1; rst = k; trigger_index = k; small_trigger = 0; start_over = 1; break; } } else { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } } trigger_index = j; small_trigger = (t1 < 4); Fc1 = 1; if (k < rr_st) rr_st = k; RowTransformStart(B1[k], in_vec, in_float, n); } mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-0.5); else mu1 = floor(mu1+0.5); double *mu_k = mu[k]; double *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) mu_k[i] -= mu1*mu_j[i]; } mu_k[j] -= mu1; conv(MU, mu1); RowTransform(B(k), B(j), MU, B1[k], B1[j], in_vec, max_b[k], max_b[j], in_float); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { RowTransformFinish(B(k), B1[k], in_vec); max_b[k] = max_abs(B1[k], n); if (!did_rr_gs) { b[k] = InnerProduct(B1[k], B1[k], n); CheckFinite(&b[k]); ComputeGS(B, B1, mu, b, c, k, bound, 1, buf); CheckFinite(&c[k]); } else { RR_GS(B, B1, mu, b, c, buf, prec, rr_st, k, m_orig, rr_B1, rr_mu, rr_b, rr_c); rr_st = k+1; } rst = k; } } while (Fc1 || start_over); if (check && (*check)(B(k))) quit = 1; if (b[k] == 0) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; t1 = b[i]; b[i] = b[i+1]; b[i+1] = t1; t1 = max_b[i]; max_b[i] = max_b[i+1]; max_b[i+1] = t1; if (U) swap((*U)(i), (*U)(i+1)); } for (i = k; i <= m+1; i++) st[i] = 1; if (k < rr_st) rr_st = k; m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions double cc = b[k]; long l = 1; while (l <= k-1 && delta*c[l] <= cc) { cc = cc - mu[k][l]*mu[k][l]*c[l]; l++; } if (l <= k-1 && (l <= deep || k-l <= deep)) { // deep insertion at position l for (i = k; i > l; i--) { // swap rows i, i-1 swap(B(i), B(i-1)); tp = B1[i]; B1[i] = B1[i-1]; B1[i-1] = tp; tp = mu[i]; mu[i] = mu[i-1]; mu[i-1] = tp; t1 = b[i]; b[i] = b[i-1]; b[i-1] = t1; t1 = max_b[i]; max_b[i] = max_b[i-1]; max_b[i-1] = t1; if (U) swap((*U)(i), (*U)(i-1)); } k = l; NumSwaps++; swap_cnt++; continue; } } // end deep insertions // test LLL reduction condition if (k > 1 && delta*c[k-1] > c[k] + mu[k][k-1]*mu[k][k-1]*c[k-1]) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; tp = mu[k]; mu[k] = mu[k-1]; mu[k-1] = tp; t1 = b[k]; b[k] = b[k-1]; b[k-1] = t1; t1 = max_b[k]; max_b[k] = max_b[k-1]; max_b[k-1] = t1; if (U) swap((*U)(k), (*U)(k-1)); k--; NumSwaps++; swap_cnt++; // cout << "-\n"; } else { k++; // cout << "+\n"; } } if (verbose) { LLLStatus(m+1, GetTime(), m, B); } delete [] buf; delete [] max_b; return m; } static long LLL_FP(mat_ZZ& B, mat_ZZ* U, double delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; ZZ MU; ZZ T1; init_red_fudge(); if (U) ident(*U, m); double **B1; // approximates B typedef double *doubleptr; B1 = NTL_NEW_OP doubleptr[m+1]; if (!B1) Error("LLL_FP: out of memory"); for (i = 1; i <= m; i++) { B1[i] = NTL_NEW_OP double[n+1]; if (!B1[i]) Error("LLL_FP: out of memory"); } double **mu; mu = NTL_NEW_OP doubleptr[m+1]; if (!mu) Error("LLL_FP: out of memory"); for (i = 1; i <= m; i++) { mu[i] = NTL_NEW_OP double[m+1]; if (!mu[i]) Error("LLL_FP: out of memory"); } double *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP double[m+1]; if (!c) Error("LLL_FP: out of memory"); double *b; // squared lengths of basis vectors b = NTL_NEW_OP double[m+1]; if (!b) Error("LLL_FP: out of memory"); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } new_m = ll_LLL_FP(B, U, delta, deep, check, B1, mu, b, c, m, 1, quit); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } // clean-up for (i = 1; i <= m+dep; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m+dep; i++) { delete [] mu[i]; } delete [] mu; delete [] c; delete [] b; return m; } long LLL_FP(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; RR_GS_time = 0; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("LLL_FP: bad delta"); if (deep < 0) Error("LLL_FP: bad deep"); return LLL_FP(B, 0, delta, deep, check); } long LLL_FP(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; RR_GS_time = 0; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("LLL_FP: bad delta"); if (deep < 0) Error("LLL_FP: bad deep"); return LLL_FP(B, &U, delta, deep, check); } static vec_double BKZConstant; static void ComputeBKZConstant(long beta, long p) { const double c_PI = 3.14159265358979323846264338328; const double LogPI = 1.14472988584940017414342735135; BKZConstant.SetLength(beta-1); vec_double Log; Log.SetLength(beta); long i, j, k; double x, y; for (j = 1; j <= beta; j++) Log(j) = log(double(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/double(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/double(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/double(i))*Log(2); y = exp(y); BKZConstant(i) = x*y/c_PI; } } static vec_double BKZThresh; static void ComputeBKZThresh(double *c, long beta) { BKZThresh.SetLength(beta-1); long i; double x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); BKZThresh(i) = exp(x/double(i))*BKZConstant(i); if (!IsFinite(&BKZThresh(i))) BKZThresh(i) = 0; } } static void BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- BKZ_FP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long BKZ_FP(mat_ZZ& BB, mat_ZZ* UU, double delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; double t1; ZZ T1; double *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); double **B1; // approximates B typedef double *doubleptr; B1 = NTL_NEW_OP doubleptr[m+2]; if (!B1) Error("BKZ_FP: out of memory"); for (i = 1; i <= m+1; i++) { B1[i] = NTL_NEW_OP double[n+1]; if (!B1[i]) Error("BKZ_FP: out of memory"); } double **mu; mu = NTL_NEW_OP doubleptr[m+2]; if (!mu) Error("LLL_FP: out of memory"); for (i = 1; i <= m+1; i++) { mu[i] = NTL_NEW_OP double[m+1]; if (!mu[i]) Error("BKZ_FP: out of memory"); } double *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP double[m+2]; if (!c) Error("BKZ_FP: out of memory"); double *b; // squared lengths of basis vectors b = NTL_NEW_OP double[m+2]; if (!b) Error("BKZ_FP: out of memory"); double cbar; double *ctilda; ctilda = NTL_NEW_OP double[m+2]; if (!ctilda) Error("BKZ_FP: out of memory"); double *vvec; vvec = NTL_NEW_OP double[m+2]; if (!vvec) Error("BKZ_FP: out of memory"); double *yvec; yvec = NTL_NEW_OP double[m+2]; if (!yvec) Error("BKZ_FP: out of memory"); double *uvec; uvec = NTL_NEW_OP double[m+2]; if (!uvec) Error("BKZ_FP: out of memory"); double *utildavec; utildavec = NTL_NEW_OP double[m+2]; if (!utildavec) Error("BKZ_FP: out of memory"); long *Deltavec; Deltavec = NTL_NEW_OP long[m+2]; if (!Deltavec) Error("BKZ_FP: out of memory"); long *deltavec; deltavec = NTL_NEW_OP long[m+2]; if (!deltavec) Error("BKZ_FP: out of memory"); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; double eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } m = ll_LLL_FP(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; ForceToMem(&ctilda[t]); // prevents an infinite loop if (prune > 0 && t > jj) { eta = BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) t1 += utildavec[i]*mu[i][t]; yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta - 8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("BKZ_FP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } // cerr << "special case\n"; new_m = ll_LLL_FP(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) Error("BKZ_FP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } b[jj] = InnerProduct(B1[jj], B1[jj], n); CheckFinite(&b[jj]); if (b[jj] == 0) Error("BKZ_FP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_FP(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) Error("BKZ_FP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_FP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_FP: internal error"); if (quit) break; } } z = 0; } else { // LLL_FP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_FP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_FP: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } for (i = 1; i <= m_orig+1; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m_orig+1; i++) { delete [] mu[i]; } delete [] mu; delete [] c; delete [] b; delete [] ctilda; delete [] vvec; delete [] yvec; delete [] uvec; delete [] utildavec; delete [] Deltavec; delete [] deltavec; return m; } long BKZ_FP(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; RR_GS_time = 0; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_FP: bad delta"); if (beta < 2) Error("BKZ_FP: bad block size"); return BKZ_FP(BB, &UU, delta, beta, prune, check); } long BKZ_FP(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; RR_GS_time = 0; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_FP: bad delta"); if (beta < 2) Error("BKZ_FP: bad block size"); return BKZ_FP(BB, 0, delta, beta, prune, check); } NTL_END_IMPL ntl-6.2.1/src/LLL_QP.c000644 000765 000024 00000130670 12377144456 014620 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL static inline void CheckFinite(double *p) { if (!IsFinite(p)) Error("LLL_QP: numbers too big...use LLL_XD"); } static inline void CheckFinite(quad_float *p) { if (!IsFinite(p)) Error("LLL_QP: numbers too big...use LLL_XD"); } static quad_float InnerProduct(quad_float *a, quad_float *b, long n) { quad_float s; long i; s = 0; for (i = 1; i <= n; i++) s += a[i]*b[i]; return s; } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } #define TR_BND (NTL_FDOUBLE_PRECISION/2.0) // Just to be safe!! static double max_abs(quad_float *v, long n) { long i; double res, t; res = 0; for (i = 1; i <= n; i++) { t = fabs(v[i].hi); if (t > res) res = t; } return res; } static void RowTransformStart(quad_float *a, long *in_a, long& in_float, long n) { long i; long inf = 1; for (i = 1; i <= n; i++) { in_a[i] = (a[i].hi < TR_BND && a[i].hi > -TR_BND); inf = inf & in_a[i]; } in_float = inf; } static void RowTransformFinish(vec_ZZ& A, quad_float *a, long *in_a) { long n = A.length(); long i; for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); } else { conv(a[i], A(i)); CheckFinite(&a[i]); } } } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1, quad_float *a, quad_float *b, long *in_a, double& max_a, double max_b, long& in_float) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; double mu; long n = A.length(); long i; conv(mu, MU1); CheckFinite(&mu); if (in_float) { double mu_abs = fabs(mu); if (mu_abs > 0 && max_b > 0 && (mu_abs >= TR_BND || max_b >= TR_BND)) { in_float = 0; } else { max_a += mu_abs*max_b; if (max_a >= TR_BND) in_float = 0; } } if (in_float) { if (mu == 1) { for (i = 1; i <= n; i++) a[i].hi -= b[i].hi; return; } if (mu == -1) { for (i = 1; i <= n; i++) a[i].hi += b[i].hi; return; } if (mu == 0) return; for (i = 1; i <= n; i++) a[i].hi -= mu*b[i].hi; return; } MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < TR_BND && b[i].hi > -TR_BND) { a[i].hi -= b[i].hi; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } sub(A(i), A(i), B(i)); } } return; } if (MU == -1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < TR_BND && b[i].hi > -TR_BND) { a[i].hi += b[i].hi; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } add(A(i), A(i), B(i)); } } return; } if (MU == 0) return; double b_bnd = fabs(TR_BND/mu) - 1; if (b_bnd < 0) b_bnd = 0; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < b_bnd && b[i].hi > -b_bnd) { a[i].hi -= b[i].hi*mu; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } MulSubFrom(A(i), B(i), mu1); } } } } else { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } static void ComputeGS(mat_ZZ& B, quad_float **B1, quad_float **mu, quad_float *b, quad_float *c, long k, double bound, long st, quad_float *buf) { long n = B.NumCols(); long i, j; quad_float s, t1, y, t; ZZ T1; long test; quad_float *mu_k = mu[k]; if (st < k) { for (i = 1; i < st; i++) buf[i] = mu_k[i]*c[i]; } for (j = st; j <= k-1; j++) { if (b[k].hi/NTL_FDOUBLE_PRECISION < NTL_FDOUBLE_PRECISION/b[j].hi) { // we can compute inner product exactly in double precision double z = 0; quad_float *B1_k = B1[k]; quad_float *B1_j = B1[j]; for (i = 1; i <= n; i++) z += B1_k[i].hi * B1_j[i].hi; s = z; } else { s = InnerProduct(B1[k], B1[j], n); y = fabs(s); if (y.hi == 0) test = (b[k].hi != 0); else { double t = y.hi/b[j].hi; double t1 = b[k].hi/y.hi; if (t <= 1) test = (t*bound <= t1); else if (t1 >= 1) test = (t <= t1/bound); else test = 0; } if (test) { InnerProduct(T1, B(k), B(j)); conv(s, T1); } } quad_float *mu_j = mu[j]; t1 = 0; for (i = 1; i <= j-1; i++) t1 += mu_j[i]*buf[i]; mu_k[j] = (buf[j] = (s - t1))/c[j]; } s = 0; for (j = 1; j <= k-1; j++) s += mu_k[j]*buf[j]; c[k] = b[k] - s; } NTL_THREAD_LOCAL static quad_float red_fudge = to_quad_float(0); NTL_THREAD_LOCAL static long log_red = 0; NTL_THREAD_LOCAL static long verbose = 0; NTL_THREAD_LOCAL static unsigned long NumSwaps = 0; NTL_THREAD_LOCAL static double StartTime = 0; NTL_THREAD_LOCAL static double LastTime = 0; static void LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- LLL_QP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static void init_red_fudge() { long i; // initial log_red should be <= NTL_DOUBLE_PRECISION-2, // to help ensure stability in BKZ_QP1 log_red = NTL_DOUBLE_PRECISION-2; red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { red_fudge = red_fudge * 2; log_red--; cerr << "LLL_QP: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) Error("LLL_QP: too much loss of precision...stop!"); } static long ll_LLL_QP(mat_ZZ& B, mat_ZZ* U, quad_float delta, long deep, LLLCheckFct check, quad_float **B1, quad_float **mu, quad_float *b, quad_float *c, long m, long init_k, long &quit) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; quad_float mu1; quad_float t1; double dt1; ZZ T1; quad_float *tp; NTL_THREAD_LOCAL static double bound = 0; if (bound == 0) { // we tolerate a 15% loss of precision in computing // inner products in ComputeGS. bound = 1; for (i = 2*long(0.15*2*NTL_DOUBLE_PRECISION); i > 0; i--) { bound = bound * 2; } } quad_float half = to_quad_float(0.5); quad_float half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long st_mem; st_mem.SetLength(m+2); long *st = st_mem.elts(); for (i = 1; i < k; i++) st[i] = i; for (i = k; i <= m+1; i++) st[i] = 1; quad_float *buf; buf = NTL_NEW_OP quad_float [m+1]; if (!buf) Error("out of memory in lll_LLL_QP"); vec_long in_vec_mem; in_vec_mem.SetLength(n+1); long *in_vec = in_vec_mem.elts(); double *max_b; max_b = NTL_NEW_OP double [m+1]; if (!max_b) Error("out of memory in lll_LLL_QP"); for (i = 1; i <= m; i++) max_b[i] = max_abs(B1[i], n); long in_float; long rst; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) LLLStatus(max_k, tt, m, B); } if (st[k] == k) rst = 1; else rst = k; if (st[k] < st[k+1]) st[k+1] = st[k]; ComputeGS(B, B1, mu, b, c, k, bound, st[k], buf); CheckFinite(&c[k]); st[k] = k; counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "LLL_QP: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = rst-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); Fc1 = 1; RowTransformStart(B1[k], in_vec, in_float, n); } mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-half); else mu1 = floor(mu1+half); quad_float *mu_k = mu[k]; quad_float *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) mu_k[i] -= mu1*mu_j[i]; } // cout << j << " " << mu[k][j] << " " << mu1 << "\n"; mu_k[j] -= mu1; conv(MU, mu1); RowTransform(B(k), B(j), MU, B1[k], B1[j], in_vec, max_b[k], max_b[j], in_float); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { RowTransformFinish(B(k), B1[k], in_vec); max_b[k] = max_abs(B1[k], n); b[k] = InnerProduct(B1[k], B1[k], n); CheckFinite(&b[k]); ComputeGS(B, B1, mu, b, c, k, bound, 1, buf); CheckFinite(&c[k]); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (b[k] == 0) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; t1 = b[i]; b[i] = b[i+1]; b[i+1] = t1; dt1 = max_b[i]; max_b[i] = max_b[i+1]; max_b[i+1] = dt1; if (U) swap((*U)(i), (*U)(i+1)); } for (i = k; i <= m+1; i++) st[i] = 1; m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions quad_float cc = b[k]; long l = 1; while (l <= k-1 && delta*c[l] <= cc) { cc = cc - mu[k][l]*mu[k][l]*c[l]; l++; } if (l <= k-1 && (l <= deep || k-l <= deep)) { // deep insertion at position l for (i = k; i > l; i--) { // swap rows i, i-1 swap(B(i), B(i-1)); tp = B1[i]; B1[i] = B1[i-1]; B1[i-1] = tp; tp = mu[i]; mu[i] = mu[i-1]; mu[i-1] = tp; t1 = b[i]; b[i] = b[i-1]; b[i-1] = t1; dt1 = max_b[i]; max_b[i] = max_b[i-1]; max_b[i-1] = dt1; if (U) swap((*U)(i), (*U)(i-1)); } k = l; NumSwaps++; continue; } } // end deep insertions // test LLL reduction condition if (k > 1 && delta*c[k-1] > c[k] + mu[k][k-1]*mu[k][k-1]*c[k-1]) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; tp = mu[k]; mu[k] = mu[k-1]; mu[k-1] = tp; t1 = b[k]; b[k] = b[k-1]; b[k-1] = t1; dt1 = max_b[k]; max_b[k] = max_b[k-1]; max_b[k-1] = dt1; if (U) swap((*U)(k), (*U)(k-1)); k--; NumSwaps++; // cout << "- " << k << "\n"; } else { k++; // cout << "+ " << k << "\n"; } } if (verbose) { LLLStatus(m+1, GetTime(), m, B); } delete [] buf; delete [] max_b; return m; } static long LLL_QP(mat_ZZ& B, mat_ZZ* U, quad_float delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; quad_float s; ZZ MU; quad_float mu1; quad_float t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); quad_float **B1; // approximates B typedef quad_float *quad_floatptr; B1 = NTL_NEW_OP quad_floatptr[m+1]; if (!B1) Error("LLL_QP: out of memory"); for (i = 1; i <= m; i++) { B1[i] = NTL_NEW_OP quad_float[n+1]; if (!B1[i]) Error("LLL_QP: out of memory"); } quad_float **mu; mu = NTL_NEW_OP quad_floatptr[m+1]; if (!mu) Error("LLL_QP: out of memory"); for (i = 1; i <= m; i++) { mu[i] = NTL_NEW_OP quad_float[m+1]; if (!mu[i]) Error("LLL_QP: out of memory"); } quad_float *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP quad_float[m+1]; if (!c) Error("LLL_QP: out of memory"); quad_float *b; // squared lengths of basis vectors b = NTL_NEW_OP quad_float[m+1]; if (!b) Error("LLL_QP: out of memory"); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } new_m = ll_LLL_QP(B, U, delta, deep, check, B1, mu, b, c, m, 1, quit); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } // clean-up for (i = 1; i <= m+dep; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m+dep; i++) { delete [] mu[i]; } delete [] mu; delete [] c; delete [] b; return m; } long LLL_QP(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("LLL_QP: bad delta"); if (deep < 0) Error("LLL_QP: bad deep"); return LLL_QP(B, 0, to_quad_float(delta), deep, check); } long LLL_QP(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("LLL_QP: bad delta"); if (deep < 0) Error("LLL_QP: bad deep"); return LLL_QP(B, &U, to_quad_float(delta), deep, check); } NTL_THREAD_LOCAL static vec_quad_float BKZConstant; static void ComputeBKZConstant(long beta, long p) { const quad_float c_PI = to_quad_float("3.141592653589793238462643383279502884197"); const quad_float LogPI = to_quad_float("1.144729885849400174143427351353058711647"); BKZConstant.SetLength(beta-1); vec_quad_float Log; Log.SetLength(beta); long i, j, k; quad_float x, y; for (j = 1; j <= beta; j++) Log(j) = log(to_quad_float(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/to_quad_float(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/to_quad_float(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/to_quad_float(i))*Log(2); y = exp(y); BKZConstant(i) = x*y/c_PI; } } NTL_THREAD_LOCAL static vec_quad_float BKZThresh; static void ComputeBKZThresh(quad_float *c, long beta) { BKZThresh.SetLength(beta-1); long i; quad_float x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); BKZThresh(i) = exp(x/to_quad_float(i))*BKZConstant(i); if (!IsFinite(&BKZThresh(i))) BKZThresh(i) = 0; } } static void BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- BKZ_QP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long BKZ_QP(mat_ZZ& BB, mat_ZZ* UU, quad_float delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; quad_float t1; ZZ T1; quad_float *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); quad_float **B1; // approximates B typedef quad_float *quad_floatptr; B1 = NTL_NEW_OP quad_floatptr[m+2]; if (!B1) Error("BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { B1[i] = NTL_NEW_OP quad_float[n+1]; if (!B1[i]) Error("BKZ_QP: out of memory"); } quad_float **mu; mu = NTL_NEW_OP quad_floatptr[m+2]; if (!mu) Error("BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { mu[i] = NTL_NEW_OP quad_float[m+1]; if (!mu[i]) Error("BKZ_QP: out of memory"); } quad_float *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP quad_float[m+2]; if (!c) Error("BKZ_QP: out of memory"); quad_float *b; // squared lengths of basis vectors b = NTL_NEW_OP quad_float[m+2]; if (!b) Error("BKZ_QP: out of memory"); quad_float cbar; quad_float *ctilda; ctilda = NTL_NEW_OP quad_float[m+2]; if (!ctilda) Error("BKZ_QP: out of memory"); quad_float *vvec; vvec = NTL_NEW_OP quad_float[m+2]; if (!vvec) Error("BKZ_QP: out of memory"); quad_float *yvec; yvec = NTL_NEW_OP quad_float[m+2]; if (!yvec) Error("BKZ_QP: out of memory"); quad_float *uvec; uvec = NTL_NEW_OP quad_float[m+2]; if (!uvec) Error("BKZ_QP: out of memory"); quad_float *utildavec; utildavec = NTL_NEW_OP quad_float[m+2]; if (!utildavec) Error("BKZ_QP: out of memory"); long *Deltavec; Deltavec = NTL_NEW_OP long[m+2]; if (!Deltavec) Error("BKZ_QP: out of memory"); long *deltavec; deltavec = NTL_NEW_OP long[m+2]; if (!deltavec) Error("BKZ_QP: out of memory"); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; quad_float eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } // cerr << "\n"; // cerr << "first LLL\n"; m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; if (prune > 0 && t > jj) { eta = BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*mu[i][t]; } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta-8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("BKZ_QP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } // cerr << "special case\n"; new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) Error("BKZ_QP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } b[jj] = InnerProduct(B1[jj], B1[jj], n); CheckFinite(&b[jj]); if (b[jj] == 0) Error("BKZ_QP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_QP(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) Error("BKZ_QP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_QP: internal error"); if (quit) break; } } z = 0; } else { // LLL_QP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_QP: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } for (i = 1; i <= m_orig+1; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m_orig+1; i++) { delete [] mu[i]; } delete [] mu; delete [] c; delete [] b; delete [] ctilda; delete [] vvec; delete [] yvec; delete [] uvec; delete [] utildavec; delete [] Deltavec; delete [] deltavec; return m; } long BKZ_QP(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_QP: bad delta"); if (beta < 2) Error("BKZ_QP: bad block size"); return BKZ_QP(BB, &UU, to_quad_float(delta), beta, prune, check); } long BKZ_QP(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_QP: bad delta"); if (beta < 2) Error("BKZ_QP: bad block size"); return BKZ_QP(BB, 0, to_quad_float(delta), beta, prune, check); } static long BKZ_QP1(mat_ZZ& BB, mat_ZZ* UU, quad_float delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; ZZ T1; quad_float *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); quad_float **B1; // approximates B typedef quad_float *quad_floatptr; B1 = NTL_NEW_OP quad_floatptr[m+2]; if (!B1) Error("BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { B1[i] = NTL_NEW_OP quad_float[n+1]; if (!B1[i]) Error("BKZ_QP: out of memory"); } quad_float **mu; mu = NTL_NEW_OP quad_floatptr[m+2]; if (!mu) Error("BKZ_QP: out of memory"); for (i = 1; i <= m+1; i++) { mu[i] = NTL_NEW_OP quad_float[m+1]; if (!mu[i]) Error("BKZ_QP: out of memory"); } quad_float *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP quad_float[m+2]; if (!c) Error("BKZ_QP: out of memory"); quad_float *b; // squared lengths of basis vectors b = NTL_NEW_OP quad_float[m+2]; if (!b) Error("BKZ_QP: out of memory"); double cbar; double *ctilda; ctilda = NTL_NEW_OP double[m+2]; if (!ctilda) Error("BKZ_QP: out of memory"); double *vvec; vvec = NTL_NEW_OP double[m+2]; if (!vvec) Error("BKZ_QP: out of memory"); double *yvec; yvec = NTL_NEW_OP double[m+2]; if (!yvec) Error("BKZ_QP: out of memory"); double *uvec; uvec = NTL_NEW_OP double[m+2]; if (!uvec) Error("BKZ_QP: out of memory"); double *utildavec; utildavec = NTL_NEW_OP double[m+2]; if (!utildavec) Error("BKZ_QP: out of memory"); long *Deltavec; Deltavec = NTL_NEW_OP long[m+2]; if (!Deltavec) Error("BKZ_QP: out of memory"); long *deltavec; deltavec = NTL_NEW_OP long[m+2]; if (!deltavec) Error("BKZ_QP: out of memory"); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; double eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } // cerr << "\n"; // cerr << "first LLL\n"; m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c[jj], kk-jj+1); cbar = to_double(c[jj]); utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*to_double(c[t]); ForceToMem(&ctilda[t]); // prevents an infinite loop if (prune > 0 && t > jj) { eta = to_double(BKZThresh(t-jj)); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { double t1; t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*to_double(mu[i][t]); } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); quad_float t1; if ((delta-8*red_fudge)*c[jj] > cbar*(1+64/NTL_FDOUBLE_PRECISION)) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("BKZ_QP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } // cerr << "special case\n"; new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) Error("BKZ_QP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } b[jj] = InnerProduct(B1[jj], B1[jj], n); CheckFinite(&b[jj]); if (b[jj] == 0) Error("BKZ_QP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_QP(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) Error("BKZ_QP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_QP: internal error"); if (quit) break; } } z = 0; } else { // LLL_QP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_QP: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } for (i = 1; i <= m_orig+1; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m_orig+1; i++) { delete [] mu[i]; } delete [] mu; delete [] c; delete [] b; delete [] ctilda; delete [] vvec; delete [] yvec; delete [] uvec; delete [] utildavec; delete [] Deltavec; delete [] deltavec; return m; } long BKZ_QP1(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_QP: bad delta"); if (beta < 2) Error("BKZ_QP: bad block size"); return BKZ_QP1(BB, &UU, to_quad_float(delta), beta, prune, check); } long BKZ_QP1(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_QP: bad delta"); if (beta < 2) Error("BKZ_QP: bad block size"); return BKZ_QP1(BB, 0, to_quad_float(delta), beta, prune, check); } NTL_END_IMPL ntl-6.2.1/src/LLL_RR.c000644 000765 000024 00000065577 12377144456 014640 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } void ComputeGS(const mat_ZZ& B, mat_RR& B1, mat_RR& mu, vec_RR& b, vec_RR& c, long k, const RR& bound, long st, vec_RR& buf, const RR& bound2) { long i, j; RR s, t, t1; ZZ T1; if (st < k) { for (i = 1; i < st; i++) mul(buf(i), mu(k,i), c(i)); } for (j = st; j <= k-1; j++) { InnerProduct(s, B1(k), B1(j)); sqr(t1, s); mul(t1, t1, bound); mul(t, b(k), b(j)); if (t >= bound2 && t >= t1) { InnerProduct(T1, B(k), B(j)); conv(s, T1); } clear(t1); for (i = 1; i <= j-1; i++) { mul(t, mu(j, i), buf(i)); add(t1, t1, t); } sub(t, s, t1); buf(j) = t; div(mu(k, j), t, c(j)); } clear(s); for (j = 1; j <= k-1; j++) { mul(t, mu(k, j), buf(j)); add(s, s, t); } sub(c(k), b(k), s); } NTL_THREAD_LOCAL static RR red_fudge; NTL_THREAD_LOCAL static long log_red = 0; static void init_red_fudge() { log_red = long(0.50*RR::precision()); power2(red_fudge, -log_red); } static void inc_red_fudge() { mul(red_fudge, red_fudge, 2); log_red--; cerr << "LLL_RR: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) Error("LLL_RR: can not continue...sorry"); } NTL_THREAD_LOCAL static long verbose = 0; NTL_THREAD_LOCAL static unsigned long NumSwaps = 0; NTL_THREAD_LOCAL static double StartTime = 0; NTL_THREAD_LOCAL static double LastTime = 0; static void LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- LLL_RR status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static long ll_LLL_RR(mat_ZZ& B, mat_ZZ* U, const RR& delta, long deep, LLLCheckFct check, mat_RR& B1, mat_RR& mu, vec_RR& b, vec_RR& c, long m, long init_k, long &quit) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; RR mu1, t1, t2, cc; ZZ T1; RR bound; // we tolerate a 15% loss of precision in computing // inner products in ComputeGS. power2(bound, 2*long(0.15*RR::precision())); RR bound2; power2(bound2, 2*RR::precision()); quit = 0; k = init_k; vec_long st_mem; st_mem.SetLength(m+2); long *st = st_mem.elts(); for (i = 1; i < k; i++) st[i] = i; for (i = k; i <= m+1; i++) st[i] = 1; vec_RR buf; buf.SetLength(m); long rst; long counter; long trigger_index; long small_trigger; long cnt; RR half; conv(half, 0.5); RR half_plus_fudge; add(half_plus_fudge, half, red_fudge); long max_k = 0; double tt; while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) LLLStatus(max_k, tt, m, B); } if (st[k] == k) rst = 1; else rst = k; if (st[k] < st[k+1]) st[k+1] = st[k]; ComputeGS(B, B1, mu, b, c, k, bound, st[k], buf, bound2); st[k] = k; counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "LLL_XD: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = rst-1; j >= 1; j--) { abs(t1, mu(k,j)); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); add(half_plus_fudge, half, red_fudge); cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu(k,j); if (sign(mu1) >= 0) { sub(mu1, mu1, half); ceil(mu1, mu1); } else { add(mu1, mu1, half); floor(mu1, mu1); } if (mu1 == 1) { for (i = 1; i <= j-1; i++) sub(mu(k,i), mu(k,i), mu(j,i)); } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) add(mu(k,i), mu(k,i), mu(j,i)); } else { for (i = 1; i <= j-1; i++) { mul(t2, mu1, mu(j,i)); sub(mu(k,i), mu(k,i), t2); } } conv(MU, mu1); sub(mu(k,j), mu(k,j), mu1); RowTransform(B(k), B(j), MU); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1(k, i), B(k, i)); InnerProduct(b(k), B1(k), B1(k)); ComputeGS(B, B1, mu, b, c, k, bound, 1, buf, bound2); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(b(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); swap(B1(i), B1(i+1)); swap(b(i), b(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = k; i <= m+1; i++) st[i] = 1; m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions cc = b(k); long l = 1; while (l <= k-1) { mul(t1, delta, c(l)); if (t1 > cc) break; sqr(t1, mu(k,l)); mul(t1, t1, c(l)); sub(cc, cc, t1); l++; } if (l <= k-1 && (l <= deep || k-l <= deep)) { // deep insertion at position l for (i = k; i > l; i--) { // swap rows i, i-1 swap(B(i), B(i-1)); swap(B1(i), B1(i-1)); swap(mu(i), mu(i-1)); swap(b(i), b(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } k = l; continue; } } // end deep insertions // test LLL reduction condition if (k <= 1) { k++; } else { sqr(t1, mu(k,k-1)); mul(t1, t1, c(k-1)); add(t1, t1, c(k)); mul(t2, delta, c(k-1)); if (t2 > t1) { // swap rows k, k-1 swap(B(k), B(k-1)); swap(B1(k), B1(k-1)); swap(mu(k), mu(k-1)); swap(b(k), b(k-1)); if (U) swap((*U)(k), (*U)(k-1)); k--; NumSwaps++; } else { k++; } } } if (verbose) { LLLStatus(m+1, GetTime(), m, B); } return m; } static long LLL_RR(mat_ZZ& B, mat_ZZ* U, const RR& delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; RR s; ZZ MU; RR mu1; RR t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); mat_RR B1; // approximates B B1.SetDims(m, n); mat_RR mu; mu.SetDims(m, m); vec_RR c; // squared lengths of Gramm-Schmidt basis vectors c.SetLength(m); vec_RR b; // squared lengths of basis vectors b.SetLength(m); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); for (i = 1; i <= m; i++) { InnerProduct(b(i), B1(i), B1(i)); } new_m = ll_LLL_RR(B, U, delta, deep, check, B1, mu, b, c, m, 1, quit); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long LLL_RR(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("LLL_RR: bad delta"); if (deep < 0) Error("LLL_RR: bad deep"); RR Delta; conv(Delta, delta); return LLL_RR(B, 0, Delta, deep, check); } long LLL_RR(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("LLL_RR: bad delta"); if (deep < 0) Error("LLL_RR: bad deep"); RR Delta; conv(Delta, delta); return LLL_RR(B, &U, Delta, deep, check); } NTL_THREAD_LOCAL static vec_RR BKZConstant; static void ComputeBKZConstant(long beta, long p) { RR c_PI; ComputePi(c_PI); RR LogPI = log(c_PI); BKZConstant.SetLength(beta-1); vec_RR Log; Log.SetLength(beta); long i, j, k; RR x, y; for (j = 1; j <= beta; j++) Log(j) = log(to_RR(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x += Log(j); x = exp(x/k); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x += Log(j); x += 0.5*LogPI - 2*(k+1)*Log(2); x = exp(2*x/i); } // Second, we compute y = 2^{2*p/i} y = exp(-(2*p/to_RR(i))*Log(2)); BKZConstant(i) = x*y/c_PI; } } NTL_THREAD_LOCAL static vec_RR BKZThresh; static void ComputeBKZThresh(RR *c, long beta) { BKZThresh.SetLength(beta-1); long i; RR x; RR t1; x = 0; for (i = 1; i <= beta-1; i++) { log(t1, c[i-1]); add(x, x, t1); div(t1, x, i); exp(t1, t1); mul(BKZThresh(i), t1, BKZConstant(i)); } } static void BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- BKZ_RR status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long BKZ_RR(mat_ZZ& BB, mat_ZZ* UU, const RR& delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; RR t1, t2; ZZ T1; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); mat_RR B1; B1.SetDims(m+1, n); mat_RR mu; mu.SetDims(m+1, m); vec_RR c; c.SetLength(m+1); vec_RR b; b.SetLength(m+1); RR cbar; vec_RR ctilda; ctilda.SetLength(m+1); vec_RR vvec; vvec.SetLength(m+1); vec_RR yvec; yvec.SetLength(m+1); vec_RR uvec; uvec.SetLength(m+1); vec_RR utildavec; utildavec.SetLength(m+1); vec_long Deltavec; Deltavec.SetLength(m+1); vec_long deltavec; deltavec.SetLength(m+1); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); for (i = 1; i <= m; i++) { InnerProduct(b(i), B1(i), B1(i)); } // cerr << "\n"; // cerr << "first LLL\n"; m = ll_LLL_RR(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } long clean = 1; if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c(jj), kk-jj+1); cbar = c(jj); conv(utildavec(jj), 1); conv(uvec(jj), 1); conv(yvec(jj), 0); conv(vvec(jj), 0); Deltavec(jj) = 0; s = t = jj; deltavec(jj) = 1; for (i = jj+1; i <= kk+1; i++) { conv(ctilda(i), 0); conv(uvec(i), 0); conv(utildavec(i), 0); conv(yvec(i), 0); Deltavec(i) = 0; conv(vvec(i), 0); deltavec(i) = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } add(t1, yvec(t), utildavec(t)); sqr(t1, t1); mul(t1, t1, c(t)); add(ctilda(t), ctilda(t+1), t1); if (prune > 0 && t > jj) sub(t1, cbar, BKZThresh(t-jj)); else t1 = cbar; if (ctilda(t) jj) { t--; clear(t1); for (i = t+1; i <= s; i++) { mul(t2, utildavec(i), mu(i,t)); add(t1, t1, t2); } yvec(t) = t1; negate(t1, t1); if (sign(t1) >= 0) { sub(t1, t1, 0.5); ceil(t1, t1); } else { add(t1, t1, 0.5); floor(t1, t1); } utildavec(t) = t1; vvec(t) = t1; Deltavec(t) = 0; negate(t1, t1); if (t1 < yvec(t)) deltavec(t) = -1; else deltavec(t) = 1; } else { cbar = ctilda(jj); for (i = jj; i <= kk; i++) { uvec(i) = utildavec(i); } } } else { t++; s = max(s, t); if (t < s) Deltavec(t) = -Deltavec(t); if (Deltavec(t)*deltavec(t) >= 0) Deltavec(t) += deltavec(t); add(utildavec(t), vvec(t), Deltavec(t)); } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); mul(t1, red_fudge, -8); add(t1, t1, delta); mul(t1, t1, c(jj)); if (t1 > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec(i) != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("BKZ_RR: internal error"); if (s > 0) { // special case // cerr << "special case\n"; NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); swap(b(i-1), b(i)); if (U) swap((*U)(i-1), (*U)(i)); } new_m = ll_LLL_RR(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) Error("BKZ_RR: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec(i) == 0) continue; conv(MU, uvec(i)); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); swap(b(i-1), b(i)); if (U) swap((*U)(i-1), (*U)(i)); } for (i = 1; i <= n; i++) conv(B1(jj, i), B(jj, i)); InnerProduct(b(jj), B1(jj), B1(jj)); if (b(jj) == 0) Error("BKZ_RR: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_RR(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) Error("BKZ_RR: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); swap(b(i-1), b(i)); if (U) swap((*U)(i-1), (*U)(i)); } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_RR(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_RR: internal error"); if (quit) break; } } z = 0; } else { // LLL_RR // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_RR(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_RR: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long BKZ_RR(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_RR: bad delta"); if (beta < 2) Error("BKZ_RR: bad block size"); RR Delta; conv(Delta, delta); return BKZ_RR(BB, &UU, Delta, beta, prune, check); } long BKZ_RR(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_RR: bad delta"); if (beta < 2) Error("BKZ_RR: bad block size"); RR Delta; conv(Delta, delta); return BKZ_RR(BB, 0, Delta, beta, prune, check); } void NearVector(vec_ZZ& ww, const mat_ZZ& BB, const vec_ZZ& a) { long n = BB.NumCols(); if (n != BB.NumRows()) Error("NearVector: matrix must be square"); if (n != a.length()) Error("NearVector: dimension mismatch"); long i, j; mat_ZZ B; B.SetDims(n+1, n); for (i = 1; i <= n; i++) B(i) = BB(i); B(n+1) = a; mat_RR B1, mu; vec_RR b, c; B1.SetDims(n+1, n); mu.SetDims(n+1, n+1); b.SetLength(n+1); c.SetLength(n+1); vec_RR buf; buf.SetLength(n+1); for (i = 1; i <= n+1; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); for (i = 1; i <= n+1; i++) InnerProduct(b(i), B1(i), B1(i)); RR bound; power2(bound, 2*long(0.15*RR::precision())); RR bound2; power2(bound2, 2*RR::precision()); for (i = 1; i <= n+1; i++) ComputeGS(B, B1, mu, b, c, i, bound, 1, buf, bound2); init_red_fudge(); RR half; conv(half, 0.5); RR half_plus_fudge; add(half_plus_fudge, half, red_fudge); RR t1, t2, mu1; ZZ MU; long trigger_index = n+1; long small_trigger = 0; long cnt = 0; long Fc1; vec_ZZ w; w.SetLength(n); clear(w); do { Fc1 = 0; for (j = n; j >= 1; j--) { abs(t1, mu(n+1,j)); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); add(half_plus_fudge, half, red_fudge); cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu(n+1,j); if (sign(mu1) >= 0) { sub(mu1, mu1, half); ceil(mu1, mu1); } else { add(mu1, mu1, half); floor(mu1, mu1); } if (mu1 == 1) { for (i = 1; i <= j-1; i++) sub(mu(n+1,i), mu(n+1,i), mu(j,i)); } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) add(mu(n+1,i), mu(n+1,i), mu(j,i)); } else { for (i = 1; i <= j-1; i++) { mul(t2, mu1, mu(j,i)); sub(mu(n+1,i), mu(n+1,i), t2); } } conv(MU, mu1); sub(mu(n+1,j), mu(n+1,j), mu1); RowTransform(B(n+1), B(j), MU); RowTransform2(w, B(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1(n+1, i), B(n+1, i)); InnerProduct(b(n+1), B1(n+1), B1(n+1)); ComputeGS(B, B1, mu, b, c, n+1, bound, 1, buf, bound2); } } while (Fc1); ww = w; } NTL_END_IMPL ntl-6.2.1/src/LLL_XD.c000644 000765 000024 00000065151 12377144456 014614 0ustar00shoupstaff000000 000000 #include #include #include #include #include NTL_START_IMPL static xdouble InnerProduct(xdouble *a, xdouble *b, long n) { xdouble s; long i; s = 0; for (i = 1; i <= n; i++) MulAdd(s, s, a[i], b[i]); return s; } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } static void ComputeGS(mat_ZZ& B, xdouble **B1, xdouble **mu, xdouble *b, xdouble *c, long k, xdouble bound, long st, xdouble *buf) { long n = B.NumCols(); long i, j; xdouble s, t1, y, t; ZZ T1; xdouble *mu_k = mu[k]; if (st < k) { for (i = 1; i < st; i++) buf[i] = mu_k[i]*c[i]; } for (j = st; j <= k-1; j++) { if (b[k]*b[j] < NTL_FDOUBLE_PRECISION*NTL_FDOUBLE_PRECISION) { double z = 0; xdouble *B1_k = B1[k]; xdouble *B1_j = B1[j]; for (i = 1; i <= n; i++) z += B1_k[i].x * B1_j[i].x; s = z; } else { s = InnerProduct(B1[k], B1[j], n); if (s*s <= b[k]*b[j]/bound) { InnerProduct(T1, B(k), B(j)); conv(s, T1); } } xdouble *mu_j = mu[j]; t1 = 0; for (i = 1; i <= j-1; i++) MulAdd(t1, t1, mu_j[i], buf[i]); mu_k[j] = (buf[j] = (s - t1))/c[j]; } s = 0; for (j = 1; j <= k-1; j++) MulAdd(s, s, mu_k[j], buf[j]); c[k] = b[k] - s; } NTL_THREAD_LOCAL static xdouble red_fudge = to_xdouble(0); NTL_THREAD_LOCAL static long log_red = 0; static void init_red_fudge() { long i; log_red = long(0.50*NTL_DOUBLE_PRECISION); red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { red_fudge = red_fudge * 2; log_red--; cerr << "LLL_XD: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) Error("LLL_XD: can not continue...sorry"); } NTL_THREAD_LOCAL static long verbose = 0; NTL_THREAD_LOCAL static unsigned long NumSwaps = 0; NTL_THREAD_LOCAL static double StartTime = 0; NTL_THREAD_LOCAL static double LastTime = 0; static void LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- LLL_XD status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static long ll_LLL_XD(mat_ZZ& B, mat_ZZ* U, xdouble delta, long deep, LLLCheckFct check, xdouble **B1, xdouble **mu, xdouble *b, xdouble *c, long m, long init_k, long &quit) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; xdouble mu1; xdouble t1; ZZ T1; xdouble *tp; NTL_THREAD_LOCAL static xdouble bound = to_xdouble(0); if (bound == 0) { // we tolerate a 15% loss of precision in computing // inner products in ComputeGS. bound = 1; for (i = 2*long(0.15*NTL_DOUBLE_PRECISION); i > 0; i--) { bound = bound * 2; } } xdouble half = to_xdouble(0.5); xdouble half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long st_mem; st_mem.SetLength(m+2); long *st = st_mem.elts(); for (i = 1; i < k; i++) st[i] = i; for (i = k; i <= m+1; i++) st[i] = 1; xdouble *buf; buf = NTL_NEW_OP xdouble [m+1]; if (!buf) Error("out of memory in lll_LLL_XD"); long rst; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) LLLStatus(max_k, tt, m, B); } if (st[k] == k) rst = 1; else rst = k; if (st[k] < st[k+1]) st[k+1] = st[k]; ComputeGS(B, B1, mu, b, c, k, bound, st[k], buf); st[k] = k; counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "LLL_XD: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = rst-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-half); else mu1 = floor(mu1+half); xdouble *mu_k = mu[k]; xdouble *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) MulSub(mu_k[i], mu_k[i], mu1, mu_j[i]); } mu_k[j] -= mu1; conv(MU, mu1); // cout << j << " " << MU << "\n"; RowTransform(B(k), B(j), MU); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1[k][i], B(k, i)); b[k] = InnerProduct(B1[k], B1[k], n); ComputeGS(B, B1, mu, b, c, k, bound, 1, buf); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (b[k] == 0) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; t1 = b[i]; b[i] = b[i+1]; b[i+1] = t1; if (U) swap((*U)(i), (*U)(i+1)); } for (i = k; i <= m+1; i++) st[i] = 1; m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions xdouble cc = b[k]; long l = 1; while (l <= k-1 && delta*c[l] <= cc) { cc = cc - mu[k][l]*mu[k][l]*c[l]; l++; } if (l <= k-1 && (l <= deep || k-l <= deep)) { // deep insertion at position l for (i = k; i > l; i--) { // swap rows i, i-1 swap(B(i), B(i-1)); tp = B1[i]; B1[i] = B1[i-1]; B1[i-1] = tp; tp = mu[i]; mu[i] = mu[i-1]; mu[i-1] = tp; t1 = b[i]; b[i] = b[i-1]; b[i-1] = t1; if (U) swap((*U)(i), (*U)(i-1)); } k = l; continue; } } // end deep insertions // test LLL reduction condition if (k > 1 && delta*c[k-1] > c[k] + mu[k][k-1]*mu[k][k-1]*c[k-1]) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; tp = mu[k]; mu[k] = mu[k-1]; mu[k-1] = tp; t1 = b[k]; b[k] = b[k-1]; b[k-1] = t1; if (U) swap((*U)(k), (*U)(k-1)); k--; NumSwaps++; // cout << "- " << k << "\n"; } else { k++; // cout << "+ " << k << "\n"; } } if (verbose) { LLLStatus(m+1, GetTime(), m, B); } delete [] buf; return m; } static long LLL_XD(mat_ZZ& B, mat_ZZ* U, xdouble delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; xdouble s; ZZ MU; xdouble mu1; xdouble t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); xdouble **B1; // approximates B typedef xdouble *xdoubleptr; B1 = NTL_NEW_OP xdoubleptr[m+1]; if (!B1) Error("LLL_XD: out of memory"); for (i = 1; i <= m; i++) { B1[i] = NTL_NEW_OP xdouble[n+1]; if (!B1[i]) Error("LLL_XD: out of memory"); } xdouble **mu; mu = NTL_NEW_OP xdoubleptr[m+1]; if (!mu) Error("LLL_XD: out of memory"); for (i = 1; i <= m; i++) { mu[i] = NTL_NEW_OP xdouble[m+1]; if (!mu[i]) Error("LLL_XD: out of memory"); } xdouble *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP xdouble[m+1]; if (!c) Error("LLL_XD: out of memory"); xdouble *b; // squared lengths of basis vectors b = NTL_NEW_OP xdouble[m+1]; if (!b) Error("LLL_XD: out of memory"); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1[i][j], B(i, j)); for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); } new_m = ll_LLL_XD(B, U, delta, deep, check, B1, mu, b, c, m, 1, quit); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } // clean-up for (i = 1; i <= m+dep; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m+dep; i++) { delete [] mu[i]; } delete [] mu; delete [] c; delete [] b; return m; } long LLL_XD(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("LLL_XD: bad delta"); if (deep < 0) Error("LLL_XD: bad deep"); return LLL_XD(B, 0, to_xdouble(delta), deep, check); } long LLL_XD(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("LLL_XD: bad delta"); if (deep < 0) Error("LLL_XD: bad deep"); return LLL_XD(B, &U, to_xdouble(delta), deep, check); } NTL_THREAD_LOCAL static vec_xdouble BKZConstant; static void ComputeBKZConstant(long beta, long p) { const double c_PI = 3.14159265358979323846264338328; const double LogPI = 1.14472988584940017414342735135; BKZConstant.SetLength(beta-1); vec_double Log; Log.SetLength(beta); long i, j, k; double x, y; for (j = 1; j <= beta; j++) Log(j) = log(double(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/double(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/double(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/double(i))*Log(2); y = exp(y); BKZConstant(i) = x*y/c_PI; } } NTL_THREAD_LOCAL static vec_xdouble BKZThresh; static void ComputeBKZThresh(xdouble *c, long beta) { BKZThresh.SetLength(beta-1); long i; double x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); BKZThresh(i) = xexp(x/double(i))*BKZConstant(i); } } static void BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- BKZ_XD status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long BKZ_XD(mat_ZZ& BB, mat_ZZ* UU, xdouble delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; xdouble t1; ZZ T1; xdouble *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); xdouble **B1; // approximates B typedef xdouble *xdoubleptr; B1 = NTL_NEW_OP xdoubleptr[m+2]; if (!B1) Error("BKZ_XD: out of memory"); for (i = 1; i <= m+1; i++) { B1[i] = NTL_NEW_OP xdouble[n+1]; if (!B1[i]) Error("BKZ_XD: out of memory"); } xdouble **mu; mu = NTL_NEW_OP xdoubleptr[m+2]; if (!mu) Error("BKZ_XD: out of memory"); for (i = 1; i <= m+1; i++) { mu[i] = NTL_NEW_OP xdouble[m+1]; if (!mu[i]) Error("BKZ_XD: out of memory"); } xdouble *c; // squared lengths of Gramm-Schmidt basis vectors c = NTL_NEW_OP xdouble[m+2]; if (!c) Error("BKZ_XD: out of memory"); xdouble *b; // squared lengths of basis vectors b = NTL_NEW_OP xdouble[m+2]; if (!b) Error("BKZ_XD: out of memory"); xdouble cbar; xdouble *ctilda; ctilda = NTL_NEW_OP xdouble[m+2]; if (!ctilda) Error("BKZ_XD: out of memory"); xdouble *vvec; vvec = NTL_NEW_OP xdouble[m+2]; if (!vvec) Error("BKZ_XD: out of memory"); xdouble *yvec; yvec = NTL_NEW_OP xdouble[m+2]; if (!yvec) Error("BKZ_XD: out of memory"); xdouble *uvec; uvec = NTL_NEW_OP xdouble[m+2]; if (!uvec) Error("BKZ_XD: out of memory"); xdouble *utildavec; utildavec = NTL_NEW_OP xdouble[m+2]; if (!utildavec) Error("BKZ_XD: out of memory"); long *Deltavec; Deltavec = NTL_NEW_OP long[m+2]; if (!Deltavec) Error("BKZ_XD: out of memory"); long *deltavec; deltavec = NTL_NEW_OP long[m+2]; if (!deltavec) Error("BKZ_XD: out of memory"); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; xdouble eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1[i][j], B(i, j)); for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); } // cerr << "\n"; // cerr << "first LLL\n"; m = ll_LLL_XD(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } long clean = 1; if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; if (prune > 0 && t > jj) { eta = BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*mu[i][t]; } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta-8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) Error("BKZ_XD: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } // cerr << "special case\n"; new_m = ll_LLL_XD(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) Error("BKZ_XD: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } for (i = 1; i <= n; i++) conv(B1[jj][i], B(jj, i)); b[jj] = InnerProduct(B1[jj], B1[jj], n); if (b[jj] == 0) Error("BKZ_XD: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_XD(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) Error("BKZ_XD: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_XD(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_XD: internal error"); if (quit) break; } } z = 0; } else { // LLL_XD // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_XD(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) Error("BKZ_XD: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } for (i = 1; i <= m_orig+1; i++) { delete [] B1[i]; } delete [] B1; for (i = 1; i <= m_orig+1; i++) { delete [] mu[i]; } delete [] mu; delete [] c; delete [] b; delete [] ctilda; delete [] vvec; delete [] yvec; delete [] uvec; delete [] utildavec; delete [] Deltavec; delete [] deltavec; return m; } long BKZ_XD(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_XD: bad delta"); if (beta < 2) Error("BKZ_XD: bad block size"); return BKZ_XD(BB, &UU, to_xdouble(delta), beta, prune, check); } long BKZ_XD(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) Error("BKZ_XD: bad delta"); if (beta < 2) Error("BKZ_XD: bad block size"); return BKZ_XD(BB, 0, to_xdouble(delta), beta, prune, check); } NTL_END_IMPL ntl-6.2.1/src/MakeDesc.c000644 000765 000024 00000056731 12377144456 015256 0ustar00shoupstaff000000 000000 #include #include #include #include #include #include #if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || defined(__i586__))) #define AutoFix (1) #else #define AutoFix (0) #endif int val_int(int x); unsigned int val_uint(unsigned int x); long val_long(long x); unsigned long val_ulong(unsigned long x); size_t val_size_t(size_t x); double val_double(double x); void touch_int(int* x); void touch_uint(unsigned int* x); void touch_long(long* x); void touch_ulong(unsigned long* x); void touch_size_t(size_t* x); void touch_double(double* x); double power2(long k) { long i; double res; res = 1; for (i = 1; i <= k; i++) res = res * 2; return res; } long DoubleRounding(long dp) { double a = power2(dp-1) + 1; double b = (power2(dp)-1)/power2(dp+1); register double x = a + b; double y = x; touch_double(&y); if (y != power2(dp-1) + 1) return 1; else return 0; } long DoublePrecision() { double eps, one, res; long k; one = val_double(1.0); eps = val_double(1.0); k = 0; do { double tmp; k++; eps *= 1.0/2.0; tmp = 1.0 + eps; touch_double(&tmp); res = tmp - one; } while (res == eps); return k; } long DoublePrecision1() { double eps, one, res; long k; one = val_double(1.0); eps = val_double(1.0); k = 0; do { register double tmp; k++; eps *= 1.0/2.0; tmp = 1.0 + eps; res = tmp - one; } while (res == eps); return k; } void print2k(FILE *f, long k, long bpl) { long m, l; long first; if (k <= 0) { fprintf(f, "((double) 1.0)"); return; } m = bpl - 2; first = 1; fprintf(f, "("); while (k > 0) { if (k > m) l = m; else l = k; k = k - l; if (first) first = 0; else fprintf(f, "*"); fprintf(f, "((double)(1L<<%ld))", l); } fprintf(f, ")"); } void print_mul_body(FILE *f, long n1, long k, long fn, long half_flag, long short_flag) { long n, i, chop, r; unsigned long mask, mask2; if (half_flag) n = n1/2; else n = n1; chop = n % k; /* first block */ if (chop == 0) chop = k; r = n - k; mask = (1UL << k) - 1UL; fprintf(f, "\n\n#define NTL_"); if (half_flag) fprintf(f, "HALF_"); if (short_flag) fprintf(f, "SHORT_"); fprintf(f, "BB_MUL_CODE%ld \\\n", fn); if (fn > 0) /* Mul1/AddMul1 */ { fprintf(f, " long i;\\\n"); fprintf(f, " _ntl_ulong carry = 0, b;\\\n"); } fprintf(f, " _ntl_ulong hi, lo, t;\\\n"); fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); fprintf(f, " A[0] = 0;\\\n"); fprintf(f, " A[1] = a;\\\n"); for (i = 2; i < (1L << k); i++) { if (i % 2 == 0) fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); else fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); } if (fn > 0) { fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); fprintf(f, " b = bp[i];\\\n"); fprintf(f, " "); } fprintf(f, " lo = A[b & %lu]; ", mask); fprintf(f, "t = A[(b >> %ld) & %lu]; ", k, mask); fprintf(f, "hi = t >> %ld; lo ^= t << %ld;\\\n", n1-k, k); for (i = 2*k; i < n - chop; i += k) { if (fn > 0) fprintf(f, " "); fprintf(f, " t = A[(b >> %ld) & %lu]; ", i, mask); fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); } if (fn > 0) fprintf(f, " "); fprintf(f, " t = A[b >> %ld]; ", n-chop); fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); mask = 0; for (i = 0; i < n; i += k) mask |= 1UL << i; mask = ~mask; if (half_flag) mask &= (1UL << n) - 1UL; mask2 = mask; if (!short_flag) { for (i = 1; i < k; i++) { if (fn > 0) fprintf(f, " "); if (i == 1) fprintf(f, " if (a >> %ld) ", n1-i); else fprintf(f, " if ((a >> %ld) & 1) ", n1-i); /* bit n1-i from a was not considered in blocks of k bits from b for index j >= i */ fprintf(f, "hi ^= ((b & 0x%lxUL) >> %ld);\\\n", mask2, i); mask2 = (mask2 << 1) & mask; } } if (fn > 0) fprintf(f, " "); if (fn == 0) { fprintf(f, " c[0] = lo; "); fprintf(f, " c[1] = hi;\\\n"); } else if (fn == 1 || fn == 3) { fprintf(f, " cp[i] = carry ^ lo; "); fprintf(f, " carry = hi;\\\n"); } else if (fn == 2) { fprintf(f, " cp[i] ^= (carry ^ lo); "); fprintf(f, " carry = hi;\\\n"); } if (fn > 0) { fprintf(f, " }\\\n"); if (fn == 1 || fn == 3) fprintf(f, " cp[sb] = carry;\\\n"); else fprintf(f, " cp[sb] ^= carry;\\\n"); } fprintf(f, "\n\n\n"); } /* * This generates anternative code that runs significantly faster * on some machines, like a PowerPC (and probably other RISC machines). * It makes it easier for the compiler to schedule instrucyions better, * and it avoids branches. It seems like this does not help * on x86 machines (and can even make things worse). */ void print_alt_mul_body(FILE *f, long n1, long k, long fn, long half_flag, long short_flag) { long n, i, chop, r; unsigned long mask, mask2; if (half_flag) n = n1/2; else n = n1; chop = n % k; /* first block */ if (chop == 0) chop = k; r = n - k; mask = (1UL << k) - 1UL; fprintf(f, "\n\n#define NTL_ALT_"); if (half_flag) fprintf(f, "HALF_"); if (short_flag) fprintf(f, "SHORT_"); fprintf(f, "BB_MUL_CODE%ld \\\n", fn); if (fn > 0) /* Mul1/AddMul1 */ { fprintf(f, " long i;\\\n"); fprintf(f, " _ntl_ulong carry = 0;\\\n"); } fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); fprintf(f, " A[0] = 0;\\\n"); fprintf(f, " A[1] = a;\\\n"); for (i = 2; i < (1L << k); i++) { if (i % 2 == 0) fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); else fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); } if (fn > 0) { fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); fprintf(f, " const _ntl_ulong b = bp[i];\\\n"); } for (i = k; i < n - chop; i += k) { if (fn > 0) fprintf(f, " "); fprintf(f, " const _ntl_ulong t%ld = A[(b >> %ld) & %lu]; \\\n", i, i, mask); } if (fn > 0) fprintf(f, " "); fprintf(f, " const _ntl_ulong t%ld = A[b >> %ld]; \\\n", n-chop, n-chop); if (fn > 0) fprintf(f, " "); fprintf(f, " const _ntl_ulong lo = A[b & %lu] \\\n", mask); for (i = k; i < n; i += k) { if (fn > 0) fprintf(f, " "); fprintf(f, " ^ (t%ld << %ld)", i, i); if (i == n - chop) fprintf(f, ";\\\n"); else fprintf(f, "\\\n"); } for (i = k; i < n; i += k) { if (fn > 0) fprintf(f, " "); if (i == k) fprintf(f, " const _ntl_ulong hi = "); else fprintf(f, " ^ "); fprintf(f, "(t%ld >> %ld)", i, n1-i); if (i == n - chop && short_flag) fprintf(f, ";\\\n"); else fprintf(f, "\\\n"); } mask = 0; for (i = 0; i < n; i += k) mask |= 1UL << i; mask = ~mask; if (half_flag) mask &= (1UL << n) - 1UL; mask2 = mask; if (!short_flag) { for (i = 1; i < k; i++) { /* bit n1-i from a was not considered in blocks of k bits from b for index j >= i */ if (fn > 0) fprintf(f, " "); if (i == 1) fprintf(f, " ^ (((b & 0x%lxUL) >> %ld) & (-(a >> %ld)))", mask2, i, n1-1); else { fprintf(f, " ^ (((b & 0x%lxUL) >> %ld) & (-((a >> %ld) & 1UL)))", mask2, i, n1-i); } if (i == k-1) fprintf(f, ";\\\n"); else fprintf(f, "\\\n"); mask2 = (mask2 << 1) & mask; } } if (fn > 0) fprintf(f, " "); if (fn == 0) { fprintf(f, " c[0] = lo; "); fprintf(f, " c[1] = hi;\\\n"); } else if (fn == 1) { fprintf(f, " cp[i] = carry ^ lo; "); fprintf(f, " carry = hi;\\\n"); } else if (fn == 2) { fprintf(f, " cp[i] ^= (carry ^ lo); "); fprintf(f, " carry = hi;\\\n"); } if (fn > 0) { fprintf(f, " }\\\n"); if (fn == 1 || fn == 3) fprintf(f, " cp[sb] = carry;\\\n"); else fprintf(f, " cp[sb] ^= carry;\\\n"); } fprintf(f, "\n\n\n"); } void print_alt1_mul_body(FILE *f, long n1, long k, long fn, long half_flag, long short_flag) { long n, i, chop, r; unsigned long mask, mask2; if (half_flag) n = n1/2; else n = n1; chop = n % k; /* first block */ if (chop == 0) chop = k; r = n - k; mask = (1UL << k) - 1UL; fprintf(f, "\n\n#define NTL_ALT1_"); if (half_flag) fprintf(f, "HALF_"); if (short_flag) fprintf(f, "SHORT_"); fprintf(f, "BB_MUL_CODE%ld \\\n", fn); if (fn > 0) /* Mul1/AddMul1 */ { fprintf(f, " long i;\\\n"); fprintf(f, " _ntl_ulong carry = 0, b;\\\n"); } fprintf(f, " _ntl_ulong hi, lo, t;\\\n"); fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); fprintf(f, " A[0] = 0;\\\n"); fprintf(f, " A[1] = a;\\\n"); for (i = 2; i < (1L << k); i++) { if (i % 2 == 0) fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); else fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); } if (fn > 0) { fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); fprintf(f, " b = bp[i];\\\n"); fprintf(f, " "); } fprintf(f, " lo = A[b & %lu]; ", mask); fprintf(f, "t = A[(b >> %ld) & %lu]; ", k, mask); fprintf(f, "hi = t >> %ld; lo ^= t << %ld;\\\n", n1-k, k); for (i = 2*k; i < n - chop; i += k) { if (fn > 0) fprintf(f, " "); fprintf(f, " t = A[(b >> %ld) & %lu]; ", i, mask); fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); } if (fn > 0) fprintf(f, " "); fprintf(f, " t = A[b >> %ld]; ", n-chop); fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); mask = 0; for (i = 0; i < n; i += k) mask |= 1UL << i; mask = ~mask; if (half_flag) mask &= (1UL << n) - 1UL; mask2 = mask; if (!short_flag) { for (i = 1; i < k; i++) { /* bit n1-i from a was not considered in blocks of k bits from b for index j >= i */ if (fn > 0) fprintf(f, " "); if (i == 1) fprintf(f, " hi ^= (((b & 0x%lxUL) >> %ld) & (-(a >> %ld)))", mask2, i, n1-1); else { fprintf(f, " ^ (((b & 0x%lxUL) >> %ld) & (-((a >> %ld) & 1UL)))", mask2, i, n1-i); } if (i == k-1) fprintf(f, ";\\\n"); else fprintf(f, "\\\n"); mask2 = (mask2 << 1) & mask; } } if (fn > 0) fprintf(f, " "); if (fn == 0) { fprintf(f, " c[0] = lo; "); fprintf(f, " c[1] = hi;\\\n"); } else if (fn == 1 || fn == 3) { fprintf(f, " cp[i] = carry ^ lo; "); fprintf(f, " carry = hi;\\\n"); } else if (fn == 2) { fprintf(f, " cp[i] ^= (carry ^ lo); "); fprintf(f, " carry = hi;\\\n"); } if (fn > 0) { fprintf(f, " }\\\n"); if (fn == 1 || fn == 3) fprintf(f, " cp[sb] = carry;\\\n"); else fprintf(f, " cp[sb] ^= carry;\\\n"); } fprintf(f, "\n\n\n"); } void print_BB_mul_code(FILE *f, long n) { long k; if (n >= 64) k = 4; else k = 3; print_mul_body(f, n, k, 0, 0, 0); print_mul_body(f, n, 4, 1, 0, 0); print_mul_body(f, n, 4, 2, 0, 0); print_mul_body(f, n, 4, 1, 0, 1); print_mul_body(f, n, 2, 0, 1, 0); print_alt_mul_body(f, n, k, 0, 0, 0); print_alt_mul_body(f, n, 4, 1, 0, 0); print_alt_mul_body(f, n, 4, 2, 0, 0); print_alt_mul_body(f, n, 4, 1, 0, 1); print_alt_mul_body(f, n, 2, 0, 1, 0); print_alt1_mul_body(f, n, k, 0, 0, 0); print_alt1_mul_body(f, n, 4, 1, 0, 0); print_alt1_mul_body(f, n, 4, 2, 0, 0); print_alt1_mul_body(f, n, 4, 1, 0, 1); print_alt1_mul_body(f, n, 2, 0, 1, 0); fprintf(f, "#define NTL_BB_MUL1_BITS (4)\n\n"); } void print_BB_sqr_code(FILE *f, long n) { long i, pos; fprintf(f, "\n\n"); fprintf(f, "#define NTL_BB_SQR_CODE \\\n"); fprintf(f, "lo=sqrtab[a&255];\\\n"); pos = 16; for (i = 8; i < n; i += 8) { if (2*(i+8) <= n) { fprintf(f, "lo=lo|(sqrtab[(a>>%ld)&255]<<%ld);\\\n", i, pos); pos += 16; } else if (2*i == n) { fprintf(f, "hi=sqrtab[(a>>%ld)&255];\\\n", i); pos = 16; } else if (2*i > n) { fprintf(f, "hi=hi|(sqrtab[(a>>%ld)&255]<<%ld);\\\n", i, pos); pos += 16; } else { /* only applies if word size is not a multiple of 16 */ fprintf(f, "_ntl_ulong t=sqrtab[(a>>%ld)&255];\\\n", i); fprintf(f, "lo=lo|(t<<%ld);\\\n", pos); fprintf(f, "hi=t>>%ld;\\\n", n-8); pos = 8; } } fprintf(f, "\n\n"); } void print_BB_rev_code(FILE *f, long n) { long i; fprintf(f, "\n\n"); fprintf(f, "#define NTL_BB_REV_CODE "); for (i = 0; i < n; i += 8) { if (i != 0) fprintf(f, "\\\n|"); fprintf(f, "(revtab[(a>>%ld)&255]<<%ld)", i, n-8-i); } fprintf(f, "\n\n"); } const char *yn_vec[2] = { "no", "yes" }; int main() { long bpl, bpi, bpt, rs_arith, nbits, single_mul_ok; long dp, dp1, dr; FILE *f; long warnings = 0; unsigned long ulval; unsigned int uival; size_t tval; long slval; fprintf(stderr, "This is NTL version %s\n\n", NTL_VERSION); /* * compute bpl = bits per long */ ulval = val_ulong(1); bpl = 0; while (ulval) { ulval <<= 1; touch_ulong(&ulval); bpl++; } /* * compute bpi = bits per int */ uival = val_uint(1); bpi = 0; while (uival) { uival <<= 1; touch_uint(&uival); bpi++; } /* * compute bpt = bits per size_t */ tval = val_size_t(1); bpt = 0; while (tval) { tval <<= 1; touch_size_t(&tval); bpt++; } /* * check if bpl and bpi are not too small --- any standard conforming * platform should pass this test. */ if (bpi < 16) { fprintf(stderr, "BAD NEWS: int type too short.\n"); return 1; } if (bpl < 32) { fprintf(stderr, "BAD NEWS: long type too short.\n"); return 1; } /* * check that ints are bigger than chars. */ if (bpi <= CHAR_BIT) { fprintf(stderr, "BAD NEWS: int type must be longer than char type.\n"); return 1; } /* * check that bpl is a multiple of 8. */ if (bpl % 8 != 0) { fprintf(stderr, "BAD NEWS: word size must be multiple of 8 bits.\n"); return 1; } /* * check if width of signed versions of int and long agree with that of * the unsigned versions, and that negative numbers are represented * using 2's compliment. * * The C99 standard, at least, is very precise about the possible * representations of unsigned and signed integer types, and so if * the following tests pass, we can be sure that the desired * properties hold. NTL relies implicitly and crucially on * these properties. * * I know of no machines for which these properties do not hold. */ if (((unsigned int) val_int(INT_MIN)) != val_uint(1U << (bpi-1))) { fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); return 1; } if (((unsigned int) val_int(INT_MAX)) != val_uint((1U << (bpi-1)) - 1U)) { fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); return 1; } if (((unsigned long) val_long(LONG_MIN)) != val_ulong(1UL << (bpl-1))) { fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); return 1; } if (((unsigned long) val_long(LONG_MAX)) != val_ulong((1UL<<(bpl-1))-1UL)) { fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); return 1; } /* * check that floating point to integer conversions truncates toward zero * --- any standard conforming platform should pass this test. */ if (((long) val_double(1.75)) != 1L) { fprintf(stderr, "BAD NEWS: machine must truncate floating point toward zero.\n"); return 1; } if (((long) val_double(-1.75)) != -1L) { fprintf(stderr, "BAD NEWS: machine must truncate floating point toward zero.\n"); return 1; } /* * Test if right shift is arithemtic or not. According to the * standards, the result of right-shifting a negative number is * "implementation defined", which almost surely means the right shift * is *always* arithmetic or *always* logical. However, this cannot * be guaranteed, and so this test is *not* 100% portable --- but I * know of no machine for which this test does not correctly * predict the general behavior. One should set the NTL_CLEAN_INT * flag if one wants to avoid such machine dependencies. */ slval = val_long(-1); if ((slval >> 1) == slval) rs_arith = 1; else rs_arith = 0; /* * Next, we check some properties of floating point arithmetic. * An implementation should conform to the IEEE floating * point standard --- essentially all modern platforms do, * except for a few very old Cray's. There is no easy way * to check this, so we simply make a few simple sanity checks, * calculate the precision, and if the platform performs * double precision arithemtic in extended double precision registers. * The last property is one that the IEE standard allows, and which * some important platforms (like x86) have --- this is quite * unfortunate, as it really makes many of the other properties * of the IEEE standard unusable. */ /* * First, we simply check that we are using a machine with radix 2. */ if (FLT_RADIX != 2) { fprintf(stderr, "BAD NEWS: machine must use IEEE floating point.\n"); return 1; } /* * Next, we calculate the precision of "in memory" doubles, * and check that it is at least 53. */ dp = DoublePrecision(); if (dp < 53) { fprintf(stderr, "BAD NEWS: machine must use IEEE floating point (*).\n"); return 1; } /* * Next, we check that the *range* of doubles is sufficiently large. * Specifically, we require that DBL_MAX > 2^{7*max(bpl, dp)} * and 1/DBL_MIN > 2^{7*max(bpl, dp)}. * On IEEE floating point compliant machines, this * will hold, and the following test will pass, if bpl is at most 128, which * should be true for the foreseeable future. */ if (log(DBL_MAX)/log(2.0) < 7.01*bpl || log(DBL_MAX)/log(2.0) < 7.01*dp || -log(DBL_MIN)/log(2.0) < 7.01*bpl || -log(DBL_MIN)/log(2.0) < 7.01*dp) { fprintf(stderr, "BAD NEWS: range of doubles too small.\n"); return 1; } /* * Next, we check if the machine has wider "in-register" doubles or not. * This test almost always yields the correct result --- if not, * you will have to set the NTL_EXT_DOUBLE in "mach_desc.h" * by hand. * * The test effectively proves that in-register doubles are wide * if dp1 > dp || dr. */ dp1 = DoublePrecision1(); dr = DoubleRounding(dp); /* * Set nbits --- the default radix size for NTL's "built in" * long integer arithmetic. * * Given the minimum size of blp and dp, the smallest possible * value of nbits is 30. */ if (bpl-2 < dp-3) nbits = bpl-2; else nbits = dp-3; if (nbits % 2 != 0) nbits--; /* * That's it! All tests have passed. */ fprintf(stderr, "GOOD NEWS: compatible machine.\n"); fprintf(stderr, "summary of machine characteristics:\n"); fprintf(stderr, "bits per long = %ld\n", bpl); fprintf(stderr, "bits per int = %ld\n", bpi); fprintf(stderr, "bits per size_t = %ld\n", bpt); fprintf(stderr, "arith right shift = %s\n", yn_vec[rs_arith]); fprintf(stderr, "double precision = %ld\n", dp); fprintf(stderr, "NBITS (maximum) = %ld\n", nbits); fprintf(stderr, "register double precision = %ld\n", dp1); fprintf(stderr, "double rounding detected = %s\n", yn_vec[dr]); if (((dp1 > dp) || dr) && AutoFix) fprintf(stderr, "-- auto x86 fix\n"); if (dp != 53) { warnings = 1; fprintf(stderr, "\n\nWARNING:\n\n"); fprintf(stderr, "Nonstandard floating point precision.\n"); fprintf(stderr, "IEEE standard is 53 bits.\n"); } #if (defined(__sparc__) && !defined(__sparc_v8__) && \ !defined(__sparcv8) && !defined(__sparc_v9__) && !defined(__sparcv9)) warnings = 1; fprintf(stderr, "\n\nWARNING:\n\n"); fprintf(stderr, "If this Sparc is a Sparc-10 or later (so it has\n"); fprintf(stderr, "a hardware integer multiply instruction) you\n"); fprintf(stderr, "should specify the -mv8 option in the makefile\n"); fprintf(stderr, "to obtain more efficient code.\n"); #endif if (((dp1 > dp) || dr) && !AutoFix) { warnings = 1; fprintf(stderr, "\n\nWARNING:\n\n"); fprintf(stderr, "This platform has extended double precision registers.\n"); fprintf(stderr, "While that may sound like a good thing, it actually is not.\n"); fprintf(stderr, "If this is a Pentium or other x86 and your compiler\n"); fprintf(stderr, "is g++ or supports GNU 'asm' constructs, it is recommended\n"); fprintf(stderr, "to compile NTL with the NTL_X86_FIX flag to get true IEEE floating point.\n"); fprintf(stderr, "Set this flag by editing the file config.h.\n"); fprintf(stderr, "The code should still work even if you don't set\n"); fprintf(stderr, "this flag. See quad_float.txt for details.\n\n"); } #if 0 /* better not to be interactive */ if (warnings) { int c; fprintf(stderr, "Do you want to continue anyway[y/n]? "); c = getchar(); if (c == 'n' || c == 'N') { fprintf(stderr, "Make the necessary changes to the makefile and/or config.h,\n"); fprintf(stderr, "then type 'make clobber' and then 'make'.\n\n\n"); return 1; } } #endif f = fopen("mach_desc.h", "w"); if (!f) { fprintf(stderr, "can't open mach_desc.h for writing\n"); return 1; } fprintf(f, "#ifndef NTL_mach_desc__H\n"); fprintf(f, "#define NTL_mach_desc__H\n\n\n"); fprintf(f, "#define NTL_BITS_PER_LONG (%ld)\n", bpl); fprintf(f, "#define NTL_MAX_LONG (%ldL)\n", ((long) ((1UL<<(bpl-1))-1UL))); fprintf(f, "#define NTL_MAX_INT (%ld)\n", ((long) ((1UL<<(bpi-1))-1UL))); fprintf(f, "#define NTL_BITS_PER_INT (%ld)\n", bpi); fprintf(f, "#define NTL_BITS_PER_SIZE_T (%ld)\n", bpt); fprintf(f, "#define NTL_ARITH_RIGHT_SHIFT (%ld)\n", rs_arith); fprintf(f, "#define NTL_NBITS_MAX (%ld)\n", nbits); fprintf(f, "#define NTL_DOUBLE_PRECISION (%ld)\n", dp); fprintf(f, "#define NTL_FDOUBLE_PRECISION "); print2k(f, dp-1, bpl); fprintf(f, "\n"); fprintf(f, "#define NTL_QUAD_FLOAT_SPLIT ("); print2k(f, dp - (dp/2), bpl); fprintf(f, "+1.0)\n"); fprintf(f, "#define NTL_EXT_DOUBLE (%d)\n", ((dp1 > dp) || dr)); fprintf(f, "#define NTL_SINGLE_MUL_OK (%d)\n", single_mul_ok != 0); fprintf(f, "#define NTL_DOUBLES_LOW_HIGH (%d)\n\n\n", single_mul_ok < 0); print_BB_mul_code(f, bpl); print_BB_sqr_code(f, bpl); print_BB_rev_code(f, bpl); fprintf(f, "#define NTL_MIN_LONG (-NTL_MAX_LONG - 1L)\n"); fprintf(f, "#define NTL_MIN_INT (-NTL_MAX_INT - 1)\n"); fprintf(f, "#endif\n\n"); fclose(f); fprintf(stderr, "\n\n"); return 0; } ntl-6.2.1/src/MakeDescAux.c000644 000765 000024 00000000747 12377144456 015730 0ustar00shoupstaff000000 000000 #include int val_int(int x) { return x; } unsigned int val_uint(unsigned int x) { return x; } long val_long(long x) { return x; } unsigned long val_ulong(unsigned long x) { return x; } size_t val_size_t(size_t x) { return x; } double val_double(double x) { return x; } void touch_int(int* x) {} void touch_uint(unsigned int* x) {} void touch_long(long* x) {} void touch_ulong(unsigned long* x) {} void touch_size_t(size_t* x) {} void touch_double(double* x) {} ntl-6.2.1/src/MakeGetTime000644 000765 000024 00000002620 12377144456 015501 0ustar00shoupstaff000000 000000 if test -f GetTime.c then rm GetTime.c fi echo "does anybody really know what time it is?" sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.c GetTime1.c $2 $1 -o TestGetTime TestGetTime.c GetTime1.c $2 if test -f TestGetTime then if ./TestGetTime 1 1048576 1048575 then cp GetTime1.c GetTime.c echo "using GetTime1.c" exit 0 fi fi sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.c GetTime2.c $2 $1 -o TestGetTime TestGetTime.c GetTime2.c $2 if test -f TestGetTime then if ./TestGetTime 1 1048576 1048575 then cp GetTime2.c GetTime.c echo "using GetTime2.c" exit 0 fi fi sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.c GetTime3.c $2 $1 -o TestGetTime TestGetTime.c GetTime3.c $2 if test -f TestGetTime then if ./TestGetTime 1 1048576 1048575 then cp GetTime3.c GetTime.c echo "using GetTime3.c" exit 0 fi fi sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.c GetTime4.c $2 $1 -o TestGetTime TestGetTime.c GetTime4.c $2 if test -f TestGetTime then if ./TestGetTime 1 1048576 1048575 then cp GetTime4.c GetTime.c echo "using GetTime4.c" exit 0 fi fi sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.c GetTime5.c $2 $1 -o TestGetTime TestGetTime.c GetTime5.c $2 if test -f TestGetTime then cp GetTime5.c GetTime.c echo "using GetTime5.c" echo "warning: this GetTime function always returns 0" exit 0 else echo "something is wrong..." exit 1 fi ntl-6.2.1/src/MatrixTest.c000644 000765 000024 00000001450 12377144457 015673 0ustar00shoupstaff000000 000000 #include #include #include NTL_CLIENT int main() { mat_ZZ B, X; vec_ZZ v, w; cin >> B; cin >> v; ZZ d; double t; cerr << "matrix inverse..."; t = GetTime(); inv(d, X, B); cerr << (GetTime()-t) << "\n"; cout << d << "\n"; cout << X << "\n"; cout << "\n\n\n"; cerr << "hensel solve..."; t = GetTime(); HenselSolve1(d, w, B, v); cerr << (GetTime()-t) << "\n"; cout << d << "\n"; cout << w << "\n"; cout << "\n\n\n"; ZZX f; cerr << "char poly..."; t = GetTime(); CharPoly(f, B); cerr << (GetTime()-t) << "\n"; cout << f << "\n"; cout << "\n\n\n"; cerr << "HNF..."; t = GetTime(); HNF(X, B, d); cerr << (GetTime()-t) << "\n"; cout << X; return 0; } ntl-6.2.1/src/MatrixTestIn000644 000765 000024 00000001452 12377144457 015743 0ustar00shoupstaff000000 000000 [[927267 -895605 -866862 -733022 647694 -555086 970641 524600 582869 890322] [-749289 -533762 -754674 -564542 874399 888872 860097 -801459 731651 -920001] [-1008354 -839027 -531044 592717 543848 647360 641018 957632 893065 -813238] [-750708 -783256 -868889 -649872 -807570 579545 840467 -734946 -720279 760893] [648723 -1016200 -587545 -1025537 710862 987663 -1047329 -803105 910327 803227] [-824476 -863571 -978793 -550626 -1000451 -780190 734624 -746905 620723 766901] [-900849 -593349 686359 1031502 832388 835860 -1034307 975079 -541187 -935991] [1015281 -971840 -970316 -851433 848978 -656104 -1044347 1014101 760024 -726970] [674372 -809805 713198 896663 590902 -783974 -651080 627852 1008582 -681953] [617949 -803220 -947289 786228 -540550 635343 -641246 536407 731378 -545576] ] [1 0 1 0 1 0 1 0 1 1] ntl-6.2.1/src/MatrixTestOut000644 000765 000024 00000017022 12377144457 016144 0ustar00shoupstaff000000 000000 113200891409702717792163966000355453253167532371751053300095404 [[9509068573319153106464382357375229187086855611933097546 4271842113282984626360758539562365814114171429102170870 -17759702680062972863550010512920362656015043038991243880 41477187861721572946030655775707662755085404597108307160 -5243782742622400377848684512280147647926604264242557316 -57570474516915330032297900074382277948092226082851451198 -39691442023468050071303361769224768064783020685116735498 1368136574325345397683214068314548753685759225204791630 38882325913404281065622952126474660414786444511334629982 21658060525924366067499408569988309603526842936659482904] [16472827960331056248258838159209192114875841064752417973 11055661592473954088842425168207875905160844070216428777 -16560334922191139189855127652632587481364130161107253300 -102245748658385867081609185652450631512925122490140100688 -6927806773133223877423268518425302220467823310751166148 28742921711161354730773870543456692789867725621589693379 14310736605755305933866385638819253964858157392606846769 -16014991501246590459421014324140905882300657048699826879 -81503308043560647324620876343032886277665012480242791525 19194058609377655982717031197566907183658664910378329254] [-109734933934562270503406590168469216229765499568865356641 -79814977936376262987151168741382893862364782954378186677 133626969697143446178706879427077311304614297868917769972 149665059613481916985855546923739615387602354833519713620 41594932401764115975248510994547285258748104347283084044 -114293087661479606464120160022800358925423770750498443543 -131521483304858915292609610805812270795903190662579776593 27868073260247900348789264908353779013914728480966707387 126507466382585557035788800218240658029902198985527596649 -103983285416770288102268920890479984309962375465970108130] [114179091124182582838159635859138807708117275312431988888 72039857186790938018866342099151764006275450407675210704 -135958647564984313864674762976737220386273609465893392876 -137836977113748623086616532582520232134322908706353110508 -39648958505403130424111817393832633444137482306335426792 98771210737273227760225008543985447809800217211255619424 138383817476246957183754907890374698153472269727036432232 -83531568830256521066176037083463270650302126963488770196 -59665850209941010245210238755312622861489834786890672540 104212488172405994217125642352348699856251768748581561844] [111146907229695951696474016292279176346380873649543797504 78969317235163683361563886953576359244786258829455206460 -111284423156656542447821201425798324474500022987488315616 -128864395236737761888784942727936809950578458670337206372 -16132840533073216704190053885210668883271756416346952680 71936575188688673331139096261137395113789612697561557288 128028235167433369167870171440603042287857319552486125624 -41129844043092203151024600561803347120823946971906314680 -69716278056658512473084306613953260253123063966900954104 34043655739979891222203807318846715642905966692040868996] [-48945544119598748666062390519512449564008849843608859415 -34927798213824985216852923656744552110662885021091481427 83872849154007409489147877549998397111409710950909271768 72378117750764994652170299394193193907241706518396524004 39167881720986278038950691657480446660498428518175599392 -81609637303540982160086561536058086094023691612652712665 -66440879526238756393022955803236662628829375990239458479 1111020514420903761458906973190717225987391378209788497 20190606337847249085182187793374022035135207033785218683 -14837054054733076096806488318719796374279547144082285446] [4565965807956488541051226759685506863651410011624760868 3492181881011202418943817267527580110911157147323976900 39461193147298576391825815620320144432845605945305549448 56604265994474462404748264295892220624225863674908427124 -17328413096863500505028926621982940665124422268469920716 -48643771179225048379840010236577072580175169863772980140 -52021419276660697100984251779634298701037261640215712780 -9349417465113435540652912465753929600296084265070495752 38749631289242781437940266166713604911714618202430909116 -18933915915475912601355036112428373924790403131648561896] [-41336383131401391642050443152991618920841425678015082424 -83981921540218745933168166698961730340818141341644355484 119619051324150226809528823887692424873092665569791069844 57359568975642082106242309019095290886689391528980785256 13601689001352389599706696797494222236044903367813347568 -59795682186578959961110105467067404963104249848788910772 -65397723614377571502938854693721405692307224823682592396 42592878104789608838213389518482176731590188510637180208 9920812157887076126172384077761201801497607298814386108 -45132518927593441552501636215301078568022033762084120792] [-49861066123459998006862729910986171295203945428483340835 -35407425167837977411438500961193686418300361423162989791 92357206488938784494418325514759738413689140887758688444 -5657564760989076343828111309403153669939072934734661300 41671230880738697588228732473944374615246021756976674148 -10711124317120463934382132614621248039431313315612206405 -76224317951311690961135035362182609056216309727633080639 2637208115428887814017590413315049349698597330449554141 25858155834234711795118681073700474922768148144251824295 -25990119790243388449513847601985281200137341894872589166] [61623531631064187432686831211234110772009391741788753961 -22095530335186280470348249242411284415648788206132842467 -20711755361024954539607118196944853953156730345410464400 -66746268941133150887857051757708016432030879372710964244 26099945908427902073513340584391341626437984932690918396 50975963872583708863130921554269663855103316623806906743 52201087513253571112258091209051975785803391414176589285 -45191083604629728008798145680113826847397615310533055439 -50146971408392286617891235891675861782320000106664060689 11541953231519243604644211417760923555459588623123390410] ] 113200891409702717792163966000355453253167532371751053300095404 [27249473184013512266407136541118635644159086017541712403 -50584592209942650462069456184321559526502345177792664705 115689488135636337213972690426493653067477248330091983968 46478284530817963216164361200291518714365212127753615988 70661072818371598049922919033409244304109328087891245876 -108305918613468066616370185132973898524229550691366617255 -119229339875612413145903997067198928544279071748882590601 -63796927162833233139985589317687726451218561510888812713 110134329954416532243495157079500276243728345769979945249 -81663651625066088258790377298297690632997722240667516882] [113200891409702717792163966000355453253167532371751053300095404 53416187193543401439887430820819294205975695546488797425 -123607612902745582703514051875473670204659819545865 -68402251288605920205399779446887509578119997 -40944447194334612294903085651515816465 -15153544924233995088343823419092 -22979394554373573500894590 -8722575497586664894 -6104870715982 413939 1] [[56600445704851358896081983000177726626583766185875526650047702 0 0 0 0 0 0 0 0 0] [11465750313487428661702512911842922520691216342563125571848443 2 0 0 0 0 0 0 0 0] [55231767316270678911483408554295434801191847687452448852191136 1 1 0 0 0 0 0 0 0] [37908835104003064912155774912601500340365754030028784231954718 0 0 1 0 0 0 0 0 0] [48615901178068930937993265623819971877392545512335892026898174 0 0 0 1 0 0 0 0 0] [51840818598597540130642998688588606375873071993964789114593617 1 0 0 0 1 0 0 0 0] [55361570761366016585700727191488280019398548582423308017837536 0 0 0 0 0 1 0 0 0] [36090811750869350784108074019471312745428867031617225757665622 0 0 0 0 0 0 1 0 0] [19232281111318501488032229905889533180588029146643536978782361 1 0 0 0 0 0 0 1 0] [42496144125982001757158835167287232900763450071403701240310105 1 0 0 0 0 0 0 0 1] ]ntl-6.2.1/src/MoreFacTest.c000644 000765 000024 00000001756 12377144457 015754 0ustar00shoupstaff000000 000000 #include NTL_CLIENT long NumFacs(const vec_pair_ZZX_long& v) { long i; long res; res = 0; for (i = 0; i < v.length(); i++) res += v[i].b; return res; } int main() { long cnt = 0; while (SkipWhiteSpace(cin)) { cnt++; cerr << "."; vec_ZZ w; ZZX f1, f; long nfacs; cin >> w; cin >> nfacs; long i, n; n = w.length(); f.rep.SetLength(n); for (i = 0; i < n; i++) f.rep[i] = w[n-1-i]; f.normalize(); vec_pair_ZZX_long factors; ZZ c; factor(c, factors, f, 0); mul(f1, factors); mul(f1, f1, c); if (f != f1) { cerr << f << "\n"; cerr << c << " " << factors << "\n"; Error("FACTORIZATION INCORRECT (1) !!!"); } long nfacs1 = NumFacs(factors); if (nfacs1 != nfacs) Error("FACTORIZATION INCORRECT (2) !!!"); } cerr << "\n"; cerr << "MoreFacTest OK\n"; return 0; } ntl-6.2.1/src/MoreFacTestIn000644 000765 000024 00000020224 12377144457 016011 0ustar00shoupstaff000000 000000 [ 1 ] 0 [ -1 ] 0 [ 1234567890987654321 ] 0 [ 1 0 ] 1 [ 1 1 ] 1 [ 1 1234567890987654321 ] 1 [ 1234567890987654321 1 ] 1 [ 1 -1234567890987654321 ] 1 [ -1234567890987654321 1 ] 1 [ 1234567890987654321 1234567890987654321 ] 1 [ -1234567890987654321 -1234567890987654321 ] 1 [ 1234500000 6789000000 ] 1 [ 1234500000 -6789000000 ] 1 [ -1234500000 6789000000 ] 1 [ -1234500000 -6789000000 ] 1 [ 1 0 1 ] 1 [ 1 0 -1 ] 2 [ 1 1125899906842624 1267650600228229401496703205376 ] 1 [ 1267650600228229401496703205376 1125899906842624 1 ] 1 [ 1 0 0 ] 2 [ -1 0 0 ] 2 [ 1 2 1 ] 2 [ -9 24 -16 ] 2 [ 1 15716643102160534111758180 61753217600172574271106391194796676956532699228100 ] 2 [ 1 23574964653240801167637270 123506435200345148542212782389593353913065398456200 ] 2 [ 123506435200345148542212782389593353913065398456200 23574964653240801167637270 1 ] 2 [ 1267167468929855903854750250191966490209 0 -61753217600172574271106391194796676956532699228100 ] 2 [ 35597295809230452047 0 -7858321551080267055879090 ] 1 [ 1 1 0 ] 2 [ 35597295809230452047 7858321551080267055879090 0 ] 2 [ 35597295809230452047 7858285953784457825427043 -7858321551080267055879090 ] 2 [ 1 0 279734996817854936178276161872067809674997229 ] 1 [ 279734996817854936178276161872067809674997231 0 279734996817854936178276161872067809674997229 ] 1 [ 348678440100000000000000000000 291733167875766667063796853374976 7979226629761200100000000000000000000 ] 1 [ 120 -720 810 ] 2 [ 1 1 -6 ] 2 [ -1 -1 6 ] 2 [ 5 19 -4 ] 2 [ -5 -19 4 ] 2 [ 42 -1 -1 ] 2 [ -42 1 1 ] 2 [ 1 0 0 0 ] 3 [ 1 -6 12 -8 ] 3 [ -8 12 -6 1 ] 3 [ 955593817727321453093807642925081991552428315714137911219172409259950196321 2910517013546164872066111470835330246421044768278430000000000000000000000000 2954919802742283328413552300000000000000000000000000000000000000000000000000 1000000000000000000000000000000000000000000000000000000000000000000000000000 ] 3 [ 1 1 0 0 ] 3 [ 3 17 21 -9 ] 3 [ 4787767769400 -56802290702175 190362236823900 -125287863234300 ] 3 [ 1 6 11 6 ] 3 [ -6 -11 -6 -1 ] 3 [ 7 48 77 -12 ] 3 [ 219912 657951 -859605 108732 ] 3 [ 41606516273784 76486500495993 -30324946543980 -57977141944800 ] 3 [ 1 2 2 1 ] 2 [ 3 8 0 -1 ] 2 [ 1005406248 -2867492493 797202216 805731303 ] 2 [ 199 -211 55667264366753132299476956212541494125324448571 -59024084328567391533616270155006307841424415319 ] 2 [ 1 6 11 279734996817854936178276161872067809674997236 ] 1 [ 61753217600172574271106391194796676956532699228100 -1 -3813459883974263793031618518285054261914116064020745192095813534545111079038096283794818335829610000 61753217600172574271106391194796676956532699228100 ] 3 [ 1 2 -2 -1 ] 2 [ 1000000 1000001 -1000001 -1000000 ] 2 [ 16 -96 216 -216 81 ] 4 [ -16 96 -216 216 -81 ] 4 [ 1 0 0 0 1 ] 1 [ 2339825252947983196289989414023384155425975650625 0 0 0 1257565912098743428344355615835487157290616629841 ] 1 [ 1 0 0 0 4 ] 2 [ 2339825252947983196289989414023384155425975650625 0 0 0 5030263648394973713377422463341948629162466519364 ] 2 [ 1 0 -2 0 9 ] 1 [ 1606938044258990275541962092341162602522202993782792835301376 0 -1306637247000141812193380534316115641074287420945909743086143932738994282954752 0 2390525899882872924049031898322016641463101073880550463771174655651832418111719646949462291396009 ] 1 [ 4 -28 61 -42 9 ] 4 [ 78251668444685311269707371487528656450521930098767964925231152371415252349959400507672900 34549072257044214828682415315874081146403635560456663308003943263668841080562387370131482083860 3813459883661257119254482986600538873291451020849207247624613697324211759570921656132843895891782081 -34549072257044214828682415315874081146403635560456663308003943263668841080562387370131482083860 78251668444685311269707371487528656450521930098767964925231152371415252349959400507672900 ] 4 [ 16 -48 64 -64 52 -28 12 -4 ] 5 [ 27648 -857088 11887488 -97206208 519469068 -1897564792 4798209187 -8242846327 8864358367 -3955897247 -3955897247 8864358367 -8242846327 4798209187 -1897564792 519469068 -97206208 11887488 -857088 27648 ] 19 [ -24016 -32548 0 211584 284066 0 -53325 307600 384808 469800 0 228140 266152 630450 0 21964 0 436050 ] 2 [ -190188 -247212 0 0 -376854 -489846 309744 0 0 -264247 133825 -90985 -118265 208008 0 601324 0 148180 ] 1 [ -190188 -247212 0 0 -376854 -489846 309744 0 0 -264247 133825 -90985 -118265 208008 0 601324 0 148180 203796 0 50220 ] 2 [ -23 0 70 0 -242 0 284 0 -309 0 301 0 -272 0 249 0 -189 0 177 0 -149 0 129 0 -116 0 108 0 -104 0 97 0 -75 0 7 0 -41 0 -110 0 51 0 19 0 -34 0 -11 0 115 0 -103 0 134 0 -135 0 134 0 -132 0 131 0 -141 0 156 0 -144 0 230 0 -220 0 255 0 -284 0 260 0 -181 0 53 0 -15 ] 3 [ -23 140883096 -45 275640840 -7 42877464 22 -134757744 -10 61253520 -9 55128168 22 -134757744 15 -91880280 ] 2 [ 1 0 -200000000000136 0 27200000000006477 0 -1295200000000142048 0 28382400000001519810 0 -302666800000007595088 0 1490635200000015464098 0 -2790152800000013050016 0 1119368000000013996989 0 -9245000000005596840 0 46225 ] 2 [ 1 0 -256 0 -999999999999999999999971968 0 255999999999999999999998270976 0 -28031999999999999999999932845823 0 1729023999999999999999998267416320 0 -67154175999999999999999969586180736 0 1732583423999999999999999635453582848 0 -30413791231999999999999997060769836800 0 364544688127999999999999984700590055424 0 -2939163009023999999999999952829480067072 0 15297677361151999999999999933076097564672 0 -47140106141695999999999999994797371400192 0 66559357747200000000000000178002258296832 0 -2263465590783999999999999325149651795968 0 -193299935657983999999999998732715790696448 0 -627710242062335999999999999173537662238720 0 -1333843567050751999999999999806700064342016 0 -824198872170495999999999999372289757937664 0 1333843567050752 0 824198872170496 ] 2 [ 1 0 -256 0 28032 0 -1729024 0 67154176 0 -1732583424 0 30413791232 0 -364544688128 0 2939163009024 0 -15297677361152 0 47140106141696 0 -66559357747200 0 2263465590784 0 193299935657984 0 627710242062336 0 1333843567050752 0 824198872170496 ] 1 [ 1 0 -456 0 80684 0 -7580440 0 426504758 0 -15173272376 0 348965414828 0 -5222990961896 0 51398572708049 0 -342604051286656 0 1550317051426208 0 -4831933058958336 0 10198629967583488 0 -15932586425303040 0 20876094152884224 0 -13926929280270336 0 316045337296896 ] 2 [ 1 0 0 0 -456 0 0 0 80684 0 0 0 -7580440 0 0 0 426504758 0 0 0 -15173272376 0 0 0 348965414828 0 0 0 -5222990961896 0 0 0 51398572708049 0 0 0 -342604051286656 0 0 0 1550317051426208 0 0 0 -4831933058958336 0 0 0 10198629967583488 0 0 0 -15932586425303040 0 0 0 20876094152884224 0 0 0 -13926929280270336 0 0 0 316045337296896 ] 2 [ -1 0 0 0 208 0 -432 0 -14944 0 63520 0 411752 0 -3169952 0 32544 0 60405744 0 -193237168 0 -153920768 0 2515813476 0 -6391147264 0 789453360 0 36373780048 0 -103370680864 0 114447129888 0 85495132376 0 -537480834720 0 952639088992 0 -815573687440 0 -94716509008 0 1280699815936 0 -1830275916102 0 1280699815936 0 -94716509008 0 -815573687440 0 952639088992 0 -537480834720 0 85495132376 0 114447129888 0 -103370680864 0 36373780048 0 789453360 0 -6391147264 0 2515813476 0 -153920768 0 -193237168 0 60405744 0 32544 0 -3169952 0 411752 0 63520 0 -14944 0 -432 0 208 0 0 0 -1 ] 1 [ 1 0 0 0 -288 0 592 0 27660 0 -115824 0 -1058592 0 7626336 0 8880418 0 -215487264 0 488513248 0 2157251280 0 -13734423844 0 15735635856 0 97082316256 0 -437410264064 0 547254790511 0 1350779531008 0 -7133429310144 0 13591562590752 0 -7381113216744 0 -29077015274080 0 97676724196928 0 -169734262965824 0 200990761577180 0 -169734262965824 0 97676724196928 0 -29077015274080 0 -7381113216744 0 13591562590752 0 -7133429310144 0 1350779531008 0 547254790511 0 -437410264064 0 97082316256 0 15735635856 0 -13734423844 0 2157251280 0 488513248 0 -215487264 0 8880418 0 7626336 0 -1058592 0 -115824 0 27660 0 592 0 -288 0 0 0 1 ] 2 [ 10000000000 0 10000000000 0 4700000000 0 1380000000 0 282000000 0 42200000 0 4740000 0 402000 0 24900 0 1080 0 27 ] 4 [ 1 0 -1 0 -2 0 9 0 -10 0 -20 0 89 0 112 0 -409 0 460 0 918 0 -4072 0 4520 0 9058 0 4171 0 327 0 770 0 871 0 -790 0 -440 0 467 0 300 0 -119 0 -44 0 110 0 20 0 -36 0 10 0 29 0 1 0 -10 0 1 0 2 0 0 0 1 0 2 0 1 ] 2 ntl-6.2.1/src/MulTimeTest.c000644 000765 000024 00000004571 12377144457 016012 0ustar00shoupstaff000000 000000 #include #include NTL_CLIENT double clean_data(double *t) { double x, y, z; long i, ix, iy, n; x = t[0]; ix = 0; y = t[0]; iy = 0; for (i = 1; i < 5; i++) { if (t[i] < x) { x = t[i]; ix = i; } if (t[i] > y) { y = t[i]; iy = i; } } z = 0; n = 0; for (i = 0; i < 5; i++) { if (i != ix && i != iy) z+= t[i], n++; } z = z/n; return z; } void print_flag() { #if defined(NTL_LONG_LONG) printf("LONG_LONG\n"); #elif defined(NTL_AVOID_FLOAT) printf("AVOID_FLOAT\n"); #else printf("DEFAULT\n"); #endif } int main() { #ifdef NTL_LONG_LONG if (sizeof(NTL_LL_TYPE) < 2*sizeof(long)) { printf("999999999999999 "); print_flag(); return 0; } #endif long i, k; k = 10*NTL_ZZ_NBITS; for (i = 0; i < 10000; i++) { ZZ a, b, c, d; long da = RandomBnd(k); long db = RandomBnd(k); long dc = RandomBnd(k); long dd = RandomBnd(k); RandomLen(a, da); RandomLen(b, db); RandomLen(c, dc); RandomLen(d, dd); if ((a + b)*(c + d) != c*a + d*a + c*b + d*b) { printf("999999999999999 "); print_flag(); return 0; } } for (i = 0; i < 10000; i++) { ZZ a, b, c; long da = RandomBnd(k); long db = RandomBnd(k); long dc = RandomBnd(k) + 2; RandomLen(a, da); RandomLen(b, db); RandomLen(c, dc); if ( ( a * b ) % c != ((a % c) * (b % c)) % c ) { printf("999999999999999 "); print_flag(); return 0; } } k = 16*NTL_ZZ_NBITS; ZZ x1, x2, x3; double t; long j; RandomLen(x1, k); RandomLen(x2, k); long iter; mul(x3, x1, x2); iter = 1; do { t = GetTime(); for (i = 0; i < iter; i++) { for (j = 0; j < 500; j++) mul(x3, x1, x2); } t = GetTime() - t; iter = 2*iter; } while(t < 1); iter = iter/2; iter = long((2/t)*iter) + 1; double tvec[5]; long w; for (w = 0; w < 5; w++) { t = GetTime(); for (i = 0; i < iter; i++) { for (j = 0; j < 500; j++) mul(x3, x1, x2); } t = GetTime() - t; tvec[w] = t; } t = clean_data(tvec); t = floor((t/iter)*1e14); if (t < 0 || t >= 1e15) printf("999999999999999 "); else printf("%015.0f ", t); printf(" [%ld] ", iter); print_flag(); return 0; } ntl-6.2.1/src/NOTES000644 000765 000024 00000001726 12377144457 014244 0ustar00shoupstaff000000 000000 Temporary development notes here -------------------------------- - besides thread safety, other things I want to do: * speed up ZZX mul: faster HomMul and faster SSMul * speed up GF2X mul using new x86 instructions ----------------------------- These are basically notes to myself on preparing a new distribution of NTL. ----------------------------- - change version numbers in ../include/NTL/version.h, DIRNAME, and WINDIR - change the libtool soname in VERSION_INFO. See: http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html - if changes were made to makefile or ../include/NTL/config.h, make sure these changes are implemented in the template files mfile and cfile, and then run: ./configure cp makefile def_makefile cp ../include/NTL/config.h ../include/NTL/def_config.h - update ../README and ../doc/copying.txt - run: make ppdoc make package make winpack NOTE: try executing export COPYFILE_DISABLE=1 beforehand ntl-6.2.1/src/Poly1TimeTest.c000644 000765 000024 00000006045 12377144457 016257 0ustar00shoupstaff000000 000000 #include #include #include NTL_CLIENT double clean_data(double *t) { double x, y, z; long i, ix, iy, n; x = t[0]; ix = 0; y = t[0]; iy = 0; for (i = 1; i < 5; i++) { if (t[i] < x) { x = t[i]; ix = i; } if (t[i] > y) { y = t[i]; iy = i; } } z = 0; n = 0; for (i = 0; i < 5; i++) { if (i != ix && i != iy) z+= t[i], n++; } z = z/n; return z; } void print_flag() { #if defined(NTL_SPMM_UL) printf("SPMM_UL "); #elif defined(NTL_SPMM_ULL) printf("SPMM_ULL "); #elif defined(NTL_SPMM_ASM) printf("SPMM_ASM "); #else printf("DEFAULT "); #endif #if defined(NTL_AVOID_BRANCHING) printf("AVOID_BRANCHING "); #endif #if defined(NTL_FFT_BIGTAB) printf("FFT_BIGTAB "); #endif #if defined(NTL_FFT_LAZYMUL) printf("FFT_LAZYMUL "); #endif printf("\n"); } int main() { #ifdef NTL_SPMM_ULL if (sizeof(NTL_ULL_TYPE) < 2*sizeof(long)) { printf("999999999999999 "); print_flag(); return 0; } #endif long n, k; n = 200; k = 10*NTL_ZZ_NBITS; ZZ p; RandomLen(p, k); ZZ_p::init(p); // initialization ZZ_pX f, g, h, r1, r2, r3; random(g, n); // g = random polynomial of degree < n random(h, n); // h = " " random(f, n); // f = " " SetCoeff(f, n); // Sets coefficient of X^n to 1 // For doing arithmetic mod f quickly, one must pre-compute // some information. ZZ_pXModulus F; build(F, f); PlainMul(r1, g, h); // this uses classical arithmetic PlainRem(r1, r1, f); MulMod(r2, g, h, F); // this uses the FFT MulMod(r3, g, h, f); // uses FFT, but slower // compare the results... if (r1 != r2) { printf("999999999999999 "); print_flag(); return 0; } else if (r1 != r3) { printf("999999999999999 "); print_flag(); return 0; } double t; long i; long iter; const int nprimes = 10; long r; for (r = 0; r < nprimes; r++) UseFFTPrime(r); vec_long aa[nprimes], AA[nprimes]; for (r = 0; r < nprimes; r++) { aa[r].SetLength(4096); AA[r].SetLength(4096); for (i = 0; i < 4096; i++) aa[r][i] = RandomBnd(FFTPrime[r]); FFTFwd(AA[r].elts(), aa[r].elts(), 12, r); } iter = 1; do { t = GetTime(); for (i = 0; i < iter; i++) { for (r = 0; r < nprimes; r++) FFTFwd(AA[r].elts(), aa[r].elts(), 12, r); } t = GetTime() - t; iter = 2*iter; } while(t < 1); iter = iter/2; iter = long((2/t)*iter) + 1; double tvec[5]; long w; for (w = 0; w < 5; w++) { t = GetTime(); for (i = 0; i < iter; i++) { for (r = 0; r < nprimes; r++) FFTFwd(AA[r].elts(), aa[r].elts(), 12, r); } t = GetTime() - t; tvec[w] = t; } t = clean_data(tvec); t = floor((t/iter)*1e13); if (t < 0 || t >= 1e15) printf("999999999999999 "); else printf("%015.0f ", t); printf(" [%ld] ", iter); print_flag(); return 0; } ntl-6.2.1/src/PolyTimeTest.c000644 000765 000024 00000004415 12377144457 016175 0ustar00shoupstaff000000 000000 #include #include NTL_CLIENT double clean_data(double *t) { double x, y, z; long i, ix, iy, n; x = t[0]; ix = 0; y = t[0]; iy = 0; for (i = 1; i < 5; i++) { if (t[i] < x) { x = t[i]; ix = i; } if (t[i] > y) { y = t[i]; iy = i; } } z = 0; n = 0; for (i = 0; i < 5; i++) { if (i != ix && i != iy) z+= t[i], n++; } z = z/n; return z; } void print_flag() { #ifdef NTL_TBL_REM printf("TBL_REM "); #else printf("DEFAULT "); #endif printf("\n"); } int main() { long n, k; n = 200; k = 10*NTL_ZZ_NBITS; ZZ p; RandomLen(p, k); ZZ_p::init(p); // initialization ZZ_pX f, g, h, r1, r2, r3; random(g, n); // g = random polynomial of degree < n random(h, n); // h = " " random(f, n); // f = " " SetCoeff(f, n); // Sets coefficient of X^n to 1 // For doing arithmetic mod f quickly, one must pre-compute // some information. ZZ_pXModulus F; build(F, f); PlainMul(r1, g, h); // this uses classical arithmetic PlainRem(r1, r1, f); MulMod(r2, g, h, F); // this uses the FFT MulMod(r3, g, h, f); // uses FFT, but slower // compare the results... if (r1 != r2) { printf("999999999999999 "); print_flag(); return 0; } else if (r1 != r3) { printf("999999999999999 "); print_flag(); return 0; } double t; long i; long iter; n = 1024; k = 1024; RandomLen(p, k); ZZ_p::init(p); ZZ_pX j1, j2, j3; random(j1, n); random(j2, n); mul(j3, j1, j2); iter = 1; do { t = GetTime(); for (i = 0; i < iter; i++) { FFTMul(j3, j1, j2); } t = GetTime() - t; iter = 2*iter; } while(t < 1); iter = iter/2; iter = long((2/t)*iter) + 1; double tvec[5]; long w; for (w = 0; w < 5; w++) { t = GetTime(); for (i = 0; i < iter; i++) { FFTMul(j3, j1, j2); } t = GetTime() - t; tvec[w] = t; } t = clean_data(tvec); t = floor((t/iter)*1e12); if (t < 0 || t >= 1e15) printf("999999999999999 "); else printf("%015.0f ", t); printf(" [%ld] ", iter); print_flag(); return 0; } ntl-6.2.1/src/QuadTest.c000644 000765 000024 00000003237 12377144457 015326 0ustar00shoupstaff000000 000000 #include NTL_CLIENT int main() { quad_float a, b, c, d; quad_float::SetOutputPrecision(25); if (PrecisionOK()) cout << "Precision OK\n"; else cout << "Precision not OK\n"; cin >> a; cout << a << "\n"; cin >> b; cout << b << "\n"; c = a + b; d = a; d += b; cout << c << "\n"; cout << d << "\n"; c = a - b; d = a; d -= b; cout << c << "\n"; cout << d << "\n"; c = a * b; d = a; d *= b; cout << c << "\n"; cout << d << "\n"; c = a / b; d = a; d /= b; cout << c << "\n"; cout << d << "\n"; c = -a; cout << c << "\n"; c = sqrt(a); cout << c << "\n"; power(c, to_quad_float(10), 20); cout << c << "\n"; { long n, n1; int shamt = min(NTL_BITS_PER_LONG,2*NTL_DOUBLE_PRECISION); n = to_long((1UL << (shamt-1)) - 1UL); c = to_quad_float(n); n1 = to_long(c); if (n1 == n) cout << "long conversion OK\n"; else cout << "long conversion not OK\n"; n = to_long(1UL << (shamt-1)); c = to_quad_float(n); n1 = to_long(c); if (n1 == n) cout << "long conversion OK\n"; else cout << "long conversion not OK\n"; } { unsigned long n; ZZ n1; int shamt = min(NTL_BITS_PER_LONG,2*NTL_DOUBLE_PRECISION); n = (1UL << (shamt-1)) - 1UL; c = to_quad_float(n); n1 = to_ZZ(c); if (n1 == to_ZZ(n)) cout << "ulong conversion OK\n"; else cout << "ulong conversion not OK\n"; n = 1UL << (shamt-1); c = to_quad_float(n); n1 = to_ZZ(c); if (n1 == to_ZZ(n)) cout << "ulong conversion OK\n"; else cout << "ulong conversion not OK\n"; } } ntl-6.2.1/src/QuadTestIn000644 000765 000024 00000000066 12377144457 015371 0ustar00shoupstaff000000 000000 1.333333333333333333333333 2.555555555555555555555555 ntl-6.2.1/src/QuadTestOut000644 000765 000024 00000000653 12377144457 015574 0ustar00shoupstaff000000 000000 Precision OK 1.333333333333333333333333 2.555555555555555555555555 3.888888888888888888888888 3.888888888888888888888888 -1.222222222222222222222222 -1.222222222222222222222222 3.407407407407407407407406 3.407407407407407407407406 0.5217391304347826086956522 0.5217391304347826086956522 -1.333333333333333333333333 1.154700538379251529018297 0.1e21 long conversion OK long conversion OK ulong conversion OK ulong conversion OK ntl-6.2.1/src/QuickTest.c000644 000765 000024 00000014105 12377144457 015504 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_CLIENT #define make_string_aux(x) #x #define make_string(x) make_string_aux(x) int SmallModulusTest(long p, long n) { zz_pBak bak; bak.save(); zz_p::init(p); zz_pX a, b, c, cc; random(a, n); random(b, n); PlainMul(c, a, b); FFTMul(cc, a, b); int res; res = (c != cc); bak.restore(); return res; } int GF2X_test() { GF2X a, b, c, c1; long n; #ifdef NTL_GF2X_LIB for (n = 32; n <= (1L << 18); n = n << 1) { random(a, n); random(b, n); OldMul(c, a, b); mul(c1, a, b); if (c1 != c) return 1; } #endif return 0; } void GF2X_time() { long n = 1000000L; long iter; GF2X a, b, c; double t; long i; random(a, n); random(b, n); mul(c, a, b); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) mul(c, a, b); t = GetTime() - t; } while (t < 0.5); cerr << "time to multiply polynomials over GF(2) \n of degree < 1000000: " << (t/iter) << "s\n"; #ifdef NTL_GF2X_LIB OldMul(c, a, b); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) OldMul(c, a, b); t = GetTime() - t; } while (t < 0.5); cerr << " **** using old code: " << (t/iter) << "s\n"; #endif } int main() { cerr << "This is NTL version " << NTL_VERSION << "\n"; cerr << "Basic Configuration Options:\n"; #ifdef NTL_STD_CXX cout << "NTL_STD_CXX\n"; #endif #ifdef NTL_PSTD_NNS cerr << "NTL_PSTD_NNS\n"; #endif #ifdef NTL_PSTD_NHF cerr << "NTL_PSTD_NHF\n"; #endif #ifdef NTL_PSTD_NTN cerr << "NTL_PSTD_NTN\n"; #endif #ifdef NTL_GMP_LIP cerr << "NTL_GMP_LIP\n"; #endif #ifdef NTL_GF2X_LIB cerr << "NTL_GF2X_LIB\n"; #endif #ifdef NTL_LONG_LONG_TYPE cerr << "NTL_LONG_LONG_TYPE: "; cerr << make_string(NTL_LONG_LONG_TYPE) << "\n"; #endif #ifdef NTL_UNSIGNED_LONG_LONG_TYPE cerr << "NTL_UNSIGNED_LONG_LONG_TYPE: "; cerr << make_string(NTL_UNSIGNED_LONG_LONG_TYPE) << "\n"; #endif #ifdef NTL_X86_FIX cerr << "NTL_X86_FIX\n"; #endif #ifdef NTL_NO_X86_FIX cerr << "NTL_NO_X86_FIX\n"; #endif #ifdef NTL_NO_INIT_TRANS cerr << "NTL_NO_INIT_TRANS\n"; #endif #ifdef NTL_CLEAN_INT cerr << "NTL_CLEAN_INT\n"; #endif #ifdef NTL_CLEAN_PTR cerr << "NTL_CLEAN_PTR\n"; #endif #ifdef NTL_RANGE_CHECK cerr << "NTL_RANGE_CHECK\n"; #endif cerr << "\n"; cerr << "Resolution of double-word types:\n"; cerr << make_string(NTL_LL_TYPE) << "\n"; cerr << make_string(NTL_ULL_TYPE) << "\n"; cerr << "\n"; cerr << "Performance Options:\n"; #ifdef NTL_LONG_LONG cerr << "NTL_LONG_LONG\n"; #endif #ifdef NTL_AVOID_FLOAT cerr << "NTL_AVOID_FLOAT\n"; #endif #ifdef NTL_SPMM_UL cerr << "NTL_SPMM_UL\n"; #endif #ifdef NTL_SPMM_ULL cerr << "NTL_SPMM_ULL\n"; #endif #ifdef NTL_SPMM_ASM cerr << "NTL_SPMM_ASM\n"; #endif #ifdef NTL_AVOID_BRANCHING cerr << "NTL_AVOID_BRANCHING\n"; #endif #ifdef NTL_FFT_BIGTAB cout << "NTL_FFT_BIGTAB\n"; #endif #ifdef NTL_FFT_LAZYMUL cout << "NTL_FFT_LAZYMUL\n"; #endif #ifdef NTL_TBL_REM cerr << "NTL_TBL_REM\n"; #endif #ifdef NTL_GF2X_ALTCODE cerr << "NTL_GF2X_ALTCODE\n"; #endif #ifdef NTL_GF2X_ALTCODE1 cerr << "NTL_GF2X_ALTCODE1\n"; #endif #ifdef NTL_GF2X_NOINLINE cerr << "NTL_GF2X_NOINLINE\n"; #endif cerr << "\n\n"; cerr << "running tests..."; long n, k; n = 200; k = 10*NTL_ZZ_NBITS; ZZ p; GenPrime(p, k); ZZ_p::init(p); // initialization ZZ_pX f, g, h, r1, r2, r3; random(g, n); // g = random polynomial of degree < n random(h, n); // h = " " random(f, n); // f = " " // SetCoeff(f, n); // Sets coefficient of X^n to 1 ZZ_p lc; do { random(lc); } while (IsZero(lc)); SetCoeff(f, n, lc); // For doing arithmetic mod f quickly, one must pre-compute // some information. ZZ_pXModulus F; build(F, f); PlainMul(r1, g, h); // this uses classical arithmetic PlainRem(r1, r1, f); MulMod(r2, g, h, F); // this uses the FFT MulMod(r3, g, h, f); // uses FFT, but slower // compare the results... if (r1 != r2) { cerr << "r1 != r2!!\n"; return 1; } else if (r1 != r3) { cerr << "r1 != r3!!\n"; return 1; } // small prime tests...I've made some changes in v5.3 // that should be checked on various platforms, so // we might as well check them here. if (SmallModulusTest(17, 1000)) { cerr << "first SmallModulusTest failed!!\n"; return 1; } if (SmallModulusTest((1L << (NTL_SP_NBITS))-1, 1000)) { cerr << "second SmallModulusTest failed!!\n"; return 1; } // Test gf2x code.... if (GF2X_test()) { cerr << "GF2X test failed!\n"; return 1; } cerr << "OK\n"; ZZ x1, x2, x3, x4; double t; long i; RandomLen(x1, 1024); RandomBnd(x2, x1); RandomBnd(x3, x1); mul(x4, x2, x3); t = GetTime(); for (i = 0; i < 100000; i++) mul(x4, x2, x3); t = GetTime()-t; cerr << "time for 1024-bit mul: " << t*10 << "us"; cerr << "\n"; rem(x2, x4, x1); t = GetTime(); for (i = 0; i < 100000; i++) rem(x2, x4, x1); t = GetTime()-t; cerr << "time for 2048/1024-bit rem: " << t*10 << "us"; cerr << "\n"; GenPrime(p, 1024); RandomBnd(x1, p); if (IsZero(x1)) set(x1); InvMod(x2, x1, p); t = GetTime(); for (i = 0; i < 1000; i++) InvMod(x2, x1, p); t = GetTime()-t; cerr << "time for 1024-bit modular inverse: " << t*1000 << "us"; cerr << "\n"; // test modulus switching n = 1024; k = 1024; RandomLen(p, k); ZZ_p::init(p); ZZ_pInfo->check(); ZZ_pX j1, j2, j3; random(j1, n); random(j2, n); t = GetTime(); for (i = 0; i < 20; i++) mul(j3, j1, j2); t = GetTime()-t; cerr << "time to multiply degree 1023 polynomials\n modulo a 1024-bit number: "; cerr << (t/20) << "s"; cerr << "\n"; GF2X_time(); return 0; } ntl-6.2.1/src/RR.c000644 000765 000024 00000102114 12377144456 014110 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL // FIXME: I just converted all the static RR's to thread local static RR's. // Perhaps I should at some point make the equivalent of an RR Register. // But be careful: certain computations, like ComputePi, actually cache // results, so that will take more work. In any case, RR is not a high // priority right now. long RR::prec = 150; void RR::SetPrecision(long p) { if (p < 53) p = 53; if (NTL_OVERFLOW(p, 1, 0)) Error("RR: precision too high"); prec = p; } long RR::oprec = 10; void RR::SetOutputPrecision(long p) { if (p < 1) p = 1; if (NTL_OVERFLOW(p, 1, 0)) Error("RR: output precision too high"); oprec = p; } static void normalize1(RR& z, const ZZ& y_x, long y_e, long prec, long residual) { long len = NumBits(y_x); if (len > prec) { long correction = ZZ_RoundCorrection(y_x, len - prec, residual); RightShift(z.x, y_x, len - prec); if (correction) add(z.x, z.x, correction); z.e = y_e + len - prec; } else if (len == 0) { clear(z.x); z.e = 0; } else { z.x = y_x; z.e = y_e; } if (!IsOdd(z.x)) z.e += MakeOdd(z.x); if (z.e >= NTL_OVFBND) Error("RR: overflow"); if (z.e <= -NTL_OVFBND) Error("RR: underflow"); } void normalize(RR& z, const RR& y, long residual = 0) { normalize1(z, y.x, y.e, RR::prec, residual); } void MakeRR(RR& z, const ZZ& a, long e) { if (e >= NTL_OVFBND) Error("MakeRR: e too big"); if (e <= -NTL_OVFBND) Error("MakeRR: e too small"); normalize1(z, a, e, RR::prec, 0); } void MakeRRPrec(RR& x, const ZZ& a, long e, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("MakeRRPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; MakeRR(x, a, e); RR::prec = old_p; } void random(RR& z) { NTL_THREAD_LOCAL static RR t; RandomBits(t.x, RR::prec); t.e = -RR::prec; normalize(z, t); } static inline void xcopy(RR& x, const RR& a) { normalize(x, a); } // xcopy emulates old assignment semantics... // many routines here implicitly assume assignment normalizes, // but that is no longer the case as of v3.0. void ConvPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; normalize(x, a); RR::prec = old_p; } void RoundToPrecision(RR& x, const RR& a, long p) { ConvPrec(x, a, p); } void conv(RR& x, const RR& a) { normalize(x, a); } long IsZero(const RR& a) { return IsZero(a.x); } long IsOne(const RR& a) { return a.e == 0 && IsOne(a.x); } long sign(const RR& a) { return sign(a.x); } void clear(RR& z) { z.e = 0; clear(z.x); } void set(RR& z) { z.e = 0; set(z.x); } void add(RR& z, const RR& a, const RR& b) { NTL_THREAD_LOCAL static RR t; if (IsZero(a.x)) { xcopy(z, b); return; } if (IsZero(b.x)) { xcopy(z, a); return; } if (a.e > b.e) { if (a.e-b.e - max(RR::prec-NumBits(a.x),0) >= NumBits(b.x) + 2) normalize(z, a, sign(b)); else { LeftShift(t.x, a.x, a.e-b.e); add(t.x, t.x, b.x); t.e = b.e; normalize(z, t); } } else if (a.e < b.e) { if (b.e-a.e - max(RR::prec-NumBits(b.x),0) >= NumBits(a.x) + 2) normalize(z, b, sign(a)); else { LeftShift(t.x, b.x, b.e-a.e); add(t.x, t.x, a.x); t.e = a.e; normalize(z, t); } } else { add(t.x, a.x, b.x); t.e = a.e; normalize(z, t); } } void AddPrec(RR& x, const RR& a, const RR& b, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("AddPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; add(x, a, b); RR::prec = old_p; } void sub(RR& z, const RR& a, const RR& b) { NTL_THREAD_LOCAL static RR t; if (IsZero(a.x)) { negate(z, b); return; } if (IsZero(b.x)) { xcopy(z, a); return; } if (a.e > b.e) { if (a.e-b.e - max(RR::prec-NumBits(a.x),0) >= NumBits(b.x) + 2) normalize(z, a, -sign(b)); else { LeftShift(t.x, a.x, a.e-b.e); sub(t.x, t.x, b.x); t.e = b.e; xcopy(z, t); } } else if (a.e < b.e) { if (b.e-a.e - max(RR::prec-NumBits(b.x),0) >= NumBits(a.x) + 2) { normalize(z, b, -sign(a)); negate(z.x, z.x); } else { LeftShift(t.x, b.x, b.e-a.e); sub(t.x, a.x, t.x); t.e = a.e; xcopy(z, t); } } else { sub(t.x, a.x, b.x); t.e = a.e; normalize(z, t); } } void SubPrec(RR& x, const RR& a, const RR& b, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("SubPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; sub(x, a, b); RR::prec = old_p; } void negate(RR& z, const RR& a) { xcopy(z, a); negate(z.x, z.x); } void NegatePrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("NegatePrec: bad precsion"); long old_p = RR::prec; RR::prec = p; negate(x, a); RR::prec = old_p; } void abs(RR& z, const RR& a) { xcopy(z, a); abs(z.x, z.x); } void AbsPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("AbsPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; abs(x, a); RR::prec = old_p; } void mul(RR& z, const RR& a, const RR& b) { NTL_THREAD_LOCAL static RR t; mul(t.x, a.x, b.x); t.e = a.e + b.e; xcopy(z, t); } void MulPrec(RR& x, const RR& a, const RR& b, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("MulPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; mul(x, a, b); RR::prec = old_p; } void sqr(RR& z, const RR& a) { NTL_THREAD_LOCAL static RR t; sqr(t.x, a.x); t.e = a.e + a.e; xcopy(z, t); } void SqrPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("SqrPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; sqr(x, a); RR::prec = old_p; } void div(RR& z, const RR& a, const RR& b) { if (IsZero(b)) Error("RR: division by zero"); if (IsZero(a)) { clear(z); return; } long la = NumBits(a.x); long lb = NumBits(b.x); long neg = (sign(a) != sign(b)); long k = RR::prec - la + lb + 1; if (k < 0) k = 0; NTL_THREAD_LOCAL static RR t; NTL_ZZRegister(A); NTL_ZZRegister(B); NTL_ZZRegister(R); abs(A, a.x); LeftShift(A, A, k); abs(B, b.x); DivRem(t.x, R, A, B); t.e = a.e - b.e - k; normalize(z, t, !IsZero(R)); if (neg) negate(z.x, z.x); } void DivPrec(RR& x, const RR& a, const RR& b, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("DivPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; div(x, a, b); RR::prec = old_p; } void SqrRoot(RR& z, const RR& a) { if (sign(a) < 0) Error("RR: attempt to take square root of negative number"); if (IsZero(a)) { clear(z); return; } RR t; ZZ T1, T2; long k; k = 2*RR::prec - NumBits(a.x) + 1; if (k < 0) k = 0; if ((a.e - k) & 1) k++; LeftShift(T1, a.x, k); // since k >= 2*prec - bits(a) + 1, T1 has at least 2*prec+1 bits, // thus T1 >= 2^(2*prec) SqrRoot(t.x, T1); // t.x >= 2^prec thus t.x contains the round bit t.e = (a.e - k)/2; sqr(T2, t.x); // T1-T2 is the (lower part of the) sticky bit normalize(z, t, T2 < T1); } void SqrRootPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("SqrRootPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; SqrRoot(x, a); RR::prec = old_p; } void swap(RR& a, RR& b) { swap(a.x, b.x); swap(a.e, b.e); } long compare(const RR& a, const RR& b) { NTL_THREAD_LOCAL static RR t; SubPrec(t, a, b, 1); return sign(t); } long operator==(const RR& a, const RR& b) { return a.e == b.e && a.x == b.x; } void trunc(RR& z, const RR& a) { NTL_THREAD_LOCAL static RR t; if (a.e >= 0) xcopy(z, a); else { RightShift(t.x, a.x, -a.e); t.e = 0; xcopy(z, t); } } void TruncPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("TruncPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; trunc(x, a); RR::prec = old_p; } void floor(RR& z, const RR& a) { NTL_THREAD_LOCAL static RR t; if (a.e >= 0) xcopy(z, a); else { RightShift(t.x, a.x, -a.e); if (sign(a.x) < 0) add(t.x, t.x, -1); t.e = 0; xcopy(z, t); } } void FloorPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("FloorPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; floor(x, a); RR::prec = old_p; } void ceil(RR& z, const RR& a) { NTL_THREAD_LOCAL static RR t; if (a.e >= 0) xcopy(z, a); else { RightShift(t.x, a.x, -a.e); if (sign(a.x) > 0) add(t.x, t.x, 1); t.e = 0; xcopy(z, t); } } void CeilPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("CeilPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; ceil(x, a); RR::prec = old_p; } void round(RR& z, const RR& a) { if (a.e >= 0) { xcopy(z, a); return; } long len = NumBits(a.x); if (-a.e > len) { z = 0; return; } if (-a.e == len) { if (len == 1) z = 0; else z = sign(a.x); return; } NTL_THREAD_LOCAL static RR t; ConvPrec(t, a, len+a.e); xcopy(z, t); } void RoundPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("RoundPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; round(x, a); RR::prec = old_p; } void conv(RR& z, const ZZ& a) { normalize1(z, a, 0, RR::prec, 0); } void ConvPrec(RR& x, const ZZ& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; conv(x, a); RR::prec = old_p; } void conv(RR& z, long a) { if (a == 0) { clear(z); return; } if (a == 1) { set(z); return; } NTL_ZZRegister(t); t = a; conv(z, t); } void ConvPrec(RR& x, long a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; conv(x, a); RR::prec = old_p; } void conv(RR& z, unsigned long a) { if (a == 0) { clear(z); return; } if (a == 1) { set(z); return; } NTL_ZZRegister(t); conv(t, a); conv(z, t); } void ConvPrec(RR& x, unsigned long a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; conv(x, a); RR::prec = old_p; } void conv(RR& z, double a) { if (a == 0) { clear(z); return; } if (a == 1) { set(z); return; } if (!IsFinite(&a)) Error("RR: conversion of a non-finite double"); int e; double f; NTL_THREAD_LOCAL static RR t; f = frexp(a, &e); f = f * NTL_FDOUBLE_PRECISION; f = f * 4; conv(t.x, f); t.e = e - (NTL_DOUBLE_PRECISION + 1); xcopy(z, t); } void ConvPrec(RR& x, double a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; conv(x, a); RR::prec = old_p; } void conv(ZZ& z, const RR& a) { if (a.e >= 0) LeftShift(z, a.x, a.e); else { long sgn = sign(a.x); RightShift(z, a.x, -a.e); if (sgn < 0) sub(z, z, 1); } } void CeilToZZ(ZZ& z, const RR& a) { if (a.e >= 0) LeftShift(z, a.x, a.e); else { long sgn = sign(a.x); RightShift(z, a.x, -a.e); if (sgn > 0) add(z, z, 1); } } void TruncToZZ(ZZ& z, const RR& a) { if (a.e >= 0) LeftShift(z, a.x, a.e); else RightShift(z, a.x, -a.e); } void RoundToZZ(ZZ& z, const RR& a) { if (a.e >= 0) { LeftShift(z, a.x, a.e); return; } long len = NumBits(a.x); if (-a.e > len) { z = 0; return; } if (-a.e == len) { if (len == 1) z = 0; else z = sign(a.x); return; } NTL_THREAD_LOCAL static RR t; ConvPrec(t, a, len+a.e); LeftShift(z, t.x, t.e); } void conv(long& z, const RR& a) { ZZ t; if (a.e >= NTL_BITS_PER_LONG) z = 0; else { conv(t, a); conv(z, t); } } void conv(double& z, const RR& aa) { double x; NTL_THREAD_LOCAL static RR a; ConvPrec(a, aa, NTL_DOUBLE_PRECISION); // round to NTL_DOUBLE_PRECISION bits to avoid double overflow conv(x, a.x); z = _ntl_ldexp(x, a.e); } void add(RR& z, const RR& a, double b) { NTL_THREAD_LOCAL static RR B; B = b; add(z, a, B); } void sub(RR& z, const RR& a, double b) { NTL_THREAD_LOCAL static RR B; B = b; sub(z, a, B); } void sub(RR& z, double a, const RR& b) { NTL_THREAD_LOCAL static RR A; A = a; sub(z, A, b); } void mul(RR& z, const RR& a, double b) { NTL_THREAD_LOCAL static RR B; B = b; mul(z, a, B); } void div(RR& z, const RR& a, double b) { NTL_THREAD_LOCAL static RR B; B = b; div(z, a, B); } void div(RR& z, double a, const RR& b) { NTL_THREAD_LOCAL static RR A; A = a; div(z, A, b); } void inv(RR& z, const RR& a) { NTL_THREAD_LOCAL static RR one = to_RR(1); div(z, one, a); } void InvPrec(RR& x, const RR& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("InvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; inv(x, a); RR::prec = old_p; } long compare(const RR& a, double b) { if (b == 0) return sign(a); NTL_THREAD_LOCAL static RR B; B = b; return compare(a, B); } long operator==(const RR& a, double b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); NTL_THREAD_LOCAL static RR B; B = b; return a == B; } void power(RR& z, const RR& a, long e) { RR b, res; long n = NumBits(e); long p = RR::precision(); RR::SetPrecision(p + n + 10); xcopy(b, a); set(res); long i; for (i = n-1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, b); } RR::SetPrecision(p); if (e < 0) inv(z, res); else xcopy(z, res); } istream& operator>>(istream& s, RR& x) { long c; long cval; long sign; ZZ a, b; if (!s) Error("bad RR input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c == '-') { sign = -1; s.get(); c = s.peek(); } else sign = 1; long got1 = 0; long got_dot = 0; long got2 = 0; a = 0; b = 1; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got1 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); s.get(); c = s.peek(); cval = CharToIntVal(c); } } if (c == '.') { got_dot = 1; s.get(); c = s.peek(); cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got2 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); mul(b, b, 10); s.get(); c = s.peek(); cval = CharToIntVal(c); } } } if (got_dot && !got1 && !got2) Error("bad RR input"); ZZ e; long got_e = 0; long e_sign; if (c == 'e' || c == 'E') { got_e = 1; s.get(); c = s.peek(); if (c == '-') { e_sign = -1; s.get(); c = s.peek(); } else if (c == '+') { e_sign = 1; s.get(); c = s.peek(); } else e_sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) Error("bad RR input"); e = 0; while (cval >= 0 && cval <= 9) { mul(e, e, 10); add(e, e, cval); s.get(); c = s.peek(); cval = CharToIntVal(c); } } if (!got1 && !got2 && !got_e) Error("bad RR input"); RR t1, t2, v; long old_p = RR::precision(); if (got1 || got2) { ConvPrec(t1, a, max(NumBits(a), 1)); ConvPrec(t2, b, NumBits(b)); if (got_e) RR::SetPrecision(old_p + 10); div(v, t1, t2); } else set(v); if (sign < 0) negate(v, v); if (got_e) { if (e >= NTL_OVFBND) Error("RR input overflow"); long E; conv(E, e); if (e_sign < 0) E = -E; RR::SetPrecision(old_p + 10); power(t1, to_RR(10), E); mul(v, v, t1); RR::prec = old_p; } xcopy(x, v); return s; } void InputPrec(RR& x, istream& s, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; s >> x; RR::prec = old_p; } void conv(RR& z, const xdouble& a) { conv(z, a.mantissa()); if (a.exponent() > ((2*NTL_OVFBND)/(2*NTL_XD_HBOUND_LOG))) Error("RR: overlow"); if (a.exponent() < -((2*NTL_OVFBND)/(2*NTL_XD_HBOUND_LOG))) Error("RR: underflow"); z.e += a.exponent()*(2*NTL_XD_HBOUND_LOG); if (z.e >= NTL_OVFBND) Error("RR: overflow"); if (z.e <= -NTL_OVFBND) Error("RR: underflow"); } void ConvPrec(RR& x, const xdouble& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; conv(x, a); RR::prec = old_p; } void conv(xdouble& z, const RR& a) { xdouble x; xdouble y; conv(x, a.x); power2(y, a.e); z = x*y; } void power2(RR& z, long e) { if (e >= NTL_OVFBND) Error("RR: overflow"); if (e <= -NTL_OVFBND) Error("RR: underflow"); set(z.x); z.e = e; } void conv(RR& z, const quad_float& a) { NTL_THREAD_LOCAL static RR hi, lo, res; ConvPrec(hi, a.hi, NTL_DOUBLE_PRECISION); ConvPrec(lo, a.lo, NTL_DOUBLE_PRECISION); add(res, hi, lo); z = res; } void ConvPrec(RR& x, const quad_float& a, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; conv(x, a); RR::prec = old_p; } void conv(quad_float& z, const RR& a) { long old_p; NTL_THREAD_LOCAL static RR a_hi, a_lo; old_p = RR::prec; ConvPrec(a_hi, a, NTL_DOUBLE_PRECISION); // high order bits SubPrec(a_lo, a, a_hi, NTL_DOUBLE_PRECISION); // low order bits z = to_quad_float(a_hi.x)*power2_quad_float(a_hi.e) + to_quad_float(a_lo.x)*power2_quad_float(a_lo.e); } void conv(RR& x, const char *s) { long c; long cval; long sign; ZZ a, b; long i = 0; if (!s) Error("bad RR input"); c = s[i]; while (IsWhiteSpace(c)) { i++; c = s[i]; } if (c == '-') { sign = -1; i++; c = s[i]; } else sign = 1; long got1 = 0; long got_dot = 0; long got2 = 0; a = 0; b = 1; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got1 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); i++; c = s[i]; cval = CharToIntVal(c); } } if (c == '.') { got_dot = 1; i++; c = s[i]; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got2 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); mul(b, b, 10); i++; c = s[i]; cval = CharToIntVal(c); } } } if (got_dot && !got1 && !got2) Error("bad RR input"); ZZ e; long got_e = 0; long e_sign; if (c == 'e' || c == 'E') { got_e = 1; i++; c = s[i]; if (c == '-') { e_sign = -1; i++; c = s[i]; } else if (c == '+') { e_sign = 1; i++; c = s[i]; } else e_sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) Error("bad RR input"); e = 0; while (cval >= 0 && cval <= 9) { mul(e, e, 10); add(e, e, cval); i++; c = s[i]; cval = CharToIntVal(c); } } if (!got1 && !got2 && !got_e) Error("bad RR input"); RR t1, t2, v; long old_p = RR::precision(); if (got1 || got2) { ConvPrec(t1, a, max(NumBits(a), 1)); ConvPrec(t2, b, NumBits(b)); if (got_e) RR::SetPrecision(old_p + 10); div(v, t1, t2); } else set(v); if (sign < 0) negate(v, v); if (got_e) { if (e >= NTL_OVFBND) Error("RR input overflow"); long E; conv(E, e); if (e_sign < 0) E = -E; RR::SetPrecision(old_p + 10); power(t1, to_RR(10), E); mul(v, v, t1); RR::prec = old_p; } xcopy(x, v); } void ConvPrec(RR& x, const char *s, long p) { if (p < 1 || NTL_OVERFLOW(p, 1, 0)) Error("ConvPrec: bad precsion"); long old_p = RR::prec; RR::prec = p; conv(x, s); RR::prec = old_p; } void ReallyComputeE(RR& res) { long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR s, s1, t; s = 1; t = 1; long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); div(t, t, i); } RR::SetPrecision(p); xcopy(res, s); } void ComputeE(RR& res) { NTL_THREAD_LOCAL static long prec = 0; NTL_THREAD_LOCAL static RR e; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputeE(e); RR::SetPrecision(p); } xcopy(res, e); } void exp(RR& res, const RR& x) { if (x >= NTL_OVFBND || x <= -NTL_OVFBND) Error("RR: overflow"); long p = RR::precision(); // step 0: write x = n + f, n an integer and |f| <= 1/2 // careful -- we want to compute f to > p bits of precision RR f, nn; RR::SetPrecision(NTL_BITS_PER_LONG); round(nn, x); RR::SetPrecision(p + 10); sub(f, x, nn); long n = to_long(nn); // step 1: calculate t1 = e^n by repeated squaring RR::SetPrecision(p + NumBits(n) + 10); RR e; ComputeE(e); RR::SetPrecision(p + 10); RR t1; power(t1, e, n); // step 2: calculate t2 = e^f using Taylor series expansion RR::SetPrecision(p + NumBits(p) + 10); RR t2, s, s1, t; long i; s = 0; t = 1; for (i = 1; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); div(t, t, i); } xcopy(t2, s); RR::SetPrecision(p); mul(res, t1, t2); } void ReallyComputeLn2(RR& res) { long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR s, s1, t, t1; s = 0; t = 0.5; t1 = 0.5; long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, 0.5); div(t, t1, i); } RR::SetPrecision(p); xcopy(res, s); } void ComputeLn2(RR& res) { NTL_THREAD_LOCAL static long prec = 0; NTL_THREAD_LOCAL static RR ln2; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputeLn2(ln2); RR::SetPrecision(p); } xcopy(res, ln2); } long Lg2(const RR& x) { return NumBits(x.mantissa()) + x.exponent(); } void log(RR& res, const RR& x) { if (x <= 0) Error("argument to log must be positive"); long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR y; long n; // re-write x = 2^n * (1 - y), where -1/2 < y < 1/4 (so 3/4 < 1-y < 3/2) if (x > 0.75 && x < 1.5) { n = 0; sub(y, 1, x); } else { n = Lg2(x) - 1; RR t; power2(t, -n); mul(t, t, x); while (t > 1.5) { mul(t, t, 0.5); n++; } sub(y, 1, t); } // compute s = - ln(1-y) by power series expansion RR s, s1, t, t1; s = 0; xcopy(t, y); xcopy(t1, y); long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, y); div(t, t1, i); } if (n == 0) t = 0; else { ComputeLn2(t); mul(t, t, n); } RR::SetPrecision(p); sub(res, t, s); } void ComputeLn10(RR& res) { NTL_THREAD_LOCAL static long prec = 0; NTL_THREAD_LOCAL static RR ln10; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); log(ln10, to_RR(10)); RR::SetPrecision(p); } xcopy(res, ln10); } void log10(RR& res, const RR& x) { long p = RR::precision(); RR::SetPrecision(p + 10); RR ln10, t1, t2; ComputeLn10(ln10); log(t1, x); div(t2, t1, ln10); RR::SetPrecision(p); xcopy(res, t2); } void expm1(RR& res, const RR& x) { long p = RR::precision(); if (x < -0.5 || x > 0.5) { RR t; RR::SetPrecision(p + 10); exp(t, x); RR::SetPrecision(p); sub(res, t, 1); return; } RR::SetPrecision(p + NumBits(p) + 10); RR f; xcopy(f, x); RR s, s1, t; long i; s = 0; xcopy(t, f); for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); div(t, t, i); } RR::SetPrecision(p); xcopy(res, s); } void log1p(RR& res, const RR& x) { long p = RR::precision(); RR y; if (x < -0.5 || x > 0.5) { RR::SetPrecision(p + 10); log(y, 1 + x); RR::SetPrecision(p); xcopy(res, y); return; } RR::SetPrecision(p + NumBits(p) + 10); negate(y, x); // compute s = - ln(1-y) by power series expansion RR s, s1, t, t1; s = 0; xcopy(t, y); xcopy(t1, y); long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, y); div(t, t1, i); } RR::SetPrecision(p); negate(res, s); } void pow(RR& res, const RR& x, const RR& y) { if (y == 0) { res = 1; return; } if (x == 0) { res = 0; return; } if (x == 1) { res = 1; return; } if (x < 0) { Error("pow: sorry...first argument to pow must be nonnegative"); } long p = RR::precision(); // calculate working precison...one could use p + NTL_BITS_PER_LONG + 10, // for example, but we want the behaviour to be machine independent. // so we calculate instead a rough approximation to log |y log(x)| RR t1, t2; long k; if (x > 0.5 && x < 1.5) { xcopy(t1, x - 1); k = Lg2(t1); } else { k = NumBits(Lg2(x)); } k += Lg2(y); if (k > NTL_BITS_PER_LONG+10) Error("RR: overflow"); if (k < 0) k = 0; RR::SetPrecision(p + k + 10); t1 = y*log(x); RR::SetPrecision(p); t2 = exp(t1); res = t2; } void ReallyComputePi(RR& res) { long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR sum1; RR s, s1, t, t1; s = 0; t = 0.5; t1 = 0.5; long i; for (i = 3; ; i+=2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, -0.25); div(t, t1, i); } xcopy(sum1, s); RR g; inv(g, to_RR(3)); // g = 1/3 s = 0; xcopy(t, g); xcopy(t1, g); sqr(g, g); negate(g, g); // g = -1/9 for (i = 3; ; i+=2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, g); div(t, t1, i); } add(s, s, sum1); mul(s, s, 4); RR::SetPrecision(p); xcopy(res, s); } void ComputePi(RR& res) { NTL_THREAD_LOCAL static long prec = 0; NTL_THREAD_LOCAL static RR pi; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputePi(pi); RR::SetPrecision(p); } xcopy(res, pi); } void sin(RR& res, const RR& x) { if (x == 0) { res = 0; return; } if (Lg2(x) > 1000) Error("sin: sorry...argument too large in absolute value"); long p = RR::precision(); RR pi, t1, f; RR n; // we want to make x^2 < 3, so that the series for sin(x) // converges nicely, without any nasty cancellations in the // first terms of the series. RR::SetPrecision(p + NumBits(p) + 10); if (x*x < 3) { xcopy(f, x); } else { // we want to write x/pi = n + f, |f| < 1/2.... // but we have to do *this* very carefully, so that f is computed // to precision > p. I know, this is sick! long p1; p1 = p + Lg2(x) + 20; for (;;) { RR::SetPrecision(p1); ComputePi(pi); xcopy(t1, x/pi); xcopy(n, floor(t1)); xcopy(f, t1 - n); if (f > 0.5) { n++; xcopy(f, t1 - n); } if (f == 0 || p1 < p - Lg2(f) + Lg2(n) + 10) { // we don't have enough bits of f...increase p1 and continue p1 = p1 + max(20, p1/10); } else break; } RR::SetPrecision(p + NumBits(p) + 10); ComputePi(pi); xcopy(f, pi * f); if (n != 0 && n.exponent() == 0) { // n is odd, so we negate f, which negates sin(f) xcopy(f, -f); } } // Boy, that was painful, but now its over, and we can simply apply // the series for sin(f) RR t2, s, s1, t; long i; s = 0; xcopy(t, f); for (i = 3; ; i=i+2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); mul(t, t, f); div(t, t, i-1); div(t, t, i); negate(t, t); } RR::SetPrecision(p); xcopy(res, s); } void cos(RR& res, const RR& x) { if (x == 0) { res = 1; return; } if (Lg2(x) > 1000) Error("cos: sorry...argument too large in absolute value"); long p = RR::precision(); RR pi, t1, f; RR n; // we want to write x/pi = (n+1/2) + f, |f| < 1/2.... // but we have to do *this* very carefully, so that f is computed // to precision > p. I know, this is sick! long p1; p1 = p + Lg2(x) + 20; for (;;) { RR::SetPrecision(p1); ComputePi(pi); xcopy(t1, x/pi); xcopy(n, floor(t1)); xcopy(f, t1 - (n + 0.5)); if (f == 0 || p1 < p - Lg2(f) + Lg2(n) + 10) { // we don't have enough bits of f...increase p1 and continue p1 = p1 + max(20, p1/10); } else break; } RR::SetPrecision(p + NumBits(p) + 10); ComputePi(pi); xcopy(f, pi * f); if (n == 0 || n.exponent() != 0) { // n is even, so we negate f, which negates sin(f) xcopy(f, -f); } // Boy, that was painful, but now its over, and we can simply apply // the series for sin(f) RR t2, s, s1, t; long i; s = 0; xcopy(t, f); for (i = 3; ; i=i+2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); mul(t, t, f); div(t, t, i-1); div(t, t, i); negate(t, t); } RR::SetPrecision(p); xcopy(res, s); } ostream& operator<<(ostream& s, const RR& a) { if (IsZero(a)) { s << "0"; return s; } long old_p = RR::precision(); // we compute new_p and log_10_a precisely using sufficient // precision---this is necessary to achieve accuracy and // platform independent behaviour long temp_p = max(NumBits(RR::OutputPrecision()), NumBits(Lg2(a))) + 10; RR::SetPrecision(temp_p); RR ln2, ln10, log_2_10; ComputeLn2(ln2); ComputeLn10(ln10); log_2_10 = ln10/ln2; long new_p = to_long(RR::OutputPrecision()*log_2_10) + 20; long log_10_a = to_long(Lg2(a)/log_2_10); RR::SetPrecision(new_p); RR b; long neg; if (a < 0) { negate(b, a); neg = 1; } else { xcopy(b, a); neg = 0; } long k = RR::OutputPrecision() - log_10_a; RR c, d; power(c, to_RR(10), RR::OutputPrecision()); power(d, to_RR(10), log_10_a); div(b, b, d); mul(b, b, c); while (b < c) { mul(b, b, 10); k++; } while (b >= c) { div(b, b, 10); k--; } add(b, b, 0.5); k = -k; ZZ B; conv(B, b); long bp_len = RR::OutputPrecision()+10; char *bp = NTL_NEW_OP char[bp_len]; if (!bp) Error("RR output: out of memory"); long len, i; len = 0; do { if (len >= bp_len) Error("RR output: buffer overflow"); bp[len] = IntValToChar(DivRem(B, B, 10)); len++; } while (B > 0); for (i = 0; i < len/2; i++) { char tmp; tmp = bp[i]; bp[i] = bp[len-1-i]; bp[len-1-i] = tmp; } i = len-1; while (bp[i] == '0') i--; k += (len-1-i); len = i+1; bp[len] = '\0'; if (k > 3 || k < -len - 3) { // use scientific notation if (neg) s << "-"; s << "0." << bp << "e" << (k + len); } else if (k >= 0) { if (neg) s << "-"; s << bp; for (i = 0; i < k; i++) s << "0"; } else if (k <= -len) { if (neg) s << "-"; s << "0."; for (i = 0; i < -len-k; i++) s << "0"; s << bp; } else { if (neg) s << "-"; for (i = 0; i < len+k; i++) s << bp[i]; s << "."; for (i = len+k; i < len; i++) s << bp[i]; } RR::SetPrecision(old_p); delete [] bp; return s; } NTL_END_IMPL ntl-6.2.1/src/RRTest.c000644 000765 000024 00000000450 12377144457 014751 0ustar00shoupstaff000000 000000 #include NTL_CLIENT int main() { mat_RR A; vec_RR x, y, z; RR d; RR::SetPrecision(200); cin >> A; cin >> y; solve(d, x, A, y); // mul(z, x, A); // sub(z, z, y); z = x*A - y; cout << d << "\n"; cout << x << "\n"; cout << z << "\n"; } ntl-6.2.1/src/RRTestIn000644 000765 000024 00000006236 12377144457 015027 0ustar00shoupstaff000000 000000 [[-1007377 -621256 -685733 -1029120 -1011952 540589 -891039 -526851 665990 -628992 -641479 -812282 732497 679539 -941076 649927 586413 761030 821315 995148] [-789365 -622518 987275 -594200 -835589 571387 -995798 -993857 806554 -915946 906504 -680376 -545294 -720939 812630 -900506 -918548 575268 688388 -593592] [550743 1012525 -742758 684636 -819566 -922450 -931004 862846 -1037626 1023813 -844078 525899 -812455 -681704 -628061 -918116 -909821 -644178 827337 -786322] [-564945 -733107 979752 773955 -548908 -642504 -793003 1042300 984860 567651 -627125 -933584 732283 528600 -615886 631186 964459 922892 -843197 774273] [-938526 576037 -864612 653669 -1018155 597732 544943 -894518 -933942 621892 -859594 -942483 -590467 775614 873241 -917781 -1000228 658893 -677585 889401] [1007616 -810354 605966 -530965 870440 672791 677405 -842554 955096 856668 985158 929574 837102 -954192 -772025 -766460 -680720 -794914 -740091 -672270] [852689 -651039 -535517 903809 982092 532512 -682583 -915492 -571826 -811136 -749897 785952 -954046 537266 883213 630761 -902395 -607566 935742 633521] [660404 591376 873522 -1001549 871542 1041954 -537328 -699583 -675351 963615 572679 833723 -832887 -623849 940286 -820470 -783690 663914 -631307 -779979] [672814 -758937 802563 -928035 1047989 620898 931085 879974 655815 1007647 557164 843862 929963 -931350 -1017250 -695547 775528 594474 845613 -1031318] [-793811 -539625 -618683 -958438 -943420 979026 985199 -705064 538218 599551 -635710 848659 -692530 578628 -581393 739362 703204 936610 -828619 -760384] [-828152 -596634 -759545 878054 611482 1028872 553542 -915076 899691 846870 -535336 -591759 693682 -613243 -808226 911793 996273 696763 -837040 -703417] [697478 629327 -594833 924068 842000 775153 675791 -543387 -978721 -575508 598224 760540 783232 849017 -1024693 -570191 583682 735309 -633097 -701871] [-992571 -948854 -911900 -764507 684692 -898657 813746 -635634 744436 854601 998034 -664419 819562 1004955 -780684 -892501 -678615 -799675 -573309 -882355] [-953063 548712 559591 922389 -558574 -967290 -655590 -687331 1047546 711682 -954689 -821640 -786920 786979 762762 603011 593903 -756313 693749 -643021] [-748707 933192 700160 -975435 995281 -646390 -1035167 973363 614204 -967837 -586649 833688 -647661 711361 615899 887422 -534256 -722406 663119 594950] [630840 -726745 991278 -809600 -665945 -660710 -603207 -954200 938302 991768 -650427 789303 905344 -728251 824408 924197 843327 -850701 728323 617049] [-780719 -1036907 -896496 729651 -780826 -554285 -604816 596378 -949904 -579762 -710465 806954 701677 946362 946408 968898 799263 -574346 -968732 635951] [-593706 622808 978139 -741721 -801289 -771952 901691 1034952 -839341 882675 570078 -666109 -794509 -629324 983777 -789268 989966 -988905 -952690 757890] [-954640 -667081 -1017441 -907522 601534 854519 937315 936736 -945500 -587586 -577805 946046 -808901 -529612 -969288 -886033 -569067 -639671 576920 733108] [-758077 585690 732142 -770057 892395 -900234 698793 -910499 -584416 -593236 -549557 -989525 -697743 -676367 1019901 -766922 752620 1037353 812504 761751] ] [947891 538090 995215 -681544 752658 -692090 904199 -892030 -819336 705526 -745006 649281 810836 -727461 612233 -739736 989072 -1028677 -646961 651303] ntl-6.2.1/src/RRTestOut000644 000765 000024 00000001161 12377144457 015220 0ustar00shoupstaff000000 000000 -0.3543709603e127 [0.6342777424 -1.66630001 -0.7490057533 -0.4878568653 -0.2446744714 1.996508497 -1.44462438 1.021627692 -0.4039028959 -0.6198159641 -1.253578169 -0.8264701067 -0.9749456962 1.80856531 -1.155185633 -0.6781996511 1.113882043 -1.103882646 0.6760286159 1.027918795] [0.3262652234e-53 0.7177834915e-53 -0.8482895808e-53 0.195759134e-53 0.6525304468e-53 0.3915182681e-53 0.6525304468e-54 -0.1174554804e-52 -0.5872774021e-53 0.4567713128e-53 0.7830365362e-53 -0.195759134e-53 -0.7830365362e-53 0.195759134e-53 0.6525304468e-54 0.5220243574e-53 0.7177834915e-53 -0.1044048715e-52 0.1305060894e-53 0.4567713128e-53] ntl-6.2.1/src/RemoveProg000644 000765 000024 00000000200 12377144456 015422 0ustar00shoupstaff000000 000000 for i in $* do rm -f "$i" rm -f "$i.exe" rm -f ".libs/$i" rm -f ".libs/$i.exe" rm -rf "$i.dSYM" done exit 0 ntl-6.2.1/src/TestGetTime.c000644 000765 000024 00000002077 12377144457 015773 0ustar00shoupstaff000000 000000 #include #include #include double _ntl_GetTime(); /* Assuming the processor speed is at most 200GHz, and that * the clock resolution is at least 1 millisecond, the following * code should correctly determine if the GetTime function * is working properly, and should not run for more than * a few seconds on a machine with a speed of at least 100MHz. */ #define LOOP_COUNT (400) int main(int argc, char **argv) { long a, x, n, m; long i, j, k; double t0, t1; fprintf(stderr, "running"); x = atol(argv[1]); /* = 1 */ n = atol(argv[2]); /* = 1048576 = 2^20 */ m = atol(argv[3]); /* = 1048575 = 2^20 - 1 */ k = -1; t0 = _ntl_GetTime(); a = 1; for (i = 1; i <= LOOP_COUNT; i++) { for (j = 0; j < n; j++) a = (a + x) & m; if (a == 17) return -2; /* keeps the compiler honest! */ t1 = _ntl_GetTime(); if (t1 > t0) { fprintf(stderr, "\n"); return 0; } if ((i % 10) == 0) { fprintf(stderr, "."); } } fprintf(stderr, "\n"); return -1; } ntl-6.2.1/src/TestScript000644 000765 000024 00000006245 12377144456 015460 0ustar00shoupstaff000000 000000 echo echo "---------------------------------" echo "making CanZassTest" make CanZassTest echo "running CanZassTest" ./CanZassTest < CanZassTestIn > XXX sh RemoveProg CanZassTest if diff -b XXX CanZassTestOut then echo "CanZassTest OK" else echo "bad CanZassTest" fi echo echo "---------------------------------" echo "making BerlekampTest" make BerlekampTest echo "running BerlekampTest" ./BerlekampTest < BerlekampTestIn > XXX sh RemoveProg BerlekampTest if diff -b XXX BerlekampTestOut then echo "BerlekampTest OK" else echo "bad BerlekampTest" fi echo echo "---------------------------------" echo "making ZZXFacTest" make ZZXFacTest echo "running ZZXFacTest" ./ZZXFacTest < ZZXFacTestIn > XXX sh RemoveProg ZZXFacTest if diff -b XXX ZZXFacTestOut then echo "ZZXFacTest OK" else echo "bad ZZXFacTest" fi echo echo "---------------------------------" echo "making MoreFacTest" make MoreFacTest echo "running MoreFacTest" ./MoreFacTest < MoreFacTestIn sh RemoveProg MoreFacTest echo echo "---------------------------------" echo "making GF2XTest" make GF2XTest echo "running GF2XTest" ./GF2XTest sh RemoveProg GF2XTest echo echo "---------------------------------" echo "making GF2EXTest" make GF2EXTest echo "running GF2EXTest" ./GF2EXTest sh RemoveProg GF2EXTest echo echo "---------------------------------" echo "making MatrixTest" make MatrixTest echo "running MatrixTest" ./MatrixTest < MatrixTestIn > XXX sh RemoveProg MatrixTest if diff -b XXX MatrixTestOut then echo "MatrixTest OK" else echo "bad MatrixTest" fi echo echo "---------------------------------" echo "making CharPolyTest" make CharPolyTest echo "running CharPolyTest" ./CharPolyTest < CharPolyTestIn > XXX sh RemoveProg CharPolyTest if diff -b XXX CharPolyTestOut then echo "CharPolyTest OK" else echo "bad CharPolyTest" fi echo echo "---------------------------------" echo "making BitMatTest" make BitMatTest echo "running BitMatTest" ./BitMatTest sh RemoveProg BitMatTest echo echo "---------------------------------" echo "making RRTest" make RRTest echo "running RRTest" ./RRTest < RRTestIn > XXX sh RemoveProg RRTest if diff -b XXX RRTestOut then echo "RRTest OK" else echo "bad RRTest" fi echo echo "---------------------------------" echo "making QuadTest" make QuadTest echo "running QuadTest" ./QuadTest < QuadTestIn > XXX sh RemoveProg QuadTest if diff -b XXX QuadTestOut then echo "QuadTest OK" else echo "bad QuadTest" fi echo echo "---------------------------------" echo "making LLLTest" make LLLTest echo "running LLLTest" ./LLLTest < LLLTestIn > XXX sh RemoveProg LLLTest if diff -b XXX LLLTestOut then echo "LLLTest OK" else echo "bad LLLTest" fi echo echo "---------------------------------" echo "making subset" make subset echo "subset 40 40 20 10 999999 f" ./subset < #include #include #include NTL_CLIENT #define TIME_IT(t, action) \ do { \ double _t0, _t1; \ long _iter = 1; \ long _cnt = 0; \ do { \ _t0 = GetTime(); \ for (long _i = 0; _i < _iter; _i++) { action; _cnt++; } \ _t1 = GetTime(); \ } while ( _t1 - _t0 < 4 && (_iter *= 2)); \ t = (_t1 - _t0)/_iter; \ } while(0) int main() { double t; long k = 1000; long n = 1000; { SetSeed(conv(1)); ZZ p = RandomPrime_ZZ(k); ZZ_p::init(p); ZZ x, y, z, w; SetSeed(conv(2)); RandomBnd(x, p); SetSeed(conv(3)); RandomBnd(y, p); TIME_IT(t, mul(z, x, y)); cout << "multiply 1000-bit ints: " << t << "\n"; TIME_IT(t, rem(w, z, p)); cout << "remainder 2000/1000-bit ints: " << t << "\n"; TIME_IT(t, GCD(w, x, y)); cout << "gcd 1000-bit ints: " << t << "\n"; ZZ_pX a, b, c; SetSeed(conv(4)); random(a, n); SetSeed(conv(5)); random(b, n); mul(c, a, b); TIME_IT(t, mul(c, a, b)); cout << "multiply degree-1000 poly mod 1000-bit prime: " << t << "\n"; ZZ_pX f; SetSeed(conv(6)); random(f, n); SetCoeff(f, n); ZZ_pX A, B; SetSeed(conv(7)); random(A, 2*(deg(f)-1)); TIME_IT(t, rem(B, A, f)); cout << "remainder degree-2000/1000 poly mod 1000-bit prime: " << t << "\n"; ZZ_pXModulus F(f); TIME_IT(t, rem(B, A, F)); cout << "preconditioned remainder degree-2000/1000 poly mod 1000-bit prime: " << t << "\n"; TIME_IT(t, GCD(a, b)); cout << "gcd degree-1000 poly mod 1000-bit prime: " << t << "\n"; ZZX AA = conv(a); ZZX BB = conv(b); ZZX CC; TIME_IT(t, mul(CC, AA, BB)); cout << "multiply degree-1000 int poly with 1000-bit coeffs: " << t << "\n"; cout << "\n"; cout << "factoring degree-1000 poly mod 1000-bit prime...\n"; TIME_IT(t, CanZass(f, _cnt == 0)); cout << "...total time = " << t << "\n\n"; } { n = 500; k = 500; SetSeed(conv(8)); GF2X p = BuildRandomIrred(BuildIrred_GF2X(k)); GF2E::init(p); GF2X x, y, z, w; SetSeed(conv(9)); random(x, deg(p)); SetSeed(conv(10)); random(y, deg(p)); TIME_IT(t, mul(z, x, y)); cout << "multiply 500-bit GF2Xs: " << t << "\n"; TIME_IT(t, rem(w, z, p)); cout << "remainder 1000/500-bit GF2Xs: " << t << "\n"; TIME_IT(t, GCD(w, x, y)); cout << "gcd 500-bit GF2Xs: " << t << "\n"; SetSeed(conv(11)); GF2X fff; random(fff, k); SetCoeff(fff, k); cout << "\n"; TIME_IT(t, CanZass(fff, 0)); cout << "factoring degree-500 GF2X: " << t << "\n"; TIME_IT(t, GCD(w, x, y)); cout << "gcd 500-bit GF2X: " << t << "\n"; GF2EX a, b, c; SetSeed(conv(12)); random(a, n); SetSeed(conv(13)); random(b, n); mul(c, a, b); TIME_IT(t, mul(c, a, b)); cout << "multiply degree-500 poly mod 500-bit GF2X: " << t << "\n"; GF2EX f; SetSeed(conv(14)); random(f, n); SetCoeff(f, n); GF2EX A, B; SetSeed(conv(15)); random(A, 2*(deg(f)-1)); TIME_IT(t, rem(B, A, f)); cout << "remainder degree-1000/500 poly mod 500-bit GF2X: " << t << "\n"; GF2EXModulus F(f); TIME_IT(t, rem(B, A, F)); cout << "preconditioned remainder degree-1000/500 poly mod 500-bit GF2X: " << t << "\n"; TIME_IT(t, GCD(a, b)); cout << "gcd degree-500 poly mod 500-bit prime: " << t << "\n"; f = f >> n/2; cout << "\n"; cout << "factoring degree-500 poly mod 500-bit prime...\n"; TIME_IT(t, CanZass(f, _cnt == 0)); cout << "\n...total time = " << t << "\n"; } } ntl-6.2.1/src/VERSION_INFO000644 000765 000024 00000000006 12377144457 015302 0ustar00shoupstaff000000 000000 5:0:0 ntl-6.2.1/src/WINDIR000644 000765 000024 00000000015 12377144457 014336 0ustar00shoupstaff000000 000000 WinNTL-6_2_1 ntl-6.2.1/src/Wizard000644 000765 000024 00000004524 12377144457 014613 0ustar00shoupstaff000000 000000 if test "$1" = "on" then echo "" echo "*" echo "*" echo "* The wizard is going to run." echo "* It will perform some timing experiments, and then automatically" echo "* update your config.h file." echo "* Please be patient, and don't be spooked by any error messages." echo "*" echo "*" else echo "" echo "*" echo "*" echo "* You have chosen not to run the wizard." echo "*" echo "*" exit 0 fi rm -rf small mkdir small mkdir small/src mkdir small/include mkdir small/include/NTL cp MulTimeTest.c small/src cp PolyTimeTest.c small/src cp Poly1TimeTest.c small/src cp GF2XTimeTest.c small/src cp InitSettings.c small/src cp DispSettings.c small/src cp FFT.c small/src cp GetTime.c small/src cp ctools.c small/src cp ZZ.c small/src cp ZZVec.c small/src cp ZZ_p.c small/src cp ZZ_pX.c small/src cp ZZ_pX1.c small/src cp lip.c small/src cp g_lip_impl.h small/src cp c_lip_impl.h small/src cp tools.c small/src cp vec_ZZ.c small/src cp vec_ZZ_p.c small/src cp GF2.c small/src cp WordVector.c small/src cp vec_GF2.c small/src cp GF2X.c small/src cp GF2X1.c small/src cp ../include/NTL/FFT.h small/include/NTL cp ../include/NTL/SPMM_ASM.h small/include/NTL cp ../include/NTL/ctools.h small/include/NTL cp ../include/NTL/ZZ.h small/include/NTL cp ../include/NTL/ZZVec.h small/include/NTL cp ../include/NTL/ZZ_p.h small/include/NTL cp ../include/NTL/ZZ_pX.h small/include/NTL cp ../include/NTL/config.h small/include/NTL cp ../include/NTL/lip.h small/include/NTL cp ../include/NTL/g_lip.h small/include/NTL cp ../include/NTL/c_lip.h small/include/NTL cp ../include/NTL/gmp_aux.h small/include/NTL cp ../include/NTL/mach_desc.h small/include/NTL cp ../include/NTL/new.h small/include/NTL cp ../include/NTL/tools.h small/include/NTL cp ../include/NTL/vec_ZZ.h small/include/NTL cp ../include/NTL/vec_ZZ_p.h small/include/NTL cp ../include/NTL/vec_long.h small/include/NTL cp ../include/NTL/vector.h small/include/NTL cp ../include/NTL/GF2.h small/include/NTL cp ../include/NTL/WordVector.h small/include/NTL cp ../include/NTL/vec_GF2.h small/include/NTL cp ../include/NTL/GF2X.h small/include/NTL cp cfile small/src cp WizardAux small/src cp makefile small/src cd small/src perl WizardAux cd ../.. echo "*" echo "*" echo "* Updating config.h" echo "*" echo "*" cp small/include/NTL/config.h ../include/NTL/config.h rm -r small exit 0 ntl-6.2.1/src/WizardAux000644 000765 000024 00000011663 12377144457 015273 0ustar00shoupstaff000000 000000 # This is a perl script, invoked from a shell use warnings; # this doesn't work on older versions of perl sub GenConfigHeader { my $line; local *CFILE; local *CFILEOUT; open(CFILE, "< cfile"); open(CFILEOUT, "> cfileout"); while ($line = ) { $line =~ s/@\{(.*?)\}/$Config{$1}/ge; print CFILEOUT $line; } close(CFILE); close(CFILEOUT); system("cp cfileout ../include/NTL/config.h"); } sub RemoveProg { # This should work on unix and cygwin on windows my ($name) = @_; unlink($name); unlink("$name.exe"); } sub RunProg { my ($name) = @_; my $val; my $res; system("make wntl.a"); RemoveProg($name); system("make $name"); print "\n*** running $name..."; $val = `./$name`; if ($? != 0) { $res = "999999999999999"; } else { ($res) = ( $val =~ /^([0-9]*)/ ); } print $val, "\n"; return $res; } ############################################################ system("make InitSettings"); @lines = `./InitSettings`; %Config = ( 'NTL_LONG_LONG' => 0, 'NTL_AVOID_FLOAT' => 0, 'NTL_SPMM_UL' => 0, 'NTL_SPMM_ULL' => 0, 'NTL_SPMM_ASM' => 0, 'NTL_TBL_REM' => 0, 'NTL_AVOID_BRANCHING' => 0, 'NTL_GF2X_ALTCODE' => 0, 'NTL_GF2X_ALTCODE1' => 0, 'NTL_GF2X_NOINLINE' => 0, 'NTL_FFT_BIGTAB' => 0, 'NTL_FFT_LAZYMUL' => 0, 'WIZARD_HACK' => '#define NTL_WIZARD_HACK', ); foreach $line (@lines) { chomp($line); ($name, $val) = ($line =~ /(.*?)=(.*)/); $Config{$name} = $val; } # set AVOID_BRANCHING, SPMM, and FFT flags...try all combinations $time = "999999999999999"; $aflag = "default"; $bflag = "default"; $cflag = "default"; $dflag = "default"; foreach $aflag1 ("default", "NTL_AVOID_BRANCHING") { foreach $bflag1 ("default", "NTL_SPMM_UL", "NTL_SPMM_ULL", "NTL_SPMM_ASM") { foreach $cflag1 ("default", "NTL_FFT_BIGTAB") { foreach $dflag1 ("default", "NTL_FFT_LAZYMUL") { $Config{$aflag1} = 1; $Config{$bflag1} = 1; $Config{$cflag1} = 1; $Config{$dflag1} = 1; if ($Config{"NTL_FFT_LAZYMUL"}) { if ($Config{"NTL_FFT_BIGTAB"} == 0 || ($Config{"NTL_SPMM_ULL"} == 0 && $Config{"NTL_SPMM_ASM"} == 0)) { $Config{$aflag1} = 0; $Config{$bflag1} = 0; $Config{$cflag1} = 0; $Config{$dflag1} = 0; print "skip: $aflag1 $bflag1 $cflag1 $dflag1\n"; next; } } print "run: $aflag1 $bflag1 $cflag1 $dflag1\n"; GenConfigHeader(); $time1 = RunProg("Poly1TimeTest"); if ($time1 < $time) { $aflag = $aflag1; $bflag = $bflag1; $cflag = $cflag1; $dflag = $dflag1; $time = $time1; } $Config{$aflag1} = 0; $Config{$bflag1} = 0; $Config{$cflag1} = 0; $Config{$dflag1} = 0; unlink("FFT.o"); unlink("ZZ_pX.o"); } } } } $Config{$aflag} = 1; $Config{$bflag} = 1; $Config{$cflag} = 1; $Config{$dflag} = 1; unlink("lip.o"); # AVOID_BRANCHING affects this too unlink("ZZ_pX.o"); # FFT_BIGTABS and FFT_LAZYMUL affect this unlink("lzz_pX.o"); # FFT_BIGTABS and FFT_LAZYMUL affect this # set the flags GF2X_NOINLINE and GF2X_ALTCODE...try all pairs $time = "999999999999999"; $aflag = "default"; $bflag = "default"; foreach $aflag1 ("default", "NTL_GF2X_NOINLINE") { foreach $bflag1 ("default", "NTL_GF2X_ALTCODE", "NTL_GF2X_ALTCODE1") { $Config{$aflag1} = 1; $Config{$bflag1} = 1; GenConfigHeader(); $time1 = RunProg("GF2XTimeTest"); if ($time1 < $time) { $aflag = $aflag1; $bflag = $bflag1; $time = $time1; } $Config{$aflag1} = 0; $Config{$bflag1} = 0; unlink("GF2X.o"); } } $Config{$aflag} = 1; $Config{$bflag} = 1; if ($Config{"NTL_GMP_LIP"} == 0) { # GMP is not the primary long integer package # Choose between default, AVOID_FLOAT, and LONG_LONG implementatsions $time = "999999999999999"; $flag = "default"; foreach $flag1 ("default", "NTL_AVOID_FLOAT", "NTL_LONG_LONG") { $Config{$flag1} = 1; GenConfigHeader(); $time1 = RunProg("MulTimeTest"); if ($time1 < $time) { $flag = $flag1; $time = $time1; } $Config{$flag1} = 0; unlink("lip.o"); } $Config{$flag} = 1; # finally, now set TBL_REM GenConfigHeader(); $time = RunProg("PolyTimeTest"); $Config{"NTL_TBL_REM"} = 1; GenConfigHeader(); unlink("lip.o"); $time1 = RunProg("PolyTimeTest"); if ($time1 >= $time) { $Config{"NTL_TBL_REM"} = 0; } } $Config{'WIZARD_HACK'} = ""; GenConfigHeader(); print "\n\n*** the wizard is done!!\n\n"; system("make DispSettings"); system("./DispSettings"); ntl-6.2.1/src/WordVector.c000644 000765 000024 00000016634 12377144456 015676 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL void WordVector::DoSetLength(long n) { long m; if (n < 0) { Error("negative length in vector::SetLength"); } if (NTL_OVERFLOW(n, NTL_BITS_PER_LONG, 0)) Error("length too big in vector::SetLength"); if (n == 0) { if (rep) rep[-1] = 0; return; } if (!rep) { m = ((n+NTL_WordVectorMinAlloc-1)/NTL_WordVectorMinAlloc) * NTL_WordVectorMinAlloc; if (NTL_OVERFLOW(m, NTL_BITS_PER_LONG, 0)) Error("length too big in vector::SetLength"); _ntl_ulong *p = (_ntl_ulong *) NTL_MALLOC(m, sizeof(_ntl_ulong), 2*sizeof(_ntl_ulong)); if (!p) { Error("out of memory in SetLength()"); } rep = p+2; rep[-1] = n; rep[-2] = m << 1; return; } long max_length = (rep[-2] >> 1); if (n <= max_length) { rep[-1] = n; return; } long frozen = (rep[-2] & 1); if (frozen) Error("Cannot grow this WordVector"); m = max(n, long(NTL_WordVectorExpansionRatio*max_length)); m = ((m+NTL_WordVectorMinAlloc-1)/NTL_WordVectorMinAlloc)*NTL_WordVectorMinAlloc; _ntl_ulong *p = rep - 2; if (NTL_OVERFLOW(m, NTL_BITS_PER_LONG, 0)) Error("length too big in vector::SetLength"); p = (_ntl_ulong *) NTL_REALLOC(p, m, sizeof(_ntl_ulong), 2*sizeof(_ntl_ulong)); if (!p) { Error("out of memory in SetLength()"); } rep = p+2; rep[-1] = n; rep[-2] = m << 1; } void WordVector::SetMaxLength(long n) { long OldLength = length(); DoSetLength(n); if (rep) rep[-1] = OldLength; } WordVector& WordVector::operator=(const WordVector& a) { long i, n; _ntl_ulong *p; const _ntl_ulong *ap; if (this == &a) return *this; n = a.length(); ap = a.elts(); SetLength(n); p = elts(); for (i = 0; i < n; i++) p[i] = ap[i]; return *this; } WordVector::~WordVector() { if (!rep) return; if (rep[-2] & 1) Error("Cannot free this WordVector"); free(rep-2); } void WordVector::kill() { if (!rep) return; if (rep[-2] & 1) Error("Cannot free this WordVector"); free(rep-2); rep = 0; } void WordVector::RangeError(long i) const { cerr << "index out of range in vector: "; cerr << i; if (!rep) cerr << "(0)"; else cerr << "(" << rep[-1] << ")"; Error(""); } void CopySwap(WordVector& x, WordVector& y) { NTL_THREAD_LOCAL static WordVector t; t = x; x = y; y = t; t.release(); } void WordVector::swap_impl(WordVector& x, WordVector& y) { if ((x.rep && (x.rep[-2] & 1)) || (y.rep && (y.rep[-2] & 1))) { CopySwap(x, y); return; } _ntl_ulong* t; t = x.rep; x.rep = y.rep; y.rep = t; } void WordVector::append_impl(WordVector& v, _ntl_ulong a) { long l = v.length(); v.SetLength(l+1); v[l] = a; } void WordVector::append_impl(WordVector& v, const WordVector& w) { long l = v.length(); long m = w.length(); long i; v.SetLength(l+m); for (i = 0; i < m; i++) v[l+i] = w[i]; } istream & operator>>(istream& s, WordVector& a) { WordVector ibuf; long c; long n; if (!s) Error("bad vector input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != '[') { Error("bad vector input"); } n = 0; ibuf.SetLength(0); s.get(); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } while (c != ']' && c != EOF) { if (n % NTL_WordVectorInputBlock == 0) ibuf.SetMaxLength(n + NTL_WordVectorInputBlock); n++; ibuf.SetLength(n); if (!(s >> ibuf[n-1])) Error("bad vector input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } } if (c == EOF) Error("bad vector input"); s.get(); a = ibuf; return s; } ostream& operator<<(ostream& s, const WordVector& a) { long i, n; n = a.length(); s << '['; for (i = 0; i < n; i++) { s << a[i]; if (i < n-1) s << " "; } s << ']'; return s; } long operator==(const WordVector& a, const WordVector& b) { long n = a.length(); if (b.length() != n) return 0; const _ntl_ulong* ap = a.elts(); const _ntl_ulong* bp = b.elts(); long i; for (i = 0; i < n; i++) if (ap[i] != bp[i]) return 0; return 1; } long operator!=(const WordVector& a, const WordVector& b) { return !(a == b); } long InnerProduct(const WordVector& a, const WordVector& b) { long n = min(a.length(), b.length()); const _ntl_ulong *ap = a.elts(); const _ntl_ulong *bp = b.elts(); _ntl_ulong acc; long i; acc = 0; for (i = 0; i < n; i++) acc ^= ap[i] & bp[i]; #if (NTL_BITS_PER_LONG == 32) acc ^= acc >> 16; acc ^= acc >> 8; acc ^= acc >> 4; acc ^= acc >> 2; acc ^= acc >> 1; acc &= 1; #elif (NTL_BITS_PER_LONG == 64) acc ^= acc >> 32; acc ^= acc >> 16; acc ^= acc >> 8; acc ^= acc >> 4; acc ^= acc >> 2; acc ^= acc >> 1; acc &= 1; #else _ntl_ulong t = acc; while (t) { t = t >> 8; acc ^= t; } acc ^= acc >> 4; acc ^= acc >> 2; acc ^= acc >> 1; acc &= 1; #endif return long(acc); } void ShiftAdd(_ntl_ulong *cp, const _ntl_ulong* ap, long sa, long n) // c = c + (a << n) { if (sa == 0) return; long i; long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (bn == 0) { for (i = sa+wn-1; i >= wn; i--) cp[i] ^= ap[i-wn]; } else { _ntl_ulong t = ap[sa-1] >> (NTL_BITS_PER_LONG-bn); if (t) cp[sa+wn] ^= t; for (i = sa+wn-1; i >= wn+1; i--) cp[i] ^= (ap[i-wn] << bn) | (ap[i-wn-1] >> (NTL_BITS_PER_LONG-bn)); cp[wn] ^= ap[0] << bn; } } long WV_BlockConstructAlloc(WordVector& x, long d, long n) { long nwords, nbytes, AllocAmt, m, j; _ntl_ulong *p, *q; /* check n value */ if (n <= 0) Error("block construct: n must be positive"); /* check d value */ if (d <= 0) Error("block construct: d must be positive"); if (NTL_OVERFLOW(d, NTL_BITS_PER_LONG, 0) || NTL_OVERFLOW(d, sizeof(_ntl_ulong), 2*sizeof(_ntl_ulong))) Error("block construct: d too large"); nwords = d + 2; nbytes = nwords*sizeof(_ntl_ulong); AllocAmt = (NTL_MAX_ALLOC_BLOCK - sizeof(_ntl_ulong)) / nbytes; if (AllocAmt == 0) AllocAmt = 1; if (AllocAmt < n) m = AllocAmt; else m = n; p = (_ntl_ulong *) NTL_MALLOC(m, nbytes, sizeof(_ntl_ulong)); if (!p) Error("out of memory in block construct"); *p = m; q = p+3; x.rep = q; for (j = 0; j < m; j++) { q[-2] = (d << 1) | 1; q[-1] = 0; q += nwords; } return m; } void WV_BlockConstructSet(WordVector& x, WordVector& y, long i) { long d, size; d = x.rep[-2] >> 1; size = d + 2; y.rep = x.rep + i*size; } long WV_BlockDestroy(WordVector& x) { long m; _ntl_ulong *p; p = x.rep - 3; m = (long) *p; free(p); return m; } long WV_storage(long d) { return (d + 2)*sizeof(_ntl_ulong) + sizeof(WordVector); } NTL_END_IMPL ntl-6.2.1/src/ZZ.c000644 000765 000024 00000121501 12377144456 014131 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL const ZZ& ZZ::zero() { NTL_THREAD_LOCAL static ZZ z; return z; } const ZZ& ZZ_expo(long e) { NTL_THREAD_LOCAL static ZZ expo_helper; conv(expo_helper, e); return expo_helper; } void AddMod(ZZ& x, const ZZ& a, long b, const ZZ& n) { NTL_ZZRegister(B); conv(B, b); AddMod(x, a, B, n); } void SubMod(ZZ& x, const ZZ& a, long b, const ZZ& n) { NTL_ZZRegister(B); conv(B, b); SubMod(x, a, B, n); } void SubMod(ZZ& x, long a, const ZZ& b, const ZZ& n) { NTL_ZZRegister(A); conv(A, a); SubMod(x, A, b, n); } // ****** input and output NTL_THREAD_LOCAL static long iodigits = 0; NTL_THREAD_LOCAL static long ioradix = 0; // iodigits is the greatest integer such that 10^{iodigits} < NTL_WSP_BOUND // ioradix = 10^{iodigits} static void InitZZIO() { long x; x = (NTL_WSP_BOUND-1)/10; iodigits = 0; ioradix = 1; while (x) { x = x / 10; iodigits++; ioradix = ioradix * 10; } if (iodigits <= 0) Error("problem with I/O"); } istream& operator>>(istream& s, ZZ& x) { long c; long cval; long sign; long ndigits; long acc; NTL_ZZRegister(a); if (!s) Error("bad ZZ input"); if (!iodigits) InitZZIO(); a = 0; SkipWhiteSpace(s); c = s.peek(); if (c == '-') { sign = -1; s.get(); c = s.peek(); } else sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) Error("bad ZZ input"); ndigits = 0; acc = 0; while (cval >= 0 && cval <= 9) { acc = acc*10 + cval; ndigits++; if (ndigits == iodigits) { mul(a, a, ioradix); add(a, a, acc); ndigits = 0; acc = 0; } s.get(); c = s.peek(); cval = CharToIntVal(c); } if (ndigits != 0) { long mpy = 1; while (ndigits > 0) { mpy = mpy * 10; ndigits--; } mul(a, a, mpy); add(a, a, acc); } if (sign == -1) negate(a, a); x = a; return s; } // The class _ZZ_local_stack should be defined in an empty namespace, // but since I don't want to rely on namespaces, we just give it a funny // name to avoid accidental name clashes. struct _ZZ_local_stack { long top; Vec data; _ZZ_local_stack() { top = -1; } long pop() { return data[top--]; } long empty() { return (top == -1); } void push(long x); }; void _ZZ_local_stack::push(long x) { top++; if (top >= data.length()) data.SetLength(max(32, long(1.414*data.length()))); data[top] = x; } static void PrintDigits(ostream& s, long d, long justify) { NTL_THREAD_LOCAL static Vec buf(INIT_SIZE, iodigits); long i = 0; while (d) { buf[i] = IntValToChar(d % 10); d = d / 10; i++; } if (justify) { long j = iodigits - i; while (j > 0) { s << "0"; j--; } } while (i > 0) { i--; s << buf[i]; } } ostream& operator<<(ostream& s, const ZZ& a) { ZZ b; _ZZ_local_stack S; long r; long k; if (!iodigits) InitZZIO(); b = a; k = sign(b); if (k == 0) { s << "0"; return s; } if (k < 0) { s << "-"; negate(b, b); } do { r = DivRem(b, b, ioradix); S.push(r); } while (!IsZero(b)); r = S.pop(); PrintDigits(s, r, 0); while (!S.empty()) { r = S.pop(); PrintDigits(s, r, 1); } return s; } long GCD(long a, long b) { long u, v, t, x; if (a < 0) { if (a < -NTL_MAX_LONG) Error("GCD: integer overflow"); a = -a; } if (b < 0) { if (b < -NTL_MAX_LONG) Error("GCD: integer overflow"); b = -b; } if (b==0) x = a; else { u = a; v = b; do { t = u % v; u = v; v = t; } while (v != 0); x = u; } return x; } void XGCD(long& d, long& s, long& t, long a, long b) { long u, v, u0, v0, u1, v1, u2, v2, q, r; long aneg = 0, bneg = 0; if (a < 0) { if (a < -NTL_MAX_LONG) Error("XGCD: integer overflow"); a = -a; aneg = 1; } if (b < 0) { if (b < -NTL_MAX_LONG) Error("XGCD: integer overflow"); b = -b; bneg = 1; } u1=1; v1=0; u2=0; v2=1; u = a; v = b; while (v != 0) { q = u / v; r = u % v; u = v; v = r; u0 = u2; v0 = v2; u2 = u1 - q*u2; v2 = v1- q*v2; u1 = u0; v1 = v0; } if (aneg) u1 = -u1; if (bneg) v1 = -v1; d = u; s = u1; t = v1; } long InvMod(long a, long n) { long d, s, t; XGCD(d, s, t, a, n); if (d != 1) Error("InvMod: inverse undefined"); if (s < 0) return s + n; else return s; } long PowerMod(long a, long ee, long n) { long x, y; unsigned long e; if (ee < 0) e = - ((unsigned long) ee); else e = ee; x = 1; y = a; while (e) { if (e & 1) x = MulMod(x, y, n); y = MulMod(y, y, n); e = e >> 1; } if (ee < 0) x = InvMod(x, n); return x; } long ProbPrime(long n, long NumTests) { long m, x, y, z; long i, j, k; if (n <= 1) return 0; if (n == 2) return 1; if (n % 2 == 0) return 0; if (n == 3) return 1; if (n % 3 == 0) return 0; if (n == 5) return 1; if (n % 5 == 0) return 0; if (n == 7) return 1; if (n % 7 == 0) return 0; if (n >= NTL_SP_BOUND) { return ProbPrime(to_ZZ(n), NumTests); } m = n - 1; k = 0; while((m & 1) == 0) { m = m >> 1; k++; } // n - 1 == 2^k * m, m odd for (i = 0; i < NumTests; i++) { do { x = RandomBnd(n); } while (x == 0); // x == 0 is not a useful candidtae for a witness! if (x == 0) continue; z = PowerMod(x, m, n); if (z == 1) continue; j = 0; do { y = z; z = MulMod(y, y, n); j++; } while (j != k && z != 1); if (z != 1 || y != n-1) return 0; } return 1; } long MillerWitness(const ZZ& n, const ZZ& x) { ZZ m, y, z; long j, k; if (x == 0) return 0; add(m, n, -1); k = MakeOdd(m); // n - 1 == 2^k * m, m odd PowerMod(z, x, m, n); if (z == 1) return 0; j = 0; do { y = z; SqrMod(z, y, n); j++; } while (j != k && z != 1); if (z != 1) return 1; add(y, y, 1); if (y != n) return 1; return 0; } // ComputePrimeBound computes a reasonable bound for trial // division in the Miller-Rabin test. // It is computed a bit on the "low" side, since being a bit // low doesn't hurt much, but being too high can hurt a lot. static long ComputePrimeBound(long bn) { long wn = (bn+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS; long fn; if (wn <= 36) fn = wn/4 + 1; else fn = long(1.67*sqrt(double(wn))); long prime_bnd; if (NumBits(bn) + NumBits(fn) > NTL_SP_NBITS) prime_bnd = NTL_SP_BOUND; else prime_bnd = bn*fn; return prime_bnd; } long ProbPrime(const ZZ& n, long NumTrials) { if (n <= 1) return 0; if (n.SinglePrecision()) { return ProbPrime(to_long(n), NumTrials); } long prime_bnd = ComputePrimeBound(NumBits(n)); PrimeSeq s; long p; p = s.next(); while (p && p < prime_bnd) { if (rem(n, p) == 0) return 0; p = s.next(); } ZZ W; W = 2; // first try W == 2....the exponentiation // algorithm runs slightly faster in this case if (MillerWitness(n, W)) return 0; long i; for (i = 0; i < NumTrials; i++) { do { RandomBnd(W, n); } while (W == 0); // W == 0 is not a useful candidate for a witness! if (MillerWitness(n, W)) return 0; } return 1; } void RandomPrime(ZZ& n, long l, long NumTrials) { if (l <= 1) Error("RandomPrime: l out of range"); if (l == 2) { if (RandomBnd(2)) n = 3; else n = 2; return; } do { RandomLen(n, l); if (!IsOdd(n)) add(n, n, 1); } while (!ProbPrime(n, NumTrials)); } void NextPrime(ZZ& n, const ZZ& m, long NumTrials) { ZZ x; if (m <= 2) { n = 2; return; } x = m; while (!ProbPrime(x, NumTrials)) add(x, x, 1); n = x; } long NextPrime(long m, long NumTrials) { long x; if (m <= 2) return 2; x = m; while (x < NTL_SP_BOUND && !ProbPrime(x, NumTrials)) x++; if (x >= NTL_SP_BOUND) Error("NextPrime: no more primes"); return x; } long NextPowerOfTwo(long m) { long k; unsigned long n, um; if (m < 0) return 0; um = m; n = 1; k = 0; while (n < um) { n = n << 1; k++; } if (k >= NTL_BITS_PER_LONG-1) Error("NextPowerOfTwo: overflow"); return k; } long NumBits(long a) { unsigned long aa; if (a < 0) aa = - ((unsigned long) a); else aa = a; long k = 0; while (aa) { k++; aa = aa >> 1; } return k; } long bit(long a, long k) { unsigned long aa; if (a < 0) aa = - ((unsigned long) a); else aa = a; if (k < 0 || k >= NTL_BITS_PER_LONG) return 0; else return long((aa >> k) & 1); } long divide(ZZ& q, const ZZ& a, const ZZ& b) { NTL_ZZRegister(qq); NTL_ZZRegister(r); if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (IsOne(b)) { q = a; return 1; } DivRem(qq, r, a, b); if (!IsZero(r)) return 0; q = qq; return 1; } long divide(const ZZ& a, const ZZ& b) { NTL_ZZRegister(r); if (IsZero(b)) return IsZero(a); if (IsOne(b)) return 1; rem(r, a, b); return IsZero(r); } long divide(ZZ& q, const ZZ& a, long b) { NTL_ZZRegister(qq); if (!b) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (b == 1) { q = a; return 1; } long r = DivRem(qq, a, b); if (r) return 0; q = qq; return 1; } long divide(const ZZ& a, long b) { if (!b) return IsZero(a); if (b == 1) { return 1; } long r = rem(a, b); return (r == 0); } long RandomPrime_long(long l, long NumTrials) { if (l <= 1 || l >= NTL_BITS_PER_LONG) Error("RandomPrime: length out of range"); long n; do { n = RandomLen_long(l); } while (!ProbPrime(n, NumTrials)); return n; } PrimeSeq::PrimeSeq() { movesieve = 0; pshift = -1; pindex = -1; exhausted = 0; } long PrimeSeq::next() { if (exhausted) { return 0; } if (pshift < 0) { shift(0); return 2; } for (;;) { char *p = movesieve; long i = pindex; while ((++i) < NTL_PRIME_BND) { if (p[i]) { pindex = i; return pshift + 2 * i + 3; } } long newshift = pshift + 2*NTL_PRIME_BND; if (newshift > 2 * NTL_PRIME_BND * (2 * NTL_PRIME_BND + 1)) { /* end of the road */ exhausted = 1; return 0; } shift(newshift); } } NTL_THREAD_LOCAL static char *lowsieve = 0; NTL_THREAD_LOCAL static Vec lowsieve_mem; void PrimeSeq::shift(long newshift) { long i; long j; long jstep; long jstart; long ibound; char *p; if (!lowsieve) start(); pindex = -1; exhausted = 0; if (newshift < 0) { pshift = -1; return; } if (newshift == pshift) return; pshift = newshift; if (pshift == 0) { movesieve = lowsieve; } else { if (movesieve_mem.length() == 0) { movesieve_mem.SetLength(NTL_PRIME_BND); } p = movesieve = movesieve_mem.elts(); for (i = 0; i < NTL_PRIME_BND; i++) p[i] = 1; jstep = 3; ibound = pshift + 2 * NTL_PRIME_BND + 1; for (i = 0; jstep * jstep <= ibound; i++) { if (lowsieve[i]) { if (!((jstart = (pshift + 2) / jstep + 1) & 1)) jstart++; if (jstart <= jstep) jstart = jstep; jstart = (jstart * jstep - pshift - 3) / 2; for (j = jstart; j < NTL_PRIME_BND; j += jstep) p[j] = 0; } jstep += 2; } } } void PrimeSeq::start() { long i; long j; long jstep; long jstart; long ibnd; char *p; lowsieve_mem.SetLength(NTL_PRIME_BND); p = lowsieve = lowsieve_mem.elts(); for (i = 0; i < NTL_PRIME_BND; i++) p[i] = 1; jstep = 1; jstart = -1; ibnd = (SqrRoot(2 * NTL_PRIME_BND + 1) - 3) / 2; for (i = 0; i <= ibnd; i++) { jstart += 2 * ((jstep += 2) - 1); if (p[i]) for (j = jstart; j < NTL_PRIME_BND; j += jstep) p[j] = 0; } } void PrimeSeq::reset(long b) { if (b > (2*NTL_PRIME_BND+1)*(2*NTL_PRIME_BND+1)) { exhausted = 1; return; } if (b <= 2) { shift(-1); return; } if ((b & 1) == 0) b++; shift(((b-3) / (2*NTL_PRIME_BND))* (2*NTL_PRIME_BND)); pindex = (b - pshift - 3)/2 - 1; } long Jacobi(const ZZ& aa, const ZZ& nn) { ZZ a, n; long t, k; long d; a = aa; n = nn; t = 1; while (a != 0) { k = MakeOdd(a); d = trunc_long(n, 3); if ((k & 1) && (d == 3 || d == 5)) t = -t; if (trunc_long(a, 2) == 3 && (d & 3) == 3) t = -t; swap(a, n); rem(a, a, n); } if (n == 1) return t; else return 0; } void SqrRootMod(ZZ& x, const ZZ& aa, const ZZ& nn) { if (aa == 0 || aa == 1) { x = aa; return; } // at this point, we must have nn >= 5 if (trunc_long(nn, 2) == 3) { // special case, n = 3 (mod 4) ZZ n, a, e, z; n = nn; a = aa; add(e, n, 1); RightShift(e, e, 2); PowerMod(z, a, e, n); x = z; return; } ZZ n, m; int h, nlen; n = nn; nlen = NumBits(n); sub(m, n, 1); h = MakeOdd(m); // h >= 2 if (nlen > 50 && h < SqrRoot(nlen)) { long i, j; ZZ a, b, a_inv, c, r, m1, d; a = aa; InvMod(a_inv, a, n); if (h == 2) b = 2; else { do { RandomBnd(b, n); } while (Jacobi(b, n) != -1); } PowerMod(c, b, m, n); add(m1, m, 1); RightShift(m1, m1, 1); PowerMod(r, a, m1, n); for (i = h-2; i >= 0; i--) { SqrMod(d, r, n); MulMod(d, d, a_inv, n); for (j = 0; j < i; j++) SqrMod(d, d, n); if (!IsOne(d)) MulMod(r, r, c, n); SqrMod(c, c, n); } x = r; return; } long i, k; ZZ ma, t, u, v, e; ZZ t1, t2, t3, t4; n = nn; NegateMod(ma, aa, n); // find t such that t^2 - 4*a is not a square MulMod(t1, ma, 4, n); do { RandomBnd(t, n); SqrMod(t2, t, n); AddMod(t2, t2, t1, n); } while (Jacobi(t2, n) != -1); // compute u*X + v = X^{(n+1)/2} mod f, where f = X^2 - t*X + a add(e, n, 1); RightShift(e, e, 1); u = 0; v = 1; k = NumBits(e); for (i = k - 1; i >= 0; i--) { add(t2, u, v); sqr(t3, t2); // t3 = (u+v)^2 sqr(t1, u); sqr(t2, v); sub(t3, t3, t1); sub(t3, t3, t2); // t1 = u^2, t2 = v^2, t3 = 2*u*v rem(t1, t1, n); mul(t4, t1, t); add(t4, t4, t3); rem(u, t4, n); mul(t4, t1, ma); add(t4, t4, t2); rem(v, t4, n); if (bit(e, i)) { MulMod(t1, u, t, n); AddMod(t1, t1, v, n); MulMod(v, u, ma, n); u = t1; } } x = v; } // Chinese Remaindering. // // This version in new to v3.7, and is significantly // simpler and faster than the previous version. // // This function takes as input g, a, G, p, // such that a > 0, 0 <= G < p, and gcd(a, p) = 1. // It computes a' = a*p and g' such that // * g' = g (mod a); // * g' = G (mod p); // * -a'/2 < g' <= a'/2. // It then sets g := g' and a := a', and returns 1 iff g has changed. // // Under normal use, the input value g satisfies -a/2 < g <= a/2; // however, this was not documented or enforced in earlier versions, // so to maintain backward compatability, no restrictions are placed // on g. This routine runs faster, though, if -a/2 < g <= a/2, // and the first thing the routine does is to make this condition // hold. // // Also, under normal use, both a and p are odd; however, the routine // will still work even if this is not so. // // The routine is based on the following simple fact. // // Let -a/2 < g <= a/2, and let h satisfy // * g + a h = G (mod p); // * -p/2 < h <= p/2. // Further, if p = 2*h and g > 0, set // g' := g - a h; // otherwise, set // g' := g + a h. // Then g' so defined satisfies the above requirements. // // It is trivial to see that g's satisfies the congruence conditions. // The only thing is to check that the "balancing" condition // -a'/2 < g' <= a'/2 also holds. long CRT(ZZ& gg, ZZ& a, long G, long p) { if (p >= NTL_SP_BOUND) { ZZ GG, pp; conv(GG, G); conv(pp, p); return CRT(gg, a, GG, pp); } long modified = 0; NTL_ZZRegister(g); if (!CRTInRange(gg, a)) { modified = 1; ZZ a1; rem(g, gg, a); RightShift(a1, a, 1); if (g > a1) sub(g, g, a); } else g = gg; long p1; p1 = p >> 1; long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long h; h = rem(g, p); h = SubMod(G, h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!(p & 1) && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } mul(a, a, p); gg = g; return modified; } long CRT(ZZ& gg, ZZ& a, const ZZ& G, const ZZ& p) { long modified = 0; ZZ g; if (!CRTInRange(gg, a)) { modified = 1; ZZ a1; rem(g, gg, a); RightShift(a1, a, 1); if (g > a1) sub(g, g, a); } else g = gg; ZZ p1; RightShift(p1, p, 1); ZZ a_inv; rem(a_inv, a, p); InvMod(a_inv, a_inv, p); ZZ h; rem(h, g, p); SubMod(h, G, h, p); MulMod(h, h, a_inv, p); if (h > p1) sub(h, h, p); if (h != 0) { modified = 1; ZZ ah; mul(ah, a, h); if (!IsOdd(p) && g > 0 && (h == p1)) sub(g, g, ah); else add(g, g, ah); } mul(a, a, p); gg = g; return modified; } void sub(ZZ& x, const ZZ& a, long b) { NTL_ZZRegister(B); conv(B, b); sub(x, a, B); } void sub(ZZ& x, long a, const ZZ& b) { NTL_ZZRegister(A); conv(A, a); sub(x, A, b); } void power2(ZZ& x, long e) { if (e < 0) Error("power2: negative exponent"); set(x); LeftShift(x, x, e); } void conv(ZZ& x, const char *s) { long c; long cval; long sign; long ndigits; long acc; long i = 0; NTL_ZZRegister(a); if (!s) Error("bad ZZ input"); if (!iodigits) InitZZIO(); a = 0; c = s[i]; while (IsWhiteSpace(c)) { i++; c = s[i]; } if (c == '-') { sign = -1; i++; c = s[i]; } else sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) Error("bad ZZ input"); ndigits = 0; acc = 0; while (cval >= 0 && cval <= 9) { acc = acc*10 + cval; ndigits++; if (ndigits == iodigits) { mul(a, a, ioradix); add(a, a, acc); ndigits = 0; acc = 0; } i++; c = s[i]; cval = CharToIntVal(c); } if (ndigits != 0) { long mpy = 1; while (ndigits > 0) { mpy = mpy * 10; ndigits--; } mul(a, a, mpy); add(a, a, acc); } if (sign == -1) negate(a, a); x = a; } void bit_and(ZZ& x, const ZZ& a, long b) { NTL_ZZRegister(B); conv(B, b); bit_and(x, a, B); } void bit_or(ZZ& x, const ZZ& a, long b) { NTL_ZZRegister(B); conv(B, b); bit_or(x, a, B); } void bit_xor(ZZ& x, const ZZ& a, long b) { NTL_ZZRegister(B); conv(B, b); bit_xor(x, a, B); } long power_long(long a, long e) { if (e < 0) Error("power_long: negative exponent"); if (e == 0) return 1; if (a == 1) return 1; if (a == -1) { if (e & 1) return -1; else return 1; } // no overflow check --- result is computed correctly // modulo word size unsigned long res = 1; unsigned long aa = a; long i; for (i = 0; i < e; i++) res *= aa; return to_long(res); } // RANDOM NUMBER GENERATION // Idea for this PRNG. Iteratively hash seed using md5 // to get 256 bytes to initialize arc4. // Then use arc4 to get a pseudo-random byte stream. // I've taken care that the pseudo-random numbers generated by // the routines RandomBnd, RandomBits, and RandomLen // are completely platform independent. // I make use of the md5 compression function, // which I've modified to work on 64-bit machines /* * BEGIN RSA's md5 stuff * */ /* ********************************************************************** ** md5.c ** ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** ** Created: 2/17/90 RLR ** ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** ********************************************************************** */ /* ********************************************************************** ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** ** ** ** License to copy and use this software is granted provided that ** ** it is identified as the "RSA Data Security, Inc. MD5 Message ** ** Digest Algorithm" in all material mentioning or referencing this ** ** software or this function. ** ** ** ** License is also granted to make and use derivative works ** ** provided that such works are identified as "derived from the RSA ** ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** ** material mentioning or referencing the derived work. ** ** ** ** RSA Data Security, Inc. makes no representations concerning ** ** either the merchantability of this software or the suitability ** ** of this software for any particular purpose. It is provided "as ** ** is" without express or implied warranty of any kind. ** ** ** ** These notices must be retained in any copies of any part of this ** ** documentation and/or software. ** ********************************************************************** */ #if (NTL_BITS_PER_LONG <= 32) #define TRUNC32(x) (x) #else #define TRUNC32(x) ((x) & ((1UL << 32)-1UL)) #endif /* F, G and H are basic MD5 functions: selection, majority, parity */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) (TRUNC32((y) ^ ((x) | (~z)))) /* ROTATE_LEFT rotates x left n bits */ #define ROTATE_LEFT(x, n) (TRUNC32(((x) << (n)) | ((x) >> (32-(n))))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ /* Rotation is separate from addition to prevent recomputation */ #define FF(a, b, c, d, x, s, ac) \ {(a) = TRUNC32((a) + F((b), (c), (d)) + (x) + (ac)); \ (a) = ROTATE_LEFT((a), (s)); \ (a) = TRUNC32((a) + (b)); \ } #define GG(a, b, c, d, x, s, ac) \ {(a) = TRUNC32((a) + G((b), (c), (d)) + (x) + (ac)); \ (a) = ROTATE_LEFT((a), (s)); \ (a) = TRUNC32((a) + (b)); \ } #define HH(a, b, c, d, x, s, ac) \ {(a) = TRUNC32((a) + H((b), (c), (d)) + (x) + (ac)); \ (a) = ROTATE_LEFT((a), (s)); \ (a) = TRUNC32((a) + (b)); \ } #define II(a, b, c, d, x, s, ac) \ {(a) = TRUNC32((a) + I((b), (c), (d)) + (x) + (ac)); \ (a) = ROTATE_LEFT((a), (s)); \ (a) = TRUNC32((a) + (b)); \ } static void MD5_default_IV(unsigned long *buf) { buf[0] = 0x67452301UL; buf[1] = 0xefcdab89UL; buf[2] = 0x98badcfeUL; buf[3] = 0x10325476UL; } /* Basic MD5 step. Transform buf based on in. */ static void MD5_compress(unsigned long *buf, unsigned long *in) { unsigned long a = buf[0], b = buf[1], c = buf[2], d = buf[3]; /* Round 1 */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 FF ( a, b, c, d, in[ 0], S11, 3614090360UL); /* 1 */ FF ( d, a, b, c, in[ 1], S12, 3905402710UL); /* 2 */ FF ( c, d, a, b, in[ 2], S13, 606105819UL); /* 3 */ FF ( b, c, d, a, in[ 3], S14, 3250441966UL); /* 4 */ FF ( a, b, c, d, in[ 4], S11, 4118548399UL); /* 5 */ FF ( d, a, b, c, in[ 5], S12, 1200080426UL); /* 6 */ FF ( c, d, a, b, in[ 6], S13, 2821735955UL); /* 7 */ FF ( b, c, d, a, in[ 7], S14, 4249261313UL); /* 8 */ FF ( a, b, c, d, in[ 8], S11, 1770035416UL); /* 9 */ FF ( d, a, b, c, in[ 9], S12, 2336552879UL); /* 10 */ FF ( c, d, a, b, in[10], S13, 4294925233UL); /* 11 */ FF ( b, c, d, a, in[11], S14, 2304563134UL); /* 12 */ FF ( a, b, c, d, in[12], S11, 1804603682UL); /* 13 */ FF ( d, a, b, c, in[13], S12, 4254626195UL); /* 14 */ FF ( c, d, a, b, in[14], S13, 2792965006UL); /* 15 */ FF ( b, c, d, a, in[15], S14, 1236535329UL); /* 16 */ /* Round 2 */ #define S21 5 #define S22 9 #define S23 14 #define S24 20 GG ( a, b, c, d, in[ 1], S21, 4129170786UL); /* 17 */ GG ( d, a, b, c, in[ 6], S22, 3225465664UL); /* 18 */ GG ( c, d, a, b, in[11], S23, 643717713UL); /* 19 */ GG ( b, c, d, a, in[ 0], S24, 3921069994UL); /* 20 */ GG ( a, b, c, d, in[ 5], S21, 3593408605UL); /* 21 */ GG ( d, a, b, c, in[10], S22, 38016083UL); /* 22 */ GG ( c, d, a, b, in[15], S23, 3634488961UL); /* 23 */ GG ( b, c, d, a, in[ 4], S24, 3889429448UL); /* 24 */ GG ( a, b, c, d, in[ 9], S21, 568446438UL); /* 25 */ GG ( d, a, b, c, in[14], S22, 3275163606UL); /* 26 */ GG ( c, d, a, b, in[ 3], S23, 4107603335UL); /* 27 */ GG ( b, c, d, a, in[ 8], S24, 1163531501UL); /* 28 */ GG ( a, b, c, d, in[13], S21, 2850285829UL); /* 29 */ GG ( d, a, b, c, in[ 2], S22, 4243563512UL); /* 30 */ GG ( c, d, a, b, in[ 7], S23, 1735328473UL); /* 31 */ GG ( b, c, d, a, in[12], S24, 2368359562UL); /* 32 */ /* Round 3 */ #define S31 4 #define S32 11 #define S33 16 #define S34 23 HH ( a, b, c, d, in[ 5], S31, 4294588738UL); /* 33 */ HH ( d, a, b, c, in[ 8], S32, 2272392833UL); /* 34 */ HH ( c, d, a, b, in[11], S33, 1839030562UL); /* 35 */ HH ( b, c, d, a, in[14], S34, 4259657740UL); /* 36 */ HH ( a, b, c, d, in[ 1], S31, 2763975236UL); /* 37 */ HH ( d, a, b, c, in[ 4], S32, 1272893353UL); /* 38 */ HH ( c, d, a, b, in[ 7], S33, 4139469664UL); /* 39 */ HH ( b, c, d, a, in[10], S34, 3200236656UL); /* 40 */ HH ( a, b, c, d, in[13], S31, 681279174UL); /* 41 */ HH ( d, a, b, c, in[ 0], S32, 3936430074UL); /* 42 */ HH ( c, d, a, b, in[ 3], S33, 3572445317UL); /* 43 */ HH ( b, c, d, a, in[ 6], S34, 76029189UL); /* 44 */ HH ( a, b, c, d, in[ 9], S31, 3654602809UL); /* 45 */ HH ( d, a, b, c, in[12], S32, 3873151461UL); /* 46 */ HH ( c, d, a, b, in[15], S33, 530742520UL); /* 47 */ HH ( b, c, d, a, in[ 2], S34, 3299628645UL); /* 48 */ /* Round 4 */ #define S41 6 #define S42 10 #define S43 15 #define S44 21 II ( a, b, c, d, in[ 0], S41, 4096336452UL); /* 49 */ II ( d, a, b, c, in[ 7], S42, 1126891415UL); /* 50 */ II ( c, d, a, b, in[14], S43, 2878612391UL); /* 51 */ II ( b, c, d, a, in[ 5], S44, 4237533241UL); /* 52 */ II ( a, b, c, d, in[12], S41, 1700485571UL); /* 53 */ II ( d, a, b, c, in[ 3], S42, 2399980690UL); /* 54 */ II ( c, d, a, b, in[10], S43, 4293915773UL); /* 55 */ II ( b, c, d, a, in[ 1], S44, 2240044497UL); /* 56 */ II ( a, b, c, d, in[ 8], S41, 1873313359UL); /* 57 */ II ( d, a, b, c, in[15], S42, 4264355552UL); /* 58 */ II ( c, d, a, b, in[ 6], S43, 2734768916UL); /* 59 */ II ( b, c, d, a, in[13], S44, 1309151649UL); /* 60 */ II ( a, b, c, d, in[ 4], S41, 4149444226UL); /* 61 */ II ( d, a, b, c, in[11], S42, 3174756917UL); /* 62 */ II ( c, d, a, b, in[ 2], S43, 718787259UL); /* 63 */ II ( b, c, d, a, in[ 9], S44, 3951481745UL); /* 64 */ buf[0] = TRUNC32(buf[0] + a); buf[1] = TRUNC32(buf[1] + b); buf[2] = TRUNC32(buf[2] + c); buf[3] = TRUNC32(buf[3] + d); } /* * END RSA's md5 stuff * */ static void words_from_bytes(unsigned long *txtl, const unsigned char *txtc, long n) { long i; unsigned long v; for (i = 0; i < n; i++) { v = txtc[4*i]; v += ((unsigned long) (txtc[4*i+1])) << 8; v += ((unsigned long) (txtc[4*i+2])) << 16; v += ((unsigned long) (txtc[4*i+3])) << 24; txtl[i] = v; } } static void bytes_from_words(unsigned char *txtc, const unsigned long *txtl, long n) { long i; unsigned long v; for (i = 0; i < n; i++) { v = txtl[i]; txtc[4*i] = v & 255; v = v >> 8; txtc[4*i+1] = v & 255; v = v >> 8; txtc[4*i+2] = v & 255; v = v >> 8; txtc[4*i+3] = v & 255; } } static void MD5_compress1(unsigned long *buf, unsigned char *in, long n) { unsigned long txtl[16]; unsigned char txtc[64]; long i, j, k; if (n < 0) n = 0; i = 0; while (i < n) { k = n-i; if (k > 64) k = 64; for (j = 0; j < k; j++) txtc[j] = in[i+j]; for (; j < 64; j++) txtc[j] = 0; words_from_bytes(txtl, txtc, 16); MD5_compress(buf, txtl); i += k; } } // the "cipherpunk" version of arc4 struct _ZZ_arc4_key { unsigned char state[256]; unsigned char x; unsigned char y; }; static inline void swap_byte(unsigned char *a, unsigned char *b) { unsigned char swapByte; swapByte = *a; *a = *b; *b = swapByte; } static void prepare_key(unsigned char *key_data_ptr, long key_data_len, _ZZ_arc4_key *key) { unsigned char index1; unsigned char index2; unsigned char* state; long counter; state = &key->state[0]; for(counter = 0; counter < 256; counter++) state[counter] = counter; key->x = 0; key->y = 0; index1 = 0; index2 = 0; for(counter = 0; counter < 256; counter++) { index2 = (key_data_ptr[index1] + state[counter] + index2) & 255; swap_byte(&state[counter], &state[index2]); index1 = (index1 + 1) % key_data_len; } } static void arc4(unsigned char *buffer_ptr, long buffer_len, _ZZ_arc4_key *key) { unsigned char x; unsigned char y; unsigned char* state; unsigned char xorIndex; long counter; x = key->x; y = key->y; state = &key->state[0]; for(counter = 0; counter < buffer_len; counter ++) { x = (x + 1) & 255; y = (state[x] + y) & 255; swap_byte(&state[x], &state[y]); xorIndex = (state[x] + state[y]) & 255; buffer_ptr[counter] = state[xorIndex]; } key->x = x; key->y = y; } // global state information for PRNG NTL_THREAD_LOCAL static long ran_initialized = 0; NTL_THREAD_LOCAL static _ZZ_arc4_key ran_key; static const unsigned long default_md5_tab[16] = { 744663023UL, 1011602954UL, 3163087192UL, 3383838527UL, 3305324122UL, 3197458079UL, 2266495600UL, 2760303563UL, 346234297UL, 1919920720UL, 1896169861UL, 2192176675UL, 2027150322UL, 2090160759UL, 2134858730UL, 1131796244UL }; static void build_arc4_tab(unsigned char *seed_bytes, const ZZ& s) { long nb = NumBytes(s); unsigned char *txt; typedef unsigned char u_char; txt = NTL_NEW_OP u_char[nb + 68]; if (!txt) Error("out of memory"); BytesFromZZ(txt + 4, s, nb); bytes_from_words(txt + nb + 4, default_md5_tab, 16); unsigned long buf[4]; unsigned long i; for (i = 0; i < 16; i++) { MD5_default_IV(buf); bytes_from_words(txt, &i, 1); MD5_compress1(buf, txt, nb + 68); bytes_from_words(seed_bytes + 16*i, buf, 4); } delete [] txt; } void SetSeed(const ZZ& s) { unsigned char seed_bytes[256]; build_arc4_tab(seed_bytes, s); prepare_key(seed_bytes, 256, &ran_key); // we discard the first 1024 bytes of the arc4 stream, as this is // recommended practice. arc4(seed_bytes, 256, &ran_key); arc4(seed_bytes, 256, &ran_key); arc4(seed_bytes, 256, &ran_key); arc4(seed_bytes, 256, &ran_key); ran_initialized = 1; } // FIXME: in a thread-safe impl, we should perhaps make the default // seed dependent on the thread ID static void ran_bytes(unsigned char *bytes, long n) { if (!ran_initialized) SetSeed(ZZ::zero()); arc4(bytes, n, &ran_key); } unsigned long RandomWord() { unsigned char buf[NTL_BITS_PER_LONG/8]; long i; unsigned long res; ran_bytes(buf, NTL_BITS_PER_LONG/8); res = 0; for (i = NTL_BITS_PER_LONG/8 - 1; i >= 0; i--) { res = res << 8; res = res | buf[i]; } return res; } long RandomBits_long(long l) { if (l <= 0) return 0; if (l >= NTL_BITS_PER_LONG) Error("RandomBits: length too big"); unsigned char buf[NTL_BITS_PER_LONG/8]; unsigned long res; long i; long nb = (l+7)/8; ran_bytes(buf, nb); res = 0; for (i = nb - 1; i >= 0; i--) { res = res << 8; res = res | buf[i]; } return long(res & ((1UL << l)-1UL)); } unsigned long RandomBits_ulong(long l) { if (l <= 0) return 0; if (l > NTL_BITS_PER_LONG) Error("RandomBits: length too big"); unsigned char buf[NTL_BITS_PER_LONG/8]; unsigned long res; long i; long nb = (l+7)/8; ran_bytes(buf, nb); res = 0; for (i = nb - 1; i >= 0; i--) { res = res << 8; res = res | buf[i]; } if (l < NTL_BITS_PER_LONG) res = res & ((1UL << l)-1UL); return res; } long RandomLen_long(long l) { if (l <= 0) return 0; if (l == 1) return 1; if (l >= NTL_BITS_PER_LONG) Error("RandomLen: length too big"); return RandomBits_long(l-1) + (1L << (l-1)); } void RandomBits(ZZ& x, long l) { if (l <= 0) { x = 0; return; } if (NTL_OVERFLOW(l, 1, 0)) Error("RandomBits: length too big"); long nb = (l+7)/8; NTL_THREAD_LOCAL static Vec buf_mem; NTL_THREAD_LOCAL static unsigned char *buf = 0; NTL_THREAD_LOCAL static long buf_len = 0; if (nb > buf_len) { buf_len = ((nb + 1023)/1024)*1024; // allocate in 1024-byte lots buf_mem.SetLength(buf_len); buf = buf_mem.elts(); } ran_bytes(buf, nb); NTL_ZZRegister(res); ZZFromBytes(res, buf, nb); trunc(res, res, l); x = res; // release buf if it is too big if (buf_len > NTL_RELEASE_THRESH) { buf_mem.kill(); buf = 0; buf_len = 0; } } void RandomLen(ZZ& x, long l) { if (l <= 0) { x = 0; return; } if (l == 1) { x = 1; return; } if (NTL_OVERFLOW(l, 1, 0)) Error("RandomLen: length too big"); // pre-allocate space to avoid two allocations long nw = (l + NTL_ZZ_NBITS - 1)/NTL_ZZ_NBITS; x.SetSize(nw); RandomBits(x, l-1); SetBit(x, l-1); } const long RandomBndExcess = 8; void RandomBnd(ZZ& x, const ZZ& bnd) { if (bnd <= 1) { x = 0; return; } long k = NumBits(bnd); if (weight(bnd) == 1) { RandomBits(x, k-1); return; } long l = k + RandomBndExcess; NTL_ZZRegister(t); NTL_ZZRegister(r); NTL_ZZRegister(t1); do { RandomBits(t, l); rem(r, t, bnd); sub(t1, bnd, r); add(t, t, t1); } while (NumBits(t) > l); x = r; } long RandomBnd(long bnd) { if (bnd <= 1) return 0; long k = NumBits(bnd); if (((bnd - 1) & bnd) == 0) return RandomBits_long(k-1); long l = k + RandomBndExcess; if (l > NTL_BITS_PER_LONG-2) { NTL_ZZRegister(Bnd); NTL_ZZRegister(res); Bnd = bnd; RandomBnd(res, Bnd); return to_long(res); } long t, r; do { t = RandomBits_long(l); r = t % bnd; } while (t + bnd - r > (1L << l)); return r; } // More prime generation stuff... static double Log2(double x) { NTL_THREAD_LOCAL static double log2 = log(2.0); return log(x)/log2; } // Define p(k,t) to be the conditional probability that a random, odd, k-bit // number is composite, given that it passes t iterations of the // Miller-Rabin test. // This routine returns 0 or 1, and if it returns 1 then // p(k,t) <= 2^{-n}. // This basically encodes the estimates of Damgard, Landrock, and Pomerance; // it uses floating point arithmetic, but is coded in such a way // that its results should be correct, assuming that the log function // is computed with reasonable precision. // // It is assumed that k >= 3 and t >= 1; if this does not hold, // then 0 is returned. static long ErrBoundTest(long kk, long tt, long nn) { const double fudge = (1.0 + 1024.0/NTL_FDOUBLE_PRECISION); const double log2_3 = Log2(3.0); const double log2_7 = Log2(7.0); const double log2_20 = Log2(20.0); double k = kk; double t = tt; double n = nn; if (k < 3 || t < 1) return 0; if (n < 1) return 1; // the following test is largely academic if (9*t > NTL_FDOUBLE_PRECISION) Error("ErrBoundTest: t too big"); double log2_k = Log2(k); if ((n + log2_k)*fudge <= 2*t) return 1; if ((2*log2_k + 4.0 + n)*fudge <= 2*sqrt(k)) return 2; if ((t == 2 && k >= 88) || (3 <= t && 9*t <= k && k >= 21)) { if ((1.5*log2_k + t + 4.0 + n)*fudge <= 0.5*Log2(t) + 2*(sqrt(t*k))) return 3; } if (k <= 9*t && 4*t <= k && k >= 21) { if ( ((log2_3 + log2_7 + log2_k + n)*fudge <= log2_20 + 5*t) && ((log2_3 + (15.0/4.0)*log2_k + n)*fudge <= log2_7 + k/2 + 2*t) && ((2*log2_3 + 2 + log2_k + n)*fudge <= k/4 + 3*t) ) return 4; } if (4*t >= k && k >= 21) { if (((15.0/4.0)*log2_k + n)*fudge <= log2_7 + k/2 + 2*t) return 5; } return 0; } void GenPrime(ZZ& n, long k, long err) { if (k <= 1) Error("GenPrime: bad length"); if (k > (1L << 20)) Error("GenPrime: length too large"); if (err < 1) err = 1; if (err > 512) err = 512; if (k == 2) { if (RandomBnd(2)) n = 3; else n = 2; return; } long t; t = 1; while (!ErrBoundTest(k, t, err)) t++; RandomPrime(n, k, t); } long GenPrime_long(long k, long err) { if (k <= 1) Error("GenPrime: bad length"); if (k >= NTL_BITS_PER_LONG) Error("GenPrime: length too large"); if (err < 1) err = 1; if (err > 512) err = 512; if (k == 2) { if (RandomBnd(2)) return 3; else return 2; } long t; t = 1; while (!ErrBoundTest(k, t, err)) t++; return RandomPrime_long(k, t); } void GenGermainPrime(ZZ& n, long k, long err) { if (k <= 1) Error("GenGermainPrime: bad length"); if (k > (1L << 20)) Error("GenGermainPrime: length too large"); if (err < 1) err = 1; if (err > 512) err = 512; if (k == 2) { if (RandomBnd(2)) n = 3; else n = 2; return; } long prime_bnd = ComputePrimeBound(k); if (NumBits(prime_bnd) >= k/2) prime_bnd = (1L << (k/2-1)); ZZ two; two = 2; ZZ n1; PrimeSeq s; ZZ iter; iter = 0; for (;;) { iter++; RandomLen(n, k); if (!IsOdd(n)) add(n, n, 1); s.reset(3); long p; long sieve_passed = 1; p = s.next(); while (p && p < prime_bnd) { long r = rem(n, p); if (r == 0) { sieve_passed = 0; break; } // test if 2*r + 1 = 0 (mod p) if (r == p-r-1) { sieve_passed = 0; break; } p = s.next(); } if (!sieve_passed) continue; if (MillerWitness(n, two)) continue; // n1 = 2*n+1 mul(n1, n, 2); add(n1, n1, 1); if (MillerWitness(n1, two)) continue; // now do t M-R iterations...just to make sure // First compute the appropriate number of M-R iterations, t // The following computes t such that // p(k,t)*8/k <= 2^{-err}/(5*iter^{1.25}) // which suffices to get an overall error probability of 2^{-err}. // Note that this method has the advantage of not requiring // any assumptions on the density of Germain primes. long err1 = max(1, err + 7 + (5*NumBits(iter) + 3)/4 - NumBits(k)); long t; t = 1; while (!ErrBoundTest(k, t, err1)) t++; ZZ W; long MR_passed = 1; long i; for (i = 1; i <= t; i++) { do { RandomBnd(W, n); } while (W == 0); // W == 0 is not a useful candidate witness! if (MillerWitness(n, W)) { MR_passed = 0; break; } } if (MR_passed) break; } } long GenGermainPrime_long(long k, long err) { if (k >= NTL_BITS_PER_LONG-1) Error("GenGermainPrime_long: length too long"); ZZ n; GenGermainPrime(n, k, err); return to_long(n); } NTL_END_IMPL ntl-6.2.1/src/ZZVec.c000644 000765 000024 00000002555 12377144456 014576 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void ZZVec::SetSize(long n, long d) { if (n < 0 || d <= 0) Error("bad args to ZZVec::SetSize()"); if (v) Error("illegal ZZVec initialization"); len = n; bsize = d; if (n == 0) return; v = (ZZ*) NTL_MALLOC(n, sizeof(ZZ), 0); if (!v) Error("out of memory in ZZVec::SetSize()"); long i = 0; long m; long j; while (i < n) { m = ZZ_BlockConstructAlloc(v[i], d, n-i); for (j = 1; j < m; j++) ZZ_BlockConstructSet(v[i], v[i+j], j); i += m; } } void ZZVec::kill() { long n = len; len = 0; bsize = 0; if (n == 0) return; long i = 0; long m; while (i < n) { m = ZZ_BlockDestroy(v[i]); i += m; } free(v); v = 0; } ZZVec& ZZVec::operator=(const ZZVec& a) { if (this == &a) return *this; kill(); SetSize(a.len, a.bsize); long i; for (i = 0; i < a.len; i++) v[i] = (a.v)[i]; return *this; } ZZVec::ZZVec(const ZZVec& a) { v = 0; len = 0; bsize = 0; SetSize(a.len, a.bsize); long i; for (i = 0; i < a.len; i++) v[i] = (a.v)[i]; } void ZZVec::swap_impl(ZZVec& x, ZZVec& y) { ZZ* t1; long t2; t1 = x.v; x.v = y.v; y.v = t1; t2 = x.len; x.len = y.len; y.len = t2; t2 = x.bsize; x.bsize = y.bsize; y.bsize = t2; } NTL_END_IMPL ntl-6.2.1/src/ZZX.c000644 000765 000024 00000036546 12377144456 014277 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL const ZZX& ZZX::zero() { NTL_THREAD_LOCAL static ZZX z; return z; } void conv(ZZ_pX& x, const ZZX& a) { conv(x.rep, a.rep); x.normalize(); } void conv(ZZX& x, const ZZ_pX& a) { conv(x.rep, a.rep); x.normalize(); } istream& operator>>(istream& s, ZZX& x) { s >> x.rep; x.normalize(); return s; } ostream& operator<<(ostream& s, const ZZX& a) { return s << a.rep; } void ZZX::normalize() { long n; const ZZ* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const ZZX& a) { return a.rep.length() == 0; } long IsOne(const ZZX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } long operator==(const ZZX& a, const ZZX& b) { long i, n; const ZZ *ap, *bp; n = a.rep.length(); if (n != b.rep.length()) return 0; ap = a.rep.elts(); bp = b.rep.elts(); for (i = 0; i < n; i++) if (ap[i] != bp[i]) return 0; return 1; } long operator==(const ZZX& a, long b) { if (b == 0) return IsZero(a); if (deg(a) != 0) return 0; return a.rep[0] == b; } long operator==(const ZZX& a, const ZZ& b) { if (IsZero(b)) return IsZero(a); if (deg(a) != 0) return 0; return a.rep[0] == b; } void GetCoeff(ZZ& x, const ZZX& a, long i) { if (i < 0 || i > deg(a)) clear(x); else x = a.rep[i]; } void SetCoeff(ZZX& x, long i, const ZZ& a) { long j, m; if (i < 0) Error("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { ZZ aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(ZZX& x, long i) { long j, m; if (i < 0) Error("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(ZZX& x) { clear(x); SetCoeff(x, 1); } long IsX(const ZZX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const ZZ& coeff(const ZZX& a, long i) { if (i < 0 || i > deg(a)) return ZZ::zero(); else return a.rep[i]; } const ZZ& LeadCoeff(const ZZX& a) { if (IsZero(a)) return ZZ::zero(); else return a.rep[deg(a)]; } const ZZ& ConstTerm(const ZZX& a) { if (IsZero(a)) return ZZ::zero(); else return a.rep[0]; } void conv(ZZX& x, const ZZ& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(ZZX& x, long a) { if (a == 0) x.rep.SetLength(0); else { x.rep.SetLength(1); conv(x.rep[0], a); } } void conv(ZZX& x, const vec_ZZ& a) { x.rep = a; x.normalize(); } void add(ZZX& x, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ *ap, *bp; ZZ* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(ZZX& x, const ZZX& a, const ZZ& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(ZZX& x, const ZZX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(ZZX& x, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ *ap, *bp; ZZ* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(ZZX& x, const ZZX& a, const ZZ& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(ZZX& x, const ZZX& a, long b) { if (b == 0) { x = a; return; } if (a.rep.length() == 0) { x.rep.SetLength(1); conv(x.rep[0], b); negate(x.rep[0], x.rep[0]); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); } x.normalize(); } void sub(ZZX& x, long a, const ZZX& b) { negate(x, b); add(x, x, a); } void sub(ZZX& x, const ZZ& b, const ZZX& a) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (x.rep.MaxLength() == 0) { negate(x, a); add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ *xp = x.rep.elts(); sub(xp[0], b, a.rep[0]); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) negate(xp[i], ap[i]); x.normalize(); } } void negate(ZZX& x, const ZZX& a) { long n = a.rep.length(); x.rep.SetLength(n); const ZZ* ap = a.rep.elts(); ZZ* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } long MaxBits(const ZZX& f) { long i, m; m = 0; for (i = 0; i <= deg(f); i++) { m = max(m, NumBits(f.rep[i])); } return m; } void PlainMul(ZZX& x, const ZZX& a, const ZZX& b) { if (&a == &b) { PlainSqr(x, a); return; } long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } long d = da+db; const ZZ *ap, *bp; ZZ *xp; ZZX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; ZZ t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, ap[j], bp[i-j]); add(accum, accum, t); } xp[i] = accum; } x.normalize(); } void PlainSqr(ZZX& x, const ZZX& a) { long da = deg(a); if (da < 0) { clear(x); return; } long d = 2*da; const ZZ *ap; ZZ *xp; ZZX la; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; long m, m2; ZZ t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-da); jmax = min(da, i); m = jmax - jmin + 1; m2 = m >> 1; jmax = jmin + m2 - 1; clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, ap[j], ap[i-j]); add(accum, accum, t); } add(accum, accum, accum); if (m & 1) { sqr(t, ap[jmax + 1]); add(accum, accum, t); } xp[i] = accum; } x.normalize(); } static void PlainMul(ZZ *xp, const ZZ *ap, long sa, const ZZ *bp, long sb) { if (sa == 0 || sb == 0) return; long sx = sa+sb-1; long i, j, jmin, jmax; NTL_ZZRegister(t); NTL_ZZRegister(accum); for (i = 0; i < sx; i++) { jmin = max(0, i-sb+1); jmax = min(sa-1, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, ap[j], bp[i-j]); add(accum, accum, t); } xp[i] = accum; } } static void KarFold(ZZ *T, const ZZ *b, long sb, long hsa) { long m = sb - hsa; long i; for (i = 0; i < m; i++) add(T[i], b[i], b[hsa+i]); for (i = m; i < hsa; i++) T[i] = b[i]; } static void KarSub(ZZ *T, const ZZ *b, long sb) { long i; for (i = 0; i < sb; i++) sub(T[i], T[i], b[i]); } static void KarAdd(ZZ *T, const ZZ *b, long sb) { long i; for (i = 0; i < sb; i++) add(T[i], T[i], b[i]); } static void KarFix(ZZ *c, const ZZ *b, long sb, long hsa) { long i; for (i = 0; i < hsa; i++) c[i] = b[i]; for (i = hsa; i < sb; i++) add(c[i], c[i], b[i]); } static void PlainMul1(ZZ *xp, const ZZ *ap, long sa, const ZZ& b) { long i; for (i = 0; i < sa; i++) mul(xp[i], ap[i], b); } static void KarMul(ZZ *c, const ZZ *a, long sa, const ZZ *b, long sb, ZZ *stk) { if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const ZZ *t = a; a = b; b = t; } } if (sb == 1) { if (sa == 1) mul(*c, *a, *b); else PlainMul1(c, a, sa, *b); return; } if (sb == 2 && sa == 2) { mul(c[0], a[0], b[0]); mul(c[2], a[1], b[1]); add(stk[0], a[0], a[1]); add(stk[1], b[0], b[1]); mul(c[1], stk[0], stk[1]); sub(c[1], c[1], c[0]); sub(c[1], c[1], c[2]); return; } long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long hsa2 = hsa << 1; ZZ *T1, *T2, *T3; T1 = stk; stk += hsa; T2 = stk; stk += hsa; T3 = stk; stk += hsa2 - 1; /* compute T1 = a_lo + a_hi */ KarFold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ KarFold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ KarMul(T3, T1, hsa, T2, hsa, stk); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ KarMul(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk); KarSub(T3, c + hsa2, sa + sb - hsa2 - 1); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ KarMul(c, a, hsa, b, hsa, stk); KarSub(T3, c, hsa2 - 1); clear(c[hsa2 - 1]); /* finally, add T3 * X^{hsa} to c */ KarAdd(c+hsa, T3, hsa2-1); } else { /* degenerate case */ ZZ *T; T = stk; stk += hsa + sb - 1; /* recursively compute b*a_hi into high part of c */ KarMul(c + hsa, a + hsa, sa - hsa, b, sb, stk); /* recursively compute b*a_lo into T */ KarMul(T, a, hsa, b, sb, stk); KarFix(c, T, hsa + sb - 1, hsa); } } void KarMul(ZZX& c, const ZZX& a, const ZZX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { KarSqr(c, a); return; } vec_ZZ mem; const ZZ *ap, *bp; ZZ *cp; long sa = a.rep.length(); long sb = b.rep.length(); if (&a == &c) { mem = a.rep; ap = mem.elts(); } else ap = a.rep.elts(); if (&b == &c) { mem = b.rep; bp = mem.elts(); } else bp = b.rep.elts(); c.rep.SetLength(sa+sb-1); cp = c.rep.elts(); long maxa, maxb, xover; maxa = MaxBits(a); maxb = MaxBits(b); xover = 2; if (sa < xover || sb < xover) PlainMul(cp, ap, sa, bp, sb); else { /* karatsuba */ long n, hn, sp, depth; n = max(sa, sb); sp = 0; depth = 0; do { hn = (n+1) >> 1; sp += (hn << 2) - 1; n = hn; depth++; } while (n >= xover); ZZVec stk; stk.SetSize(sp, ((maxa + maxb + NumBits(min(sa, sb)) + 2*depth + 10) + NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); KarMul(cp, ap, sa, bp, sb, stk.elts()); } c.normalize(); } void PlainSqr(ZZ* xp, const ZZ* ap, long sa) { if (sa == 0) return; long da = sa-1; long d = 2*da; long i, j, jmin, jmax; long m, m2; NTL_ZZRegister(t); NTL_ZZRegister(accum); for (i = 0; i <= d; i++) { jmin = max(0, i-da); jmax = min(da, i); m = jmax - jmin + 1; m2 = m >> 1; jmax = jmin + m2 - 1; clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, ap[j], ap[i-j]); add(accum, accum, t); } add(accum, accum, accum); if (m & 1) { sqr(t, ap[jmax + 1]); add(accum, accum, t); } xp[i] = accum; } } static void KarSqr(ZZ *c, const ZZ *a, long sa, ZZ *stk) { if (sa == 1) { sqr(*c, *a); return; } if (sa == 2) { sqr(c[0], a[0]); sqr(c[2], a[1]); mul(c[1], a[0], a[1]); add(c[1], c[1], c[1]); return; } if (sa == 3) { sqr(c[0], a[0]); mul(c[1], a[0], a[1]); add(c[1], c[1], c[1]); sqr(stk[0], a[1]); mul(c[2], a[0], a[2]); add(c[2], c[2], c[2]); add(c[2], c[2], stk[0]); mul(c[3], a[1], a[2]); add(c[3], c[3], c[3]); sqr(c[4], a[2]); return; } long hsa = (sa + 1) >> 1; long hsa2 = hsa << 1; ZZ *T1, *T2; T1 = stk; stk += hsa; T2 = stk; stk += hsa2-1; KarFold(T1, a, sa, hsa); KarSqr(T2, T1, hsa, stk); KarSqr(c + hsa2, a+hsa, sa-hsa, stk); KarSub(T2, c + hsa2, sa + sa - hsa2 - 1); KarSqr(c, a, hsa, stk); KarSub(T2, c, hsa2 - 1); clear(c[hsa2 - 1]); KarAdd(c+hsa, T2, hsa2-1); } void KarSqr(ZZX& c, const ZZX& a) { if (IsZero(a)) { clear(c); return; } vec_ZZ mem; const ZZ *ap; ZZ *cp; long sa = a.rep.length(); if (&a == &c) { mem = a.rep; ap = mem.elts(); } else ap = a.rep.elts(); c.rep.SetLength(sa+sa-1); cp = c.rep.elts(); long maxa, xover; maxa = MaxBits(a); xover = 2; if (sa < xover) PlainSqr(cp, ap, sa); else { /* karatsuba */ long n, hn, sp, depth; n = sa; sp = 0; depth = 0; do { hn = (n+1) >> 1; sp += hn+hn+hn - 1; n = hn; depth++; } while (n >= xover); ZZVec stk; stk.SetSize(sp, ((2*maxa + NumBits(sa) + 2*depth + 10) + NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); KarSqr(cp, ap, sa, stk.elts()); } c.normalize(); } NTL_END_IMPL ntl-6.2.1/src/ZZX1.c000644 000765 000024 00000122213 12377144456 014343 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void conv(zz_pX& x, const ZZX& a) { conv(x.rep, a.rep); x.normalize(); } void conv(ZZX& x, const zz_pX& a) { conv(x.rep, a.rep); x.normalize(); } long CRT(ZZX& gg, ZZ& a, const zz_pX& G) { long n = gg.rep.length(); long p = zz_p::modulus(); ZZ new_a; mul(new_a, a, p); long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long p1; p1 = p >> 1; ZZ a1; RightShift(a1, a, 1); long p_odd = (p & 1); long modified = 0; long h; long m = G.rep.length(); long max_mn = max(m, n); gg.rep.SetLength(max_mn); ZZ g; long i; for (i = 0; i < n; i++) { if (!CRTInRange(gg.rep[i], a)) { modified = 1; rem(g, gg.rep[i], a); if (g > a1) sub(g, g, a); } else g = gg.rep[i]; h = rem(g, p); if (i < m) h = SubMod(rep(G.rep[i]), h, p); else h = NegateMod(h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!p_odd && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } gg.rep[i] = g; } for (; i < m; i++) { h = rep(G.rep[i]); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; modified = 1; mul(g, a, h); gg.rep[i] = g; } gg.normalize(); a = new_a; return modified; } long CRT(ZZX& gg, ZZ& a, const ZZ_pX& G) { long n = gg.rep.length(); const ZZ& p = ZZ_p::modulus(); ZZ new_a; mul(new_a, a, p); ZZ a_inv; rem(a_inv, a, p); InvMod(a_inv, a_inv, p); ZZ p1; RightShift(p1, p, 1); ZZ a1; RightShift(a1, a, 1); long p_odd = IsOdd(p); long modified = 0; ZZ h; ZZ ah; long m = G.rep.length(); long max_mn = max(m, n); gg.rep.SetLength(max_mn); ZZ g; long i; for (i = 0; i < n; i++) { if (!CRTInRange(gg.rep[i], a)) { modified = 1; rem(g, gg.rep[i], a); if (g > a1) sub(g, g, a); } else g = gg.rep[i]; rem(h, g, p); if (i < m) SubMod(h, rep(G.rep[i]), h, p); else NegateMod(h, h, p); MulMod(h, h, a_inv, p); if (h > p1) sub(h, h, p); if (h != 0) { modified = 1; mul(ah, a, h); if (!p_odd && g > 0 && (h == p1)) sub(g, g, ah); else add(g, g, ah); } gg.rep[i] = g; } for (; i < m; i++) { h = rep(G.rep[i]); MulMod(h, h, a_inv, p); if (h > p1) sub(h, h, p); modified = 1; mul(g, a, h); gg.rep[i] = g; } gg.normalize(); a = new_a; return modified; } /* Compute a = b * 2^l mod p, where p = 2^n+1. 0<=l<=n and 0= 0) { l %= (n << 1); } else { l = (n << 1) - 1 - (-(l + 1) % (n << 1)); } /* a = b * 2^l mod p */ if (l < n) { LeftRotate(a, b, l, p, n); } else { LeftRotate(a, b, l - n, p, n); SubPos(a, p, a); } } /* Fast Fourier Transform. a is a vector of length 2^l, 2^l divides 2n, p = 2^n+1, w = 2^r mod p is a primitive (2^l)th root of unity. Returns a(1),a(w),...,a(w^{2^l-1}) mod p in bit-reverse order. */ static void fft(vec_ZZ& a, long r, long l, const ZZ& p, long n) { long round; long off, i, j, e; long halfsize; ZZ tmp, tmp1; for (round = 0; round < l; round++, r <<= 1) { halfsize = 1L << (l - 1 - round); for (i = (1L << round) - 1, off = 0; i >= 0; i--, off += halfsize) { for (j = 0, e = 0; j < halfsize; j++, off++, e+=r) { /* One butterfly : ( a[off], a[off+halfsize] ) *= ( 1 w^{j2^round} ) ( 1 -w^{j2^round} ) */ /* tmp = a[off] - a[off + halfsize] mod p */ sub(tmp, a[off], a[off + halfsize]); if (sign(tmp) < 0) { add(tmp, tmp, p); } /* a[off] += a[off + halfsize] mod p */ add(a[off], a[off], a[off + halfsize]); sub(tmp1, a[off], p); if (sign(tmp1) >= 0) { a[off] = tmp1; } /* a[off + halfsize] = tmp * w^{j2^round} mod p */ Rotate(a[off + halfsize], tmp, e, p, n); } } } } /* Inverse FFT. r must be the same as in the call to FFT. Result is by 2^l too large. */ static void ifft(vec_ZZ& a, long r, long l, const ZZ& p, long n) { long round; long off, i, j, e; long halfsize; ZZ tmp, tmp1; for (round = l - 1, r <<= l - 1; round >= 0; round--, r >>= 1) { halfsize = 1L << (l - 1 - round); for (i = (1L << round) - 1, off = 0; i >= 0; i--, off += halfsize) { for (j = 0, e = 0; j < halfsize; j++, off++, e+=r) { /* One inverse butterfly : ( a[off], a[off+halfsize] ) *= ( 1 1 ) ( w^{-j2^round} -w^{-j2^round} ) */ /* a[off + halfsize] *= w^{-j2^round} mod p */ Rotate(a[off + halfsize], a[off + halfsize], -e, p, n); /* tmp = a[off] - a[off + halfsize] */ sub(tmp, a[off], a[off + halfsize]); /* a[off] += a[off + halfsize] mod p */ add(a[off], a[off], a[off + halfsize]); sub(tmp1, a[off], p); if (sign(tmp1) >= 0) { a[off] = tmp1; } /* a[off+halfsize] = tmp mod p */ if (sign(tmp) < 0) { add(a[off+halfsize], tmp, p); } else { a[off+halfsize] = tmp; } } } } } /* Multiplication a la Schoenhage & Strassen, modulo a "Fermat" number p = 2^{mr}+1, where m is a power of two and r is odd. Then w = 2^r is a primitive 2mth root of unity, i.e., polynomials whose product has degree less than 2m can be multiplied, provided that the coefficients of the product polynomial are at most 2^{mr-1} in absolute value. The algorithm is not called recursively; coefficient arithmetic is done directly.*/ void SSMul(ZZX& c, const ZZX& a, const ZZX& b) { long na = deg(a); long nb = deg(b); if (na <= 0 || nb <= 0) { PlainMul(c, a, b); return; } long n = na + nb; /* degree of the product */ /* Choose m and r suitably */ long l = NextPowerOfTwo(n + 1) - 1; /* 2^l <= n < 2^{l+1} */ long m2 = 1L << (l + 1); /* m2 = 2m = 2^{l+1} */ /* Bitlength of the product: if the coefficients of a are absolutely less than 2^ka and the coefficients of b are absolutely less than 2^kb, then the coefficients of ab are absolutely less than (min(na,nb)+1)2^{ka+kb} <= 2^bound. */ long bound = 2 + NumBits(min(na, nb)) + MaxBits(a) + MaxBits(b); /* Let r be minimal so that mr > bound */ long r = (bound >> l) + 1; long mr = r << l; /* p := 2^{mr}+1 */ ZZ p; set(p); LeftShift(p, p, mr); add(p, p, 1); /* Make coefficients of a and b positive */ vec_ZZ aa, bb; aa.SetLength(m2); bb.SetLength(m2); long i; for (i = 0; i <= deg(a); i++) { if (sign(a.rep[i]) >= 0) { aa[i] = a.rep[i]; } else { add(aa[i], a.rep[i], p); } } for (i = 0; i <= deg(b); i++) { if (sign(b.rep[i]) >= 0) { bb[i] = b.rep[i]; } else { add(bb[i], b.rep[i], p); } } /* 2m-point FFT's mod p */ fft(aa, r, l + 1, p, mr); fft(bb, r, l + 1, p, mr); /* Pointwise multiplication aa := aa * bb mod p */ ZZ tmp, ai; for (i = 0; i < m2; i++) { mul(ai, aa[i], bb[i]); if (NumBits(ai) > mr) { RightShift(tmp, ai, mr); trunc(ai, ai, mr); sub(ai, ai, tmp); if (sign(ai) < 0) { add(ai, ai, p); } } aa[i] = ai; } ifft(aa, r, l + 1, p, mr); /* Retrieve c, dividing by 2m, and subtracting p where necessary */ c.rep.SetLength(n + 1); for (i = 0; i <= n; i++) { ai = aa[i]; ZZ& ci = c.rep[i]; if (!IsZero(ai)) { /* ci = -ai * 2^{mr-l-1} = ai * 2^{-l-1} = ai / 2m mod p */ LeftRotate(ai, ai, mr - l - 1, p, mr); sub(tmp, p, ai); if (NumBits(tmp) >= mr) { /* ci >= (p-1)/2 */ negate(ci, ai); /* ci = -ai = ci - p */ } else ci = tmp; } else clear(ci); } } // SSRatio computes how much bigger the SS modulus must be // to accomodate the necessary roots of unity. // This is useful in determining algorithm crossover points. double SSRatio(long na, long maxa, long nb, long maxb) { if (na <= 0 || nb <= 0) return 0; long n = na + nb; /* degree of the product */ long l = NextPowerOfTwo(n + 1) - 1; /* 2^l <= n < 2^{l+1} */ long bound = 2 + NumBits(min(na, nb)) + maxa + maxb; long r = (bound >> l) + 1; long mr = r << l; return double(mr + 1)/double(bound); } void HomMul(ZZX& x, const ZZX& a, const ZZX& b) { if (&a == &b) { HomSqr(x, a); return; } long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } long bound = 2 + NumBits(min(da, db)+1) + MaxBits(a) + MaxBits(b); ZZ prod; set(prod); long i, nprimes; zz_pBak bak; bak.save(); for (nprimes = 0; NumBits(prod) <= bound; nprimes++) { if (nprimes >= NumFFTPrimes) zz_p::FFTInit(nprimes); mul(prod, prod, FFTPrime[nprimes]); } ZZ coeff; ZZ t1; long tt; vec_ZZ c; c.SetLength(da+db+1); long j; for (i = 0; i < nprimes; i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); div(t1, prod, p); tt = rem(t1, p); tt = InvMod(tt, p); mul(coeff, t1, tt); zz_pX A, B, C; conv(A, a); conv(B, b); mul(C, A, B); long m = deg(C); for (j = 0; j <= m; j++) { /* c[j] += coeff*rep(C.rep[j]) */ MulAddTo(c[j], coeff, rep(C.rep[j])); // mul(t1, coeff, rep(C.rep[j])); // add(c[j], c[j], t1); } } x.rep.SetLength(da+db+1); ZZ prod2; RightShift(prod2, prod, 1); for (j = 0; j <= da+db; j++) { rem(t1, c[j], prod); if (t1 > prod2) sub(x.rep[j], t1, prod); else x.rep[j] = t1; } x.normalize(); bak.restore(); } static long MaxSize(const ZZX& a) { long res = 0; long n = a.rep.length(); long i; for (i = 0; i < n; i++) { long t = a.rep[i].size(); if (t > res) res = t; } return res; } void mul(ZZX& c, const ZZX& a, const ZZX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { sqr(c, a); return; } long maxa = MaxSize(a); long maxb = MaxSize(b); long k = min(maxa, maxb); long s = min(deg(a), deg(b)) + 1; if (s == 1 || (k == 1 && s < 40) || (k == 2 && s < 20) || (k == 3 && s < 10)) { PlainMul(c, a, b); return; } if (s < 80 || (k < 30 && s < 150)) { KarMul(c, a, b); return; } if (maxa + maxb >= 40 && SSRatio(deg(a), MaxBits(a), deg(b), MaxBits(b)) < 1.75) SSMul(c, a, b); else HomMul(c, a, b); } void SSSqr(ZZX& c, const ZZX& a) { long na = deg(a); if (na <= 0) { PlainSqr(c, a); return; } long n = na + na; /* degree of the product */ long l = NextPowerOfTwo(n + 1) - 1; /* 2^l <= n < 2^{l+1} */ long m2 = 1L << (l + 1); /* m2 = 2m = 2^{l+1} */ long bound = 2 + NumBits(na) + 2*MaxBits(a); long r = (bound >> l) + 1; long mr = r << l; /* p := 2^{mr}+1 */ ZZ p; set(p); LeftShift(p, p, mr); add(p, p, 1); vec_ZZ aa; aa.SetLength(m2); long i; for (i = 0; i <= deg(a); i++) { if (sign(a.rep[i]) >= 0) { aa[i] = a.rep[i]; } else { add(aa[i], a.rep[i], p); } } /* 2m-point FFT's mod p */ fft(aa, r, l + 1, p, mr); /* Pointwise multiplication aa := aa * aa mod p */ ZZ tmp, ai; for (i = 0; i < m2; i++) { sqr(ai, aa[i]); if (NumBits(ai) > mr) { RightShift(tmp, ai, mr); trunc(ai, ai, mr); sub(ai, ai, tmp); if (sign(ai) < 0) { add(ai, ai, p); } } aa[i] = ai; } ifft(aa, r, l + 1, p, mr); ZZ ci; /* Retrieve c, dividing by 2m, and subtracting p where necessary */ c.rep.SetLength(n + 1); for (i = 0; i <= n; i++) { ai = aa[i]; ZZ& ci = c.rep[i]; if (!IsZero(ai)) { /* ci = -ai * 2^{mr-l-1} = ai * 2^{-l-1} = ai / 2m mod p */ LeftRotate(ai, ai, mr - l - 1, p, mr); sub(tmp, p, ai); if (NumBits(tmp) >= mr) { /* ci >= (p-1)/2 */ negate(ci, ai); /* ci = -ai = ci - p */ } else ci = tmp; } else clear(ci); } } void HomSqr(ZZX& x, const ZZX& a) { long da = deg(a); if (da < 0) { clear(x); return; } long bound = 2 + NumBits(da+1) + 2*MaxBits(a); ZZ prod; set(prod); long i, nprimes; zz_pBak bak; bak.save(); for (nprimes = 0; NumBits(prod) <= bound; nprimes++) { if (nprimes >= NumFFTPrimes) zz_p::FFTInit(nprimes); mul(prod, prod, FFTPrime[nprimes]); } ZZ coeff; ZZ t1; long tt; vec_ZZ c; c.SetLength(da+da+1); long j; for (i = 0; i < nprimes; i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); div(t1, prod, p); tt = rem(t1, p); tt = InvMod(tt, p); mul(coeff, t1, tt); zz_pX A, C; conv(A, a); sqr(C, A); long m = deg(C); for (j = 0; j <= m; j++) { /* c[j] += coeff*rep(C.rep[j]) */ MulAddTo(c[j], coeff, rep(C.rep[j])); // mul(t1, coeff, rep(C.rep[j])); // add(c[j], c[j], t1); } } x.rep.SetLength(da+da+1); ZZ prod2; RightShift(prod2, prod, 1); for (j = 0; j <= da+da; j++) { rem(t1, c[j], prod); if (t1 > prod2) sub(x.rep[j], t1, prod); else x.rep[j] = t1; } x.normalize(); bak.restore(); } void sqr(ZZX& c, const ZZX& a) { if (IsZero(a)) { clear(c); return; } long maxa = MaxSize(a); long k = maxa; long s = deg(a) + 1; if (s == 1 || (k == 1 && s < 50) || (k == 2 && s < 25) || (k == 3 && s < 25) || (k == 4 && s < 10)) { PlainSqr(c, a); return; } if (s < 80 || (k < 30 && s < 150)) { KarSqr(c, a); return; } long mba = MaxBits(a); if (2*maxa >= 40 && SSRatio(deg(a), mba, deg(a), mba) < 1.75) SSSqr(c, a); else HomSqr(c, a); } void mul(ZZX& x, const ZZX& a, const ZZ& b) { ZZ t; long i, da; const ZZ *ap; ZZ* xp; if (IsZero(b)) { clear(x); return; } t = b; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); } void mul(ZZX& x, const ZZX& a, long b) { long i, da; const ZZ *ap; ZZ* xp; if (b == 0) { clear(x); return; } da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], b); } void diff(ZZX& x, const ZZX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void HomPseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b) { if (IsZero(b)) Error("division by zero"); long da = deg(a); long db = deg(b); if (da < db) { r = a; clear(q); return; } ZZ LC; LC = LeadCoeff(b); ZZ LC1; power(LC1, LC, da-db+1); long a_bound = NumBits(LC1) + MaxBits(a); LC1.kill(); long b_bound = MaxBits(b); zz_pBak bak; bak.save(); ZZX qq, rr; ZZ prod, t; set(prod); clear(qq); clear(rr); long i; long Qinstable, Rinstable; Qinstable = 1; Rinstable = 1; for (i = 0; ; i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LC, p)) continue; zz_pX A, B, Q, R; conv(A, a); conv(B, b); if (!IsOne(LC)) { zz_p y; conv(y, LC); power(y, y, da-db+1); mul(A, A, y); } if (!Qinstable) { conv(Q, qq); mul(R, B, Q); sub(R, A, R); if (deg(R) >= db) Qinstable = 1; else Rinstable = CRT(rr, prod, R); } if (Qinstable) { DivRem(Q, R, A, B); t = prod; Qinstable = CRT(qq, t, Q); Rinstable = CRT(rr, prod, R); } if (!Qinstable && !Rinstable) { // stabilized...check if prod is big enough long bound1 = b_bound + MaxBits(qq) + NumBits(min(db, da-db)+1); long bound2 = MaxBits(rr); long bound = max(bound1, bound2); if (a_bound > bound) bound = a_bound; bound += 4; if (NumBits(prod) > bound) break; } } bak.restore(); q = qq; r = rr; } void HomPseudoDiv(ZZX& q, const ZZX& a, const ZZX& b) { ZZX r; HomPseudoDivRem(q, r, a, b); } void HomPseudoRem(ZZX& r, const ZZX& a, const ZZX& b) { ZZX q; HomPseudoDivRem(q, r, a, b); } void PlainPseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b) { long da, db, dq, i, j, LCIsOne; const ZZ *bp; ZZ *qp; ZZ *xp; ZZ s, t; da = deg(a); db = deg(b); if (db < 0) Error("ZZX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); ZZ LC = bp[db]; LCIsOne = IsOne(LC); vec_ZZ x; x = a.rep; xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); if (!LCIsOne) { t = LC; for (i = dq-1; i >= 0; i--) { mul(xp[i], xp[i], t); if (i > 0) mul(t, t, LC); } } for (i = dq; i >= 0; i--) { t = xp[i+db]; qp[i] = t; for (j = db-1; j >= 0; j--) { mul(s, t, bp[j]); if (!LCIsOne) mul(xp[i+j], xp[i+j], LC); sub(xp[i+j], xp[i+j], s); } } if (!LCIsOne) { t = LC; for (i = 1; i <= dq; i++) { mul(qp[i], qp[i], t); if (i < dq) mul(t, t, LC); } } r.rep.SetLength(db); for (i = 0; i < db; i++) r.rep[i] = xp[i]; r.normalize(); } void PlainPseudoDiv(ZZX& q, const ZZX& a, const ZZX& b) { ZZX r; PlainPseudoDivRem(q, r, a, b); } void PlainPseudoRem(ZZX& r, const ZZX& a, const ZZX& b) { ZZX q; PlainPseudoDivRem(q, r, a, b); } void div(ZZX& q, const ZZX& a, long b) { if (b == 0) Error("div: division by zero"); if (!divide(q, a, b)) Error("DivRem: quotient undefined over ZZ"); } void div(ZZX& q, const ZZX& a, const ZZ& b) { if (b == 0) Error("div: division by zero"); if (!divide(q, a, b)) Error("DivRem: quotient undefined over ZZ"); } static void ConstDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZ& b) { if (b == 0) Error("DivRem: division by zero"); if (!divide(q, a, b)) Error("DivRem: quotient undefined over ZZ"); r = 0; } static void ConstRem(ZZX& r, const ZZX& a, const ZZ& b) { if (b == 0) Error("rem: division by zero"); r = 0; } void DivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db < 0) Error("DivRem: division by zero"); if (da < db) { r = a; q = 0; } else if (db == 0) { ConstDivRem(q, r, a, ConstTerm(b)); } else if (IsOne(LeadCoeff(b))) { PseudoDivRem(q, r, a, b); } else if (LeadCoeff(b) == -1) { ZZX b1; negate(b1, b); PseudoDivRem(q, r, a, b1); negate(q, q); } else if (divide(q, a, b)) { r = 0; } else { ZZX q1, r1; ZZ m; PseudoDivRem(q1, r1, a, b); power(m, LeadCoeff(b), da-db+1); if (!divide(q, q1, m)) Error("DivRem: quotient not defined over ZZ"); if (!divide(r, r1, m)) Error("DivRem: remainder not defined over ZZ"); } } void div(ZZX& q, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db < 0) Error("div: division by zero"); if (da < db) { q = 0; } else if (db == 0) { div(q, a, ConstTerm(b)); } else if (IsOne(LeadCoeff(b))) { PseudoDiv(q, a, b); } else if (LeadCoeff(b) == -1) { ZZX b1; negate(b1, b); PseudoDiv(q, a, b1); negate(q, q); } else if (divide(q, a, b)) { // nothing to do } else { ZZX q1; ZZ m; PseudoDiv(q1, a, b); power(m, LeadCoeff(b), da-db+1); if (!divide(q, q1, m)) Error("div: quotient not defined over ZZ"); } } void rem(ZZX& r, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db < 0) Error("rem: division by zero"); if (da < db) { r = a; } else if (db == 0) { ConstRem(r, a, ConstTerm(b)); } else if (IsOne(LeadCoeff(b))) { PseudoRem(r, a, b); } else if (LeadCoeff(b) == -1) { ZZX b1; negate(b1, b); PseudoRem(r, a, b1); } else if (divide(a, b)) { r = 0; } else { ZZX r1; ZZ m; PseudoRem(r1, a, b); power(m, LeadCoeff(b), da-db+1); if (!divide(r, r1, m)) Error("rem: remainder not defined over ZZ"); } } long HomDivide(ZZX& q, const ZZX& a, const ZZX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (IsZero(a)) { clear(q); return 1; } if (deg(b) == 0) { return divide(q, a, ConstTerm(b)); } if (deg(a) < deg(b)) return 0; ZZ ca, cb, cq; content(ca, a); content(cb, b); if (!divide(cq, ca, cb)) return 0; ZZX aa, bb; divide(aa, a, ca); divide(bb, b, cb); if (!divide(LeadCoeff(aa), LeadCoeff(bb))) return 0; if (!divide(ConstTerm(aa), ConstTerm(bb))) return 0; zz_pBak bak; bak.save(); ZZX qq; ZZ prod; set(prod); clear(qq); long res = 1; long Qinstable = 1; long a_bound = MaxBits(aa); long b_bound = MaxBits(bb); long i; for (i = 0; ; i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LeadCoeff(bb), p)) continue; zz_pX A, B, Q, R; conv(A, aa); conv(B, bb); if (!Qinstable) { conv(Q, qq); mul(R, B, Q); sub(R, A, R); if (deg(R) >= deg(B)) Qinstable = 1; else if (!IsZero(R)) { res = 0; break; } else mul(prod, prod, p); } if (Qinstable) { if (!divide(Q, A, B)) { res = 0; break; } Qinstable = CRT(qq, prod, Q); } if (!Qinstable) { // stabilized...check if prod is big enough long bound = b_bound + MaxBits(qq) + NumBits(min(deg(bb), deg(qq)) + 1); if (a_bound > bound) bound = a_bound; bound += 3; if (NumBits(prod) > bound) break; } } bak.restore(); if (res) mul(q, qq, cq); return res; } long HomDivide(const ZZX& a, const ZZX& b) { if (deg(b) == 0) { return divide(a, ConstTerm(b)); } else { ZZX q; return HomDivide(q, a, b); } } long PlainDivide(ZZX& qq, const ZZX& aa, const ZZX& bb) { if (IsZero(bb)) { if (IsZero(aa)) { clear(qq); return 1; } else return 0; } if (deg(bb) == 0) { return divide(qq, aa, ConstTerm(bb)); } long da, db, dq, i, j, LCIsOne; const ZZ *bp; ZZ *qp; ZZ *xp; ZZ s, t; da = deg(aa); db = deg(bb); if (da < db) { return 0; } ZZ ca, cb, cq; content(ca, aa); content(cb, bb); if (!divide(cq, ca, cb)) { return 0; } ZZX a, b, q; divide(a, aa, ca); divide(b, bb, cb); if (!divide(LeadCoeff(a), LeadCoeff(b))) return 0; if (!divide(ConstTerm(a), ConstTerm(b))) return 0; long coeff_bnd = MaxBits(a) + (NumBits(da+1)+1)/2 + (da-db); bp = b.rep.elts(); ZZ LC; LC = bp[db]; LCIsOne = IsOne(LC); xp = a.rep.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { if (!LCIsOne) { if (!divide(t, xp[i+db], LC)) return 0; } else t = xp[i+db]; if (NumBits(t) > coeff_bnd) return 0; qp[i] = t; for (j = db-1; j >= 0; j--) { mul(s, t, bp[j]); sub(xp[i+j], xp[i+j], s); } } for (i = 0; i < db; i++) if (!IsZero(xp[i])) return 0; mul(qq, q, cq); return 1; } long PlainDivide(const ZZX& a, const ZZX& b) { if (deg(b) == 0) return divide(a, ConstTerm(b)); else { ZZX q; return PlainDivide(q, a, b); } } long divide(ZZX& q, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db <= 8 || da-db <= 8) return PlainDivide(q, a, b); else return HomDivide(q, a, b); } long divide(const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db <= 8 || da-db <= 8) return PlainDivide(a, b); else return HomDivide(a, b); } long divide(ZZX& q, const ZZX& a, const ZZ& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (IsOne(b)) { q = a; return 1; } if (b == -1) { negate(q, a); return 1; } long n = a.rep.length(); vec_ZZ res(INIT_SIZE, n); long i; for (i = 0; i < n; i++) { if (!divide(res[i], a.rep[i], b)) return 0; } q.rep = res; return 1; } long divide(const ZZX& a, const ZZ& b) { if (IsZero(b)) return IsZero(a); if (IsOne(b) || b == -1) { return 1; } long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (!divide(a.rep[i], b)) return 0; } return 1; } long divide(ZZX& q, const ZZX& a, long b) { if (b == 0) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (b == 1) { q = a; return 1; } if (b == -1) { negate(q, a); return 1; } long n = a.rep.length(); vec_ZZ res(INIT_SIZE, n); long i; for (i = 0; i < n; i++) { if (!divide(res[i], a.rep[i], b)) return 0; } q.rep = res; return 1; } long divide(const ZZX& a, long b) { if (b == 0) return IsZero(a); if (b == 1 || b == -1) { return 1; } long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (!divide(a.rep[i], b)) return 0; } return 1; } void content(ZZ& d, const ZZX& f) { ZZ res; long i; clear(res); for (i = 0; i <= deg(f); i++) { GCD(res, res, f.rep[i]); if (IsOne(res)) break; } if (sign(LeadCoeff(f)) < 0) negate(res, res); d = res; } void PrimitivePart(ZZX& pp, const ZZX& f) { if (IsZero(f)) { clear(pp); return; } ZZ d; content(d, f); divide(pp, f, d); } static void BalCopy(ZZX& g, const zz_pX& G) { long p = zz_p::modulus(); long p2 = p >> 1; long n = G.rep.length(); long i; long t; g.rep.SetLength(n); for (i = 0; i < n; i++) { t = rep(G.rep[i]); if (t > p2) t = t - p; conv(g.rep[i], t); } } void GCD(ZZX& d, const ZZX& a, const ZZX& b) { if (IsZero(a)) { d = b; if (sign(LeadCoeff(d)) < 0) negate(d, d); return; } if (IsZero(b)) { d = a; if (sign(LeadCoeff(d)) < 0) negate(d, d); return; } ZZ c1, c2, c; ZZX f1, f2; content(c1, a); divide(f1, a, c1); content(c2, b); divide(f2, b, c2); GCD(c, c1, c2); ZZ ld; GCD(ld, LeadCoeff(f1), LeadCoeff(f2)); ZZX g, h, res; ZZ prod; set(prod); zz_pBak bak; bak.save(); long FirstTime = 1; long i; for (i = 0; ;i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LeadCoeff(f1), p) || divide(LeadCoeff(f2), p)) continue; zz_pX G, F1, F2; zz_p LD; conv(F1, f1); conv(F2, f2); conv(LD, ld); GCD(G, F1, F2); mul(G, G, LD); if (deg(G) == 0) { set(res); break; } if (FirstTime || deg(G) < deg(g)) { FirstTime = 0; conv(prod, p); BalCopy(g, G); } else if (deg(G) > deg(g)) continue; else if (!CRT(g, prod, G)) { PrimitivePart(res, g); if (divide(f1, res) && divide(f2, res)) break; } } bak.restore(); mul(d, res, c); if (sign(LeadCoeff(d)) < 0) negate(d, d); } void trunc(ZZX& x, const ZZX& a, long m) // x = a % X^m, output may alias input { if (m < 0) Error("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; ZZ* xp; const ZZ* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void LeftShift(ZZX& x, const ZZX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void RightShift(ZZX& x, const ZZX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) Error("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void TraceVec(vec_ZZ& S, const ZZX& ff) { if (!IsOne(LeadCoeff(ff))) Error("TraceVec: bad args"); ZZX f; f = ff; long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; ZZ acc, t; S[0] = n; for (k = 1; k < n; k++) { mul(acc, f.rep[n-k], k); for (i = 1; i < k; i++) { mul(t, f.rep[n-i], S[k-i]); add(acc, acc, t); } negate(S[k], acc); } } static void EuclLength(ZZ& l, const ZZX& a) { long n = a.rep.length(); long i; ZZ sum, t; clear(sum); for (i = 0; i < n; i++) { sqr(t, a.rep[i]); add(sum, sum, t); } if (sum > 1) { SqrRoot(l, sum); add(l, l, 1); } else l = sum; } static long ResBound(const ZZX& a, const ZZX& b) { if (IsZero(a) || IsZero(b)) return 0; ZZ t1, t2, t; EuclLength(t1, a); EuclLength(t2, b); power(t1, t1, deg(b)); power(t2, t2, deg(a)); mul(t, t1, t2); return NumBits(t); } void resultant(ZZ& rres, const ZZX& a, const ZZX& b, long deterministic) { if (IsZero(a) || IsZero(b)) { clear(rres); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); long instable = 1; long bound = 2+ResBound(a, b); long gp_cnt = 0; ZZ res, prod; clear(res); set(prod); long i; for (i = 0; ; i++) { if (NumBits(prod) > bound) break; if (!deterministic && !instable && bound > 1000 && NumBits(prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(res))); do { GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); } while (divide(LeadCoeff(a), P) || divide(LeadCoeff(b), P)); ZZ_p::init(P); ZZ_pX A, B; conv(A, a); conv(B, b); ZZ_p t; resultant(t, A, B); if (CRT(res, prod, rep(t), P)) instable = 1; else break; } zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LeadCoeff(a), p) || divide(LeadCoeff(b), p)) continue; zz_pX A, B; conv(A, a); conv(B, b); zz_p t; resultant(t, A, B); instable = CRT(res, prod, rep(t), p); } rres = res; zbak.restore(); Zbak.restore(); } void MinPolyMod(ZZX& gg, const ZZX& a, const ZZX& f) { if (!IsOne(LeadCoeff(f)) || deg(f) < 1 || deg(a) >= deg(f)) Error("MinPolyMod: bad args"); if (IsZero(a)) { SetX(gg); return; } ZZ_pBak Zbak; Zbak.save(); zz_pBak zbak; zbak.save(); long n = deg(f); long instable = 1; long gp_cnt = 0; ZZ prod; ZZX g; clear(g); set(prod); long bound = -1; long i; for (i = 0; ; i++) { if (deg(g) == n) { if (bound < 0) bound = 2+CharPolyBound(a, f); if (NumBits(prod) > bound) break; } if (!instable && (deg(g) < n || (deg(g) == n && bound > 1000 && NumBits(prod) < 0.75*bound))) { // guarantees 2^{-80} error probability long plen = 90 + max( 2*NumBits(n) + NumBits(MaxBits(f)), max( NumBits(n) + NumBits(MaxBits(a)), NumBits(MaxBits(g)) )); ZZ P; GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); ZZ_pX A, F, G; conv(A, a); conv(F, f); conv(G, g); ZZ_pXModulus FF; build(FF, F); ZZ_pX H; CompMod(H, G, A, FF); if (IsZero(H)) break; instable = 1; } zz_p::FFTInit(i); zz_pX A, F; conv(A, a); conv(F, f); zz_pXModulus FF; build(FF, F); zz_pX G; MinPolyMod(G, A, FF); if (deg(G) < deg(g)) continue; if (deg(G) > deg(g)) { clear(g); set(prod); } instable = CRT(g, prod, G); } gg = g; Zbak.restore(); zbak.restore(); } void XGCD(ZZ& rr, ZZX& ss, ZZX& tt, const ZZX& a, const ZZX& b, long deterministic) { ZZ r; resultant(r, a, b, deterministic); if (IsZero(r)) { clear(rr); return; } zz_pBak bak; bak.save(); long i; long instable = 1; ZZ tmp; ZZ prod; ZZX s, t; set(prod); clear(s); clear(t); for (i = 0; ; i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LeadCoeff(a), p) || divide(LeadCoeff(b), p) || divide(r, p)) continue; zz_p R; conv(R, r); zz_pX D, S, T, A, B; conv(A, a); conv(B, b); if (!instable) { conv(S, s); conv(T, t); zz_pX t1, t2; mul(t1, A, S); mul(t2, B, T); add(t1, t1, t2); if (deg(t1) == 0 && ConstTerm(t1) == R) mul(prod, prod, p); else instable = 1; } if (instable) { XGCD(D, S, T, A, B); mul(S, S, R); mul(T, T, R); tmp = prod; long Sinstable = CRT(s, tmp, S); long Tinstable = CRT(t, prod, T); instable = Sinstable || Tinstable; } if (!instable) { long bound1 = NumBits(min(deg(a), deg(s)) + 1) + MaxBits(a) + MaxBits(s); long bound2 = NumBits(min(deg(b), deg(t)) + 1) + MaxBits(b) + MaxBits(t); long bound = 4 + max(NumBits(r), max(bound1, bound2)); if (NumBits(prod) > bound) break; } } rr = r; ss = s; tt = t; bak.restore(); } void NormMod(ZZ& x, const ZZX& a, const ZZX& f, long deterministic) { if (!IsOne(LeadCoeff(f)) || deg(a) >= deg(f) || deg(f) <= 0) Error("norm: bad args"); if (IsZero(a)) { clear(x); return; } resultant(x, f, a, deterministic); } void TraceMod(ZZ& res, const ZZX& a, const ZZX& f) { if (!IsOne(LeadCoeff(f)) || deg(a) >= deg(f) || deg(f) <= 0) Error("trace: bad args"); vec_ZZ S; TraceVec(S, f); InnerProduct(res, S, a.rep); } void discriminant(ZZ& d, const ZZX& a, long deterministic) { long m = deg(a); if (m < 0) { clear(d); return; } ZZX a1; ZZ res; diff(a1, a); resultant(res, a, a1, deterministic); if (!divide(res, res, LeadCoeff(a))) Error("discriminant: inexact division"); m = m & 3; if (m >= 2) negate(res, res); d = res; } void MulMod(ZZX& x, const ZZX& a, const ZZX& b, const ZZX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0 || !IsOne(LeadCoeff(f))) Error("MulMod: bad args"); ZZX t; mul(t, a, b); rem(x, t, f); } void SqrMod(ZZX& x, const ZZX& a, const ZZX& f) { if (deg(a) >= deg(f) || deg(f) == 0 || !IsOne(LeadCoeff(f))) Error("MulMod: bad args"); ZZX t; sqr(t, a); rem(x, t, f); } static void MulByXModAux(ZZX& h, const ZZX& a, const ZZX& f) { long i, n, m; ZZ* hh; const ZZ *aa, *ff; ZZ t, z; n = deg(f); m = deg(a); if (m >= n || n == 0 || !IsOne(LeadCoeff(f))) Error("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(ZZX& h, const ZZX& a, const ZZX& f) { if (&h == &f) { ZZX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } static void EuclLength1(ZZ& l, const ZZX& a) { long n = a.rep.length(); long i; ZZ sum, t; clear(sum); for (i = 0; i < n; i++) { sqr(t, a.rep[i]); add(sum, sum, t); } abs(t, ConstTerm(a)); mul(t, t, 2); add(t, t, 1); add(sum, sum, t); if (sum > 1) { SqrRoot(l, sum); add(l, l, 1); } else l = sum; } long CharPolyBound(const ZZX& a, const ZZX& f) // This computes a bound on the size of the // coefficients of the characterstic polynomial. // It uses the characterization of the char poly as // resultant_y(f(y), x-a(y)), and then interpolates this // through complex primimitive (deg(f)+1)-roots of unity. { if (IsZero(a) || IsZero(f)) Error("CharPolyBound: bad args"); ZZ t1, t2, t; EuclLength1(t1, a); EuclLength(t2, f); power(t1, t1, deg(f)); power(t2, t2, deg(a)); mul(t, t1, t2); return NumBits(t); } void SetCoeff(ZZX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else { NTL_ZZRegister(aa); conv(aa, a); SetCoeff(x, i, aa); } } void CopyReverse(ZZX& x, const ZZX& a, long hi) // x[0..hi] = reverse(a[0..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi+1; m = a.rep.length(); x.rep.SetLength(n); const ZZ* ap = a.rep.elts(); ZZ* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void reverse(ZZX& x, const ZZX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) Error("overflow in reverse"); if (&x == &a) { ZZX tmp; CopyReverse(tmp, a, hi); x = tmp; } else CopyReverse(x, a, hi); } void MulTrunc(ZZX& x, const ZZX& a, const ZZX& b, long n) { ZZX t; mul(t, a, b); trunc(x, t, n); } void SqrTrunc(ZZX& x, const ZZX& a, long n) { ZZX t; sqr(t, a); trunc(x, t, n); } void NewtonInvTrunc(ZZX& c, const ZZX& a, long e) { ZZ x; if (ConstTerm(a) == 1) x = 1; else if (ConstTerm(a) == -1) x = -1; else Error("InvTrunc: non-invertible constant term"); if (e == 1) { conv(c, x); return; } vec_long E; E.SetLength(0); append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long L = E.length(); ZZX g, g0, g1, g2; g.rep.SetMaxLength(E[0]); g0.rep.SetMaxLength(E[0]); g1.rep.SetMaxLength((3*E[0]+1)/2); g2.rep.SetMaxLength(E[0]); conv(g, x); long i; for (i = L-1; i > 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); sub(g, g, g2); } c = g; } void InvTrunc(ZZX& c, const ZZX& a, long e) { if (e < 0) Error("InvTrunc: bad args"); if (e == 0) { clear(c); return; } if (NTL_OVERFLOW(e, 1, 0)) Error("overflow in InvTrunc"); NewtonInvTrunc(c, a, e); } NTL_END_IMPL ntl-6.2.1/src/ZZXCharPoly.c000644 000765 000024 00000002375 12377144456 015732 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void CharPolyMod(ZZX& gg, const ZZX& a, const ZZX& f, long deterministic) { if (!IsOne(LeadCoeff(f)) || deg(f) < 1 || deg(a) >= deg(f)) Error("CharPolyMod: bad args"); if (IsZero(a)) { clear(gg); SetCoeff(gg, deg(f)); return; } long bound = 2 + CharPolyBound(a, f); long gp_cnt = 0; zz_pBak bak; bak.save(); ZZ_pBak bak1; bak1.save(); ZZX g; ZZ prod; clear(g); set(prod); long i; long instable = 1; for (i = 0; ; i++) { if (NumBits(prod) > bound) break; if (!deterministic && !instable && bound > 1000 && NumBits(prod) < 0.25*bound) { long plen = 90 + NumBits(max(bound, MaxBits(g))); ZZ P; GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); ZZ_pX G, A, F; conv(A, a); conv(F, f); CharPolyMod(G, A, F); if (CRT(g, prod, G)) instable = 1; else break; } zz_p::FFTInit(i); zz_pX G, A, F; conv(A, a); conv(F, f); CharPolyMod(G, A, F); instable = CRT(g, prod, G); } gg = g; bak.restore(); bak1.restore(); } NTL_END_IMPL ntl-6.2.1/src/ZZXFacTest.c000644 000765 000024 00000002116 12377144457 015534 0ustar00shoupstaff000000 000000 #include NTL_CLIENT long compare(const ZZX& a, const ZZX& b) { if (deg(a) < deg(b)) return 0; if (deg(a) > deg(b)) return 1; long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (a.rep[i] < b.rep[i]) return 0; if (a.rep[i] > b.rep[i]) return 1; } return 0; } void sort(vec_pair_ZZX_long& v) { long n = v.length(); long i, j; for (i = 0; i < n-1; i++) for (j = 0; j < n-1-i; j++) if (compare(v[j].a, v[j+1].a)) { swap(v[j].a, v[j+1].a); swap(v[j].b, v[j+1].b); } } int main(int argc, char **argv) { ZZX f1, f; if (argc > 1) ZZXFac_MaxPrune = atoi(argv[1]); cin >> f; vec_pair_ZZX_long factors; ZZ c; double t; t = GetTime(); factor(c, factors, f, 0); t = GetTime()-t; cerr << "total time: " << t << "\n"; mul(f1, factors); mul(f1, f1, c); if (f != f1) Error("FACTORIZATION INCORRECT!!!"); sort(factors); cout << c << "\n"; cout << factors << "\n"; return 0; } ntl-6.2.1/src/ZZXFacTestIn000644 000765 000024 00000014423 12377144457 015606 0ustar00shoupstaff000000 000000 [ 2757808487144838302895430769948248417729237108863869417509479459915767341323330697211864790593685466362642868685686280572196434680273380283012145961103760692626213505149801403142032630867205290294889677921852958863296316098679545758264555461523658710938789459422476508285713011640130252486568573874403279248369585169539213650618995126951019719642265868631105857663880266888615740687129117228288314207488263153874611799588864 0 0 0 0 0 -216322796837555313021432683645937044292921028613383407157804069297831574640998740656489092120685008467028608331849579265535298919026656996120638521170849310580349430742714282458612690837924997423939358531519250439003103809474194653867052412730011984853274391208927747745495001768576577005852099658803085546514828589578330785402902514368037827033046816681733696103002335485194130317912396254882191766550071245537280 0 0 0 0 0 -461037645433479417894020721333520318742787637796222824861773705209889273869538158383427629416696554307900636877857163108477972707536277062193762789904663727290361284224373517600871057249998734207159849953758589691456457289461969382313561313225919667846650484354465287838669574263259013740628682955721862333944942797610117714349319340424888849377188433375019685712170554798874566289464703683278915239936 0 0 0 0 0 -3006606488311441089896683017688393310181237526393515483185168180454254753097973363635722407434487318654611062408549655477030250215182281891825672566995224009864674440632939039163270907351880438387976862382953630127475285232095605983810246580601204355061953631934206101782233808526261885763004588113518320634896519093555011110157604966440212309535525594054654293518320014613131809110622208 0 0 0 0 0 -21667646451621122746329554641562526144092633323312599411016990419323105385099476066414168972485002571354506235276444763858199439264635997569307854261698326829531703857487029929169587379456251270438809123403197975344780862412222180332148184540879408846734261457232407592147312924337495632438881306066500258566449544033936294138097409605834038606201765458164323353573757812736 0 0 0 0 0 -36008946342647299345277533676465042992542509358162091707911485884063199188678585181307031154064029716715217548592392000646414311357113983560970141370451913098200635822787067067854257570327208938999696955706264073506673179971102683350614122127866850451153062491787093182867397127538003924258331826086311209206145468869911581822662684689775342390081444166762496 0 0 0 0 0 64738333885402706154009400777843384948514403975131509466836736265603889387062685884838924226241494383359395885853573043385536386037715829201209541872597706855188799653603478660006394706968635342978467902539925660331269747297563569373972862258677268612185384308671129076702627081272278586910256050615727493523124564910427355844022903201664598016 0 0 0 0 0 -26515019326962174180142979909852192000598024025005741295940640978614198820508372895246811842900425977352727727321855043342564236181262669572054649107156675328942799346600624572167621155490882477365676272092450671794375283335841074839674104033802419109510303627230113525211458922561813524476132216574712854465367040031027145736192 0 0 0 0 0 7206103572192660713378206441635342218917489717304647992423853713271386261468915707872924405011212678144586363155710573280556474140830016874081726445858124315662916567493737199217110913142452405975457031642733926038866594546019867393529529573884911052196182095293632879922014565430281245217054716156649445034819584 0 0 0 0 0 -1781067445792627012203411699914789751917558964317719007317246424900608235475797721781459407143458070618250900401160717537304193257391576912113861254338589725654811524225989470856639467420913364918958248936121424237401680876071173527822994467656057208698530802400487646077493116544189557449970155520 0 0 0 0 0 257785868023252499546719038629025522238370895088838886132974669167861057091364847664488796999614147085642953811171182098166013025545859882309438475565596820726130902460185426222014793570631782686609398943162320798462220946658785090792728810983258963716578939056822038673472371032064 0 0 0 0 0 -11784090207202014162295386617819122580975749672866993427537075993392758066192465164322165415699997447946113816444451865902475946080059998736123233932142195687596120620775313704725043713670267057116323795251403918781211539279372041111665200731953898028103168618921984 0 0 0 0 0 -516024270178733628499623062311311909026630748206142586718438261050317424310047984113834321775600080026192071968298564681207899012445940514128285818475704941072871032892579017242172498256146144732370397366971600828731748910067376163611390633039626240 0 0 0 0 0 30082639005203703587384390914836066417375929216836277495255127429645641088564854026651642629932602536304239256338883055950342516352052967456427931536708936701164689433642079716822865825451517411212445927909524063734481575283370491904 0 0 0 0 0 -473470234117762253449114353073575227253051133950080887048220406201777923641087656057923908627860421347898111116275922195546977433176120962969045561381814949718893972897291028710748149921273892963880265171252944044032 0 0 0 0 0 1716231160060069630599685050354626175015068955757203109707649882577572773165548338611188714799775273882912731234014004123562719620912869622981185312386637525543829470533595866145631607760885722906624 0 0 0 0 0 29097610765037817861202663659325678575900946766272112229562997159720733072202069362200879071525561150306287386997432893787696445551277644983772558101666007653602762940659581050683392 0 0 0 0 0 -359926316046483943753279829287876608460021803187136100943332906260813526077725113393005907399350257834664287535635450778981949557310768189387775714926393025942781952 0 0 0 0 0 1585164055408008634764541421847990628448201383564778254157208549989039915612818011950714697494640213070044956331618331201033480861222528629063286784 0 0 0 0 0 -2786147914453983786915822775172002754752542153742435684470657396691295332282129004399822009077517014397168296974400680697863864320 0 0 0 0 0 -38152084257499719867416104314045082135545017120806331924723488759543432766463641099223031913762482060169052160 0 0 0 0 0 6156765507729276548165940166182211314235431893392787456381452344509549569751736679901247307776 0 0 0 0 0 -6689833869884920066141475743520535508680559052015304499397212203049103130624 0 0 0 0 0 2000741892753026115892243757690184900091769801141945106432 0 0 0 0 0 -50111580155260460844584241578962989056 0 0 0 0 0 -28293184124737694080 0 0 0 0 0 1 ] ntl-6.2.1/src/ZZXFacTestOut000644 000765 000024 00000003437 12377144457 016012 0ustar00shoupstaff000000 000000 1 [[[-446972 -1000 1] 1] [[-446972 1000 1] 1] [[-33692 -652 1] 1] [[-33692 652 1] 1] [[273892 -1076 1] 1] [[273892 1076 1] 1] [[680548 -1652 1] 1] [[680548 1652 1] 1] [[849892 -1844 1] 1] [[849892 1844 1] 1] [[2052868 -2920 1] 1] [[2052868 2920 1] 1] [[1135150864 -21967184 458796 652 1] 1] [[1135150864 21967184 458796 -652 1] 1] [[75016827664 -294707792 883884 -1076 1] 1] [[75016827664 294707792 883884 1076 1] 1] [[190713877264 0 -868516 0 1] 1] [[190713877264 0 354248 0 1] 1] [[190713877264 0 514268 0 1] 1] [[199783968784 -446972000 1446972 1000 1] 1] [[199783968784 446972000 1446972 -1000 1] 1] [[463145580304 -1124265296 2048556 -1652 1] 1] [[463145580304 1124265296 2048556 1652 1] 1] [[722316411664 -1567200848 2550444 -1844 1] 1] [[722316411664 1567200848 2550444 1844 1] 1] [[4214267025424 -5994374560 6473532 -2920 1] 1] [[4214267025424 5994374560 6473532 2920 1] 1] [[1509082248015679744 -4357134752332032 -98072348436992 295269334272 9137611056 68929344 311776 828 1] 1] [[1509082248015679744 0 208724941108480 0 2515466400 0 62032 0 1] 1] [[1509082248015679744 4357134752332032 -98072348436992 -295269334272 9137611056 -68929344 311776 -828 1] 1] [[8242842673465502834944 -15956454898822379520 -27757983946374272 73664993909760 11779157808 -523091712 100024 1248 1] 1] [[8242842673465502834944 0 86404395953830144 0 503486762592 0 1357456 0 1] 1] [[8242842673465502834944 15956454898822379520 -27757983946374272 -73664993909760 11779157808 523091712 100024 -1248 1] 1] [[24645776912953075323136 -32346413682678568704 122046949888364032 -141608259851520 543658138416 -2284518720 4370272 -3324 1] 1] [[24645776912953075323136 0 -201640765439499008 0 329745118368 0 2308432 0 1] 1] [[24645776912953075323136 32346413682678568704 122046949888364032 141608259851520 543658138416 2284518720 4370272 3324 1] 1]] ntl-6.2.1/src/ZZXFactoring.c000644 000765 000024 00000232712 12377144456 016125 0ustar00shoupstaff000000 000000 #include #include #include #include #include #include #include NTL_START_IMPL NTL_THREAD_LOCAL long ZZXFac_van_Hoeij = 1; NTL_THREAD_LOCAL static long ok_to_abandon = 0; struct LocalInfoT { long n; long NumPrimes; long NumFactors; vec_long p; vec_vec_long pattern; ZZ PossibleDegrees; PrimeSeq s; }; static void mul(ZZ_pX& x, vec_ZZ_pX& a) // this performs multiplications in close-to-optimal order, // and kills a in the process { long n = a.length(); // first, deal with some trivial cases if (n == 0) { set(x); a.kill(); return; } else if (n == 1) { x = a[0]; a.kill(); return; } long i, j; // assume n > 1 and all a[i]'s are nonzero // sort into non-increasing degrees for (i = 1; i <= n - 1; i++) for (j = 0; j <= n - i - 1; j++) if (deg(a[j]) < deg(a[j+1])) swap(a[j], a[j+1]); ZZ_pX g; while (n > 1) { // replace smallest two poly's by their product mul(g, a[n-2], a[n-1]); a[n-2].kill(); a[n-1].kill(); swap(g, a[n-2]); n--; // re-establish order i = n-1; while (i > 0 && deg(a[i-1]) < deg(a[i])) { swap(a[i-1], a[i]); i--; } } x = a[0]; a[0].kill(); a.SetLength(0); } void mul(ZZX& x, const vec_pair_ZZX_long& a) { long l = a.length(); ZZX res; long i, j; set(res); for (i = 0; i < l; i++) for (j = 0; j < a[i].b; j++) mul(res, res, a[i].a); x = res; } void SquareFreeDecomp(vec_pair_ZZX_long& u, const ZZX& ff) // input is primitive { ZZX f = ff; ZZX d, v, w, s, t1; long i; u.SetLength(0); if (deg(f) <= 0) return; diff(t1, f); GCD(d, f, t1); if (deg(d) == 0) { append(u, cons(f, 1L)); return; } divide(v, f, d); divide(w, t1, d); i = 0; for (;;) { i = i + 1; diff(t1, v); sub(s, w, t1); if (IsZero(s)) { if (deg(v) != 0) append(u, cons(v, i)); return; } GCD(d, v, s); divide(v, v, d); divide(w, s, d); if (deg(d) != 0) append(u, cons(d, i)); } } static void HenselLift(ZZX& Gout, ZZX& Hout, ZZX& Aout, ZZX& Bout, const ZZX& f, const ZZX& g, const ZZX& h, const ZZX& a, const ZZX& b, const ZZ& p) { ZZX c, g1, h1, G, H, A, B; mul(c, g, h); sub(c, f, c); if (!divide(c, c, p)) Error("inexact division"); ZZ_pX cc, gg, hh, aa, bb, tt, gg1, hh1; conv(cc, c); conv(gg, g); conv(hh, h); conv(aa, a); conv(bb, b); ZZ_pXModulus GG; ZZ_pXModulus HH; build(GG, gg); build(HH, hh); ZZ_pXMultiplier AA; ZZ_pXMultiplier BB; build(AA, aa, HH); build(BB, bb, GG); rem(gg1, cc, GG); MulMod(gg1, gg1, BB, GG); rem(hh1, cc, HH); MulMod(hh1, hh1, AA, HH); conv(g1, gg1); mul(g1, g1, p); add(G, g, g1); conv(h1, hh1); mul(h1, h1, p); add(H, h, h1); /* lift inverses */ ZZX t1, t2, r; mul(t1, a, G); mul(t2, b, H); add(t1, t1, t2); add(t1, t1, -1); negate(t1, t1); if (!divide(r, t1, p)) Error("inexact division"); ZZ_pX rr, aa1, bb1; conv(rr, r); rem(aa1, rr, HH); MulMod(aa1, aa1, AA, HH); rem(bb1, rr, GG); MulMod(bb1, bb1, BB, GG); ZZX a1, b1; conv(a1, aa1); mul(a1, a1, p); add(A, a, a1); conv(b1, bb1); mul(b1, b1, p); add(B, b, b1); Gout = G; Hout = H; Aout = A; Bout = B; } static void HenselLift1(ZZX& Gout, ZZX& Hout, const ZZX& f, const ZZX& g, const ZZX& h, const ZZX& a, const ZZX& b, const ZZ& p) { ZZX c, g1, h1, G, H; mul(c, g, h); sub(c, f, c); if (!divide(c, c, p)) Error("inexact division"); ZZ_pX cc, gg, hh, aa, bb, tt, gg1, hh1; conv(cc, c); conv(gg, g); conv(hh, h); conv(aa, a); conv(bb, b); ZZ_pXModulus GG; ZZ_pXModulus HH; build(GG, gg); build(HH, hh); rem(gg1, cc, GG); MulMod(gg1, gg1, bb, GG); rem(hh1, cc, HH); MulMod(hh1, hh1, aa, HH); conv(g1, gg1); mul(g1, g1, p); add(G, g, g1); conv(h1, hh1); mul(h1, h1, p); add(H, h, h1); Gout = G; Hout = H; } static void BuildTree(vec_long& link, vec_ZZX& v, vec_ZZX& w, const vec_zz_pX& a) { long k = a.length(); if (k < 2) Error("bad arguments to BuildTree"); vec_zz_pX V, W; V.SetLength(2*k-2); W.SetLength(2*k-2); link.SetLength(2*k-2); long i, j, s; long minp, mind; for (i = 0; i < k; i++) { V[i] = a[i]; link[i] = -(i+1); } for (j = 0; j < 2*k-4; j += 2) { minp = j; mind = deg(V[j]); for (s = j+1; s < i; s++) if (deg(V[s]) < mind) { minp = s; mind = deg(V[s]); } swap(V[j], V[minp]); swap(link[j], link[minp]); minp = j+1; mind = deg(V[j+1]); for (s = j+2; s < i; s++) if (deg(V[s]) < mind) { minp = s; mind = deg(V[s]); } swap(V[j+1], V[minp]); swap(link[j+1], link[minp]); mul(V[i], V[j], V[j+1]); link[i] = j; i++; } zz_pX d; for (j = 0; j < 2*k-2; j += 2) { XGCD(d, W[j], W[j+1], V[j], V[j+1]); if (!IsOne(d)) Error("relatively prime polynomials expected"); } v.SetLength(2*k-2); for (j = 0; j < 2*k-2; j++) conv(v[j], V[j]); w.SetLength(2*k-2); for (j = 0; j < 2*k-2; j++) conv(w[j], W[j]); } static void RecTreeLift(const vec_long& link, vec_ZZX& v, vec_ZZX& w, const ZZ& p, const ZZX& f, long j, long inv) { if (j < 0) return; if (inv) HenselLift(v[j], v[j+1], w[j], w[j+1], f, v[j], v[j+1], w[j], w[j+1], p); else HenselLift1(v[j], v[j+1], f, v[j], v[j+1], w[j], w[j+1], p); RecTreeLift(link, v, w, p, v[j], link[j], inv); RecTreeLift(link, v, w, p, v[j+1], link[j+1], inv); } static void TreeLift(const vec_long& link, vec_ZZX& v, vec_ZZX& w, long e0, long e1, const ZZX& f, long inv) // lift from p^{e0} to p^{e1} { ZZ p0, p1; power(p0, zz_p::modulus(), e0); power(p1, zz_p::modulus(), e1-e0); ZZ_pBak bak; bak.save(); ZZ_p::init(p1); RecTreeLift(link, v, w, p0, f, v.length()-2, inv); bak.restore(); } void MultiLift(vec_ZZX& A, const vec_zz_pX& a, const ZZX& f, long e, long verbose) { long k = a.length(); long i; if (k < 2 || e < 1 || NTL_OVERFLOW(e, 1, 0)) Error("MultiLift: bad args"); if (!IsOne(LeadCoeff(f))) Error("MultiLift: bad args"); for (i = 0; i < a.length(); i++) if (!IsOne(LeadCoeff(a[i]))) Error("MultiLift: bad args"); if (e == 1) { A.SetLength(k); for (i = 0; i < k; i++) conv(A[i], a[i]); return; } vec_long E; append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long l = E.length(); vec_ZZX v, w; vec_long link; double t; if (verbose) { cerr << "building tree..."; t = GetTime(); } BuildTree(link, v, w, a); if (verbose) cerr << (GetTime()-t) << "\n"; for (i = l-1; i > 0; i--) { if (verbose) { cerr << "lifting to " << E[i-1] << "..."; t = GetTime(); } TreeLift(link, v, w, E[i], E[i-1], f, i != 1); if (verbose) cerr << (GetTime()-t) << "\n"; } A.SetLength(k); for (i = 0; i < 2*k-2; i++) { long t = link[i]; if (t < 0) A[-(t+1)] = v[i]; } } static void inplace_rev(ZZX& f) { long n = deg(f); long i, j; i = 0; j = n; while (i < j) { swap(f.rep[i], f.rep[j]); i++; j--; } f.normalize(); } NTL_THREAD_LOCAL long ZZXFac_InitNumPrimes = 7; NTL_THREAD_LOCAL long ZZXFac_MaxNumPrimes = 50; static void RecordPattern(vec_long& pat, vec_pair_zz_pX_long& fac) { long n = pat.length()-1; long i; for (i = 0; i <= n; i++) pat[i] = 0; long k = fac.length(); for (i = 0; i < k; i++) { long d = fac[i].b; long m = deg(fac[i].a)/d; pat[d] = m; } } static long NumFactors(const vec_long& pat) { long n = pat.length()-1; long i; long res = 0; for (i = 0; i <= n; i++) res += pat[i]; return res; } static void CalcPossibleDegrees(ZZ& pd, const vec_long& pat) { long n = pat.length()-1; set(pd); long d, j; ZZ t1; for (d = 1; d <= n; d++) for (j = 0; j < pat[d]; j++) { LeftShift(t1, pd, d); bit_or(pd, pd, t1); } } static void CalcPossibleDegrees(vec_ZZ& S, const vec_ZZ_pX& fac, long k) // S[i] = possible degrees of the product of any subset of size k // among fac[i...], encoded as a bit vector. { long r = fac.length(); S.SetLength(r); if (r == 0) return; if (k < 1 || k > r) Error("CalcPossibleDegrees: bad args"); long i, l; ZZ old, t1; set(S[r-1]); LeftShift(S[r-1], S[r-1], deg(fac[r-1])); for (i = r-2; i >= 0; i--) { set(t1); LeftShift(t1, t1, deg(fac[i])); bit_or(S[i], t1, S[i+1]); } for (l = 2; l <= k; l++) { old = S[r-l]; LeftShift(S[r-l], S[r-l+1], deg(fac[r-l])); for (i = r-l-1; i >= 0; i--) { LeftShift(t1, old, deg(fac[i])); old = S[i]; bit_or(S[i], S[i+1], t1); } } } static vec_zz_pX * SmallPrimeFactorization(LocalInfoT& LocalInfo, const ZZX& f, long verbose) { long n = deg(f); long i; double t; LocalInfo.n = n; long& NumPrimes = LocalInfo.NumPrimes; NumPrimes = 0; LocalInfo.NumFactors = 0; // some sanity checking... if (ZZXFac_InitNumPrimes < 1 || ZZXFac_InitNumPrimes > 10000) Error("bad ZZXFac_InitNumPrimes"); if (ZZXFac_MaxNumPrimes < ZZXFac_InitNumPrimes || ZZXFac_MaxNumPrimes > 10000) Error("bad ZZXFac_MaxNumPrimes"); LocalInfo.p.SetLength(ZZXFac_InitNumPrimes); LocalInfo.pattern.SetLength(ZZXFac_InitNumPrimes); // set bits 0..n of LocalInfo.PossibleDegrees SetBit(LocalInfo.PossibleDegrees, n+1); add(LocalInfo.PossibleDegrees, LocalInfo.PossibleDegrees, -1); long minr = n+1; long irred = 0; vec_pair_zz_pX_long *bestfac = 0; zz_pX *besth = 0; vec_zz_pX *spfactors = 0; zz_pContext bestp; long bestp_index; long maxroot = NextPowerOfTwo(deg(f))+1; for (; NumPrimes < ZZXFac_InitNumPrimes;) { long p = LocalInfo.s.next(); if (!p) Error("out of small primes"); if (divide(LeadCoeff(f), p)) { if (verbose) cerr << "skipping " << p << "\n"; continue; } zz_p::init(p, maxroot); zz_pX ff, ffp, d; conv(ff, f); MakeMonic(ff); diff(ffp, ff); GCD(d, ffp, ff); if (!IsOne(d)) { if (verbose) cerr << "skipping " << p << "\n"; continue; } if (verbose) { cerr << "factoring mod " << p << "..."; t = GetTime(); } vec_pair_zz_pX_long thisfac; zz_pX thish; SFCanZass1(thisfac, thish, ff, 0); LocalInfo.p[NumPrimes] = p; vec_long& pattern = LocalInfo.pattern[NumPrimes]; pattern.SetLength(n+1); RecordPattern(pattern, thisfac); long r = NumFactors(pattern); if (verbose) { cerr << (GetTime()-t) << "\n"; cerr << "degree sequence: "; for (i = 0; i <= n; i++) if (pattern[i]) { cerr << pattern[i] << "*" << i << " "; } cerr << "\n"; } if (r == 1) { irred = 1; break; } // update admissibility info ZZ pd; CalcPossibleDegrees(pd, pattern); bit_and(LocalInfo.PossibleDegrees, LocalInfo.PossibleDegrees, pd); if (weight(LocalInfo.PossibleDegrees) == 2) { irred = 1; break; } if (r < minr) { minr = r; delete bestfac; bestfac = NTL_NEW_OP vec_pair_zz_pX_long; *bestfac = thisfac; delete besth; besth = NTL_NEW_OP zz_pX; *besth = thish; bestp.save(); bestp_index = NumPrimes; } NumPrimes++; } if (!irred) { // delete best prime from LocalInfo swap(LocalInfo.pattern[bestp_index], LocalInfo.pattern[NumPrimes-1]); LocalInfo.p[bestp_index] = LocalInfo.p[NumPrimes-1]; NumPrimes--; bestp.restore(); spfactors = NTL_NEW_OP vec_zz_pX; if (verbose) { cerr << "p = " << zz_p::modulus() << ", completing factorization..."; t = GetTime(); } SFCanZass2(*spfactors, *bestfac, *besth, 0); if (verbose) { cerr << (GetTime()-t) << "\n"; } } delete bestfac; delete besth; return spfactors; } static long ConstTermTest(const vec_ZZ_pX& W, const vec_long& I, const ZZ& ct, const ZZ_p& lc, vec_ZZ_p& prod, long& ProdLen) { long k = I.length(); ZZ_p t; ZZ t1, t2; long i; if (ProdLen == 0) { mul(prod[0], lc, ConstTerm(W[I[0]])); ProdLen++; } for (i = ProdLen; i < k; i++) mul(prod[i], prod[i-1], ConstTerm(W[I[i]])); ProdLen = k-1; // should make this a routine in ZZ_p t1 = rep(prod[k-1]); RightShift(t2, ZZ_p::modulus(), 1); if (t1 > t2) sub(t1, t1, ZZ_p::modulus()); return divide(ct, t1); } static void BalCopy(ZZX& g, const ZZ_pX& G) { const ZZ& p = ZZ_p::modulus(); ZZ p2, t; RightShift(p2, p, 1); long n = G.rep.length(); long i; g.rep.SetLength(n); for (i = 0; i < n; i++) { t = rep(G.rep[i]); if (t > p2) sub(t, t, p); g.rep[i] = t; } } static void mul(ZZ_pX& g, const vec_ZZ_pX& W, const vec_long& I) { vec_ZZ_pX w; long k = I.length(); w.SetLength(k); long i; for (i = 0; i < k; i++) w[i] = W[I[i]]; mul(g, w); } static void InvMul(ZZ_pX& g, const vec_ZZ_pX& W, const vec_long& I) { vec_ZZ_pX w; long k = I.length(); long r = W.length(); w.SetLength(r-k); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else w[j-i] = W[j]; } mul(g, w); } static void RemoveFactors(vec_ZZ_pX& W, const vec_long& I) { long k = I.length(); long r = W.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } W.SetLength(r-k); } static void unpack(vec_long& x, const ZZ& a, long n) { x.SetLength(n+1); long i; for (i = 0; i <= n; i++) x[i] = bit(a, i); } static void SubPattern(vec_long& p1, const vec_long& p2) { long l = p1.length(); if (p2.length() != l) Error("SubPattern: bad args"); long i; for (i = 0; i < l; i++) { p1[i] -= p2[i]; if (p1[i] < 0) Error("SubPattern: internal error"); } } static void UpdateLocalInfo(LocalInfoT& LocalInfo, vec_ZZ& pdeg, const vec_ZZ_pX& W, const vec_ZZX& factors, const ZZX& f, long k, long verbose) { NTL_THREAD_LOCAL static long cnt = 0; if (verbose) { cnt = (cnt + 1) % 100; if (!cnt) cerr << "#"; } double t; long i, j; if (LocalInfo.NumFactors < factors.length()) { zz_pBak bak; bak.save(); vec_long pattern; pattern.SetLength(LocalInfo.n+1); ZZ pd; if (verbose) { cerr << "updating local info..."; t = GetTime(); } for (i = 0; i < LocalInfo.NumPrimes; i++) { zz_p::init(LocalInfo.p[i], NextPowerOfTwo(LocalInfo.n)+1); for (j = LocalInfo.NumFactors; j < factors.length(); j++) { vec_pair_zz_pX_long thisfac; zz_pX thish; zz_pX ff; conv(ff, factors[j]); MakeMonic(ff); SFCanZass1(thisfac, thish, ff, 0); RecordPattern(pattern, thisfac); SubPattern(LocalInfo.pattern[i], pattern); } CalcPossibleDegrees(pd, LocalInfo.pattern[i]); bit_and(LocalInfo.PossibleDegrees, LocalInfo.PossibleDegrees, pd); } bak.restore(); LocalInfo.NumFactors = factors.length(); CalcPossibleDegrees(pdeg, W, k); if (verbose) cerr << (GetTime()-t) << "\n"; } if (!ZZXFac_van_Hoeij && LocalInfo.NumPrimes + 1 < ZZXFac_MaxNumPrimes) { if (verbose) cerr << "adding a prime\n"; zz_pBak bak; bak.save(); for (;;) { long p = LocalInfo.s.next(); if (!p) Error("UpdateLocalInfo: out of primes"); if (divide(LeadCoeff(f), p)) { if (verbose) cerr << "skipping " << p << "\n"; continue; } zz_p::init(p, NextPowerOfTwo(deg(f))+1); zz_pX ff, ffp, d; conv(ff, f); MakeMonic(ff); diff(ffp, ff); GCD(d, ffp, ff); if (!IsOne(d)) { if (verbose) cerr << "skipping " << p << "\n"; continue; } vec_pair_zz_pX_long thisfac; zz_pX thish; if (verbose) { cerr << "factoring mod " << p << "..."; t = GetTime(); } SFCanZass1(thisfac, thish, ff, 0); LocalInfo.p.SetLength(LocalInfo.NumPrimes+1); LocalInfo.pattern.SetLength(LocalInfo.NumPrimes+1); LocalInfo.p[LocalInfo.NumPrimes] = p; vec_long& pattern = LocalInfo.pattern[LocalInfo.NumPrimes]; pattern.SetLength(LocalInfo.n+1); RecordPattern(pattern, thisfac); if (verbose) { cerr << (GetTime()-t) << "\n"; cerr << "degree sequence: "; for (i = 0; i <= LocalInfo.n; i++) if (pattern[i]) { cerr << pattern[i] << "*" << i << " "; } cerr << "\n"; } ZZ pd; CalcPossibleDegrees(pd, pattern); bit_and(LocalInfo.PossibleDegrees, LocalInfo.PossibleDegrees, pd); LocalInfo.NumPrimes++; break; } bak.restore(); } } const int ZZX_OVERLIFT = NTL_BITS_PER_LONG; // number of bits by which we "overlift"....this enables, in particular, // the "n-1" test. // Must lie in the range 4..NTL_BITS_PER_LONG. #define EXTRA_BITS (1) // Any small number, like 1, 2 or 3, should be OK. static void CardinalitySearch(vec_ZZX& factors, ZZX& f, vec_ZZ_pX& W, LocalInfoT& LocalInfo, long k, long bnd, long verbose) { double start_time, end_time; if (verbose) { start_time = GetTime(); cerr << "\n************ "; cerr << "start cardinality " << k << "\n"; } vec_long I, D; I.SetLength(k); D.SetLength(k); long r = W.length(); vec_ZZ_p prod; prod.SetLength(k); long ProdLen; vec_ZZ pdeg; CalcPossibleDegrees(pdeg, W, k); ZZ pd; vec_long upd; long i, state; long cnt = 0; ZZ ct; mul(ct, ConstTerm(f), LeadCoeff(f)); ZZ_p lc; conv(lc, LeadCoeff(f)); ZZ_pX gg; ZZX g, h; I[0] = 0; while (I[0] <= r-k) { bit_and(pd, pdeg[I[0]], LocalInfo.PossibleDegrees); if (IsZero(pd)) { if (verbose) cerr << "skipping\n"; goto done; } unpack(upd, pd, LocalInfo.n); D[0] = deg(W[I[0]]); i = 1; state = 0; ProdLen = 0; for (;;) { if (i < ProdLen) ProdLen = i; if (i == k) { // process indices I[0], ..., I[k-1] if (cnt > 2000000) { cnt = 0; UpdateLocalInfo(LocalInfo, pdeg, W, factors, f, k, verbose); bit_and(pd, pdeg[I[0]], LocalInfo.PossibleDegrees); if (IsZero(pd)) { if (verbose) cerr << "skipping\n"; goto done; } unpack(upd, pd, LocalInfo.n); } state = 1; // default continuation state if (!upd[D[k-1]]) { i--; cnt++; continue; } if (!ConstTermTest(W, I, ct, lc, prod, ProdLen)) { i--; cnt += 100; continue; } if (verbose) { cerr << "+"; } cnt += 1000; if (2*D[k-1] <= deg(f)) { mul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if(MaxBits(g) > bnd) { i--; continue; } if (verbose) { cerr << "*"; } PrimitivePart(g, g); if (!divide(h, f, g)) { i--; continue; } // factor found! append(factors, g); if (verbose) { cerr << "degree " << deg(g) << " factor found\n"; } f = h; mul(ct, ConstTerm(f), LeadCoeff(f)); conv(lc, LeadCoeff(f)); } else { InvMul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if(MaxBits(g) > bnd) { i--; continue; } if (verbose) { cerr << "*"; } PrimitivePart(g, g); if (!divide(h, f, g)) { i--; continue; } // factor found! append(factors, h); if (verbose) { cerr << "degree " << deg(h) << " factor found\n"; } f = g; mul(ct, ConstTerm(f), LeadCoeff(f)); conv(lc, LeadCoeff(f)); } RemoveFactors(W, I); r = W.length(); cnt = 0; if (2*k > r) goto done; else break; } else if (state == 0) { I[i] = I[i-1] + 1; D[i] = D[i-1] + deg(W[I[i]]); i++; } else { // state == 1 I[i]++; if (i == 0) break; if (I[i] > r-k+i) i--; else { D[i] = D[i-1] + deg(W[I[i]]); i++; state = 0; } } } } done: if (verbose) { end_time = GetTime(); cerr << "\n************ "; cerr << "end cardinality " << k << "\n"; cerr << "time: " << (end_time-start_time) << "\n"; } } typedef unsigned long TBL_T; #if (NTL_BITS_PER_LONG >= 64) // for 64-bit machines #define TBL_MSK (63) #define TBL_SHAMT (6) #else // for 32-bit machines #define TBL_MSK (31) #define TBL_SHAMT (5) #endif #if 0 // recursive version static void RecInitTab(TBL_T ***lookup_tab, long i, const vec_ulong& ratio, long r, long k, unsigned long thresh1, long **shamt_tab, unsigned long sum, long card, long j) { if (j >= i || card >= k-1) { if (card > 1) { long shamt = shamt_tab[i][card]; unsigned long index1 = ((-sum) >> shamt); lookup_tab[i][card][index1 >> TBL_SHAMT] |= (1UL << (index1 & TBL_MSK)); unsigned long index2 = ((-sum+thresh1) >> shamt); if (index1 != index2) lookup_tab[i][card][index2 >> TBL_SHAMT] |= (1UL << (index2 & TBL_MSK)); } return; } RecInitTab(lookup_tab, i, ratio, r, k, thresh1, shamt_tab, sum, card, j+1); RecInitTab(lookup_tab, i, ratio, r, k, thresh1, shamt_tab, sum+ratio[r-1-j], card+1, j+1); } static void DoInitTab(TBL_T ***lookup_tab, long i, const vec_ulong& ratio, long r, long k, unsigned long thresh1, long **shamt_tab) { RecInitTab(lookup_tab, i, ratio, r, k, thresh1, shamt_tab, 0, 0, 0); } #else // iterative version static void DoInitTab(TBL_T ***lookup_tab, long i, const vec_ulong& ratio, long r, long k, unsigned long thresh1, long **shamt_tab) { vec_long sum_vec, card_vec, location_vec; sum_vec.SetLength(i+1); card_vec.SetLength(i+1); location_vec.SetLength(i+1); long j = 0; sum_vec[0] = 0; card_vec[0] = 0; unsigned long sum; long card, location; location = 0; while (j >= 0) { sum = sum_vec[j]; card = card_vec[j]; switch (location) { case 0: if (j >= i || card >= k-1) { if (card > 1) { long shamt = shamt_tab[i][card]; unsigned long index1 = ((-sum) >> shamt); lookup_tab[i][card][index1 >> TBL_SHAMT] |= (1UL << (index1 & TBL_MSK)); unsigned long index2 = ((-sum+thresh1) >> shamt); if (index1 != index2) lookup_tab[i][card][index2 >> TBL_SHAMT] |= (1UL << (index2 & TBL_MSK)); } location = location_vec[j]; j--; continue; } sum_vec[j+1] = sum; card_vec[j+1] = card; location_vec[j+1] = 1; j++; location = 0; continue; case 1: sum_vec[j+1] = sum+ratio[r-1-j]; card_vec[j+1] = card+1; location_vec[j+1] = 2; j++; location = 0; continue; case 2: location = location_vec[j]; j--; continue; } } } #endif static void InitTab(TBL_T ***lookup_tab, const vec_ulong& ratio, long r, long k, unsigned long thresh1, long **shamt_tab, long pruning) { long i, j, t; if (pruning) { for (i = 2; i <= pruning; i++) { long len = min(k-1, i); for (j = 2; j <= len; j++) { long ub = (((1L << (NTL_BITS_PER_LONG-shamt_tab[i][j])) + TBL_MSK) >> TBL_SHAMT); for (t = 0; t < ub; t++) lookup_tab[i][j][t] = 0; } DoInitTab(lookup_tab, i, ratio, r, k, thresh1, shamt_tab); } } } static void RatioInit1(vec_ulong& ratio, const vec_ZZ_pX& W, const ZZ_p& lc, long pruning, TBL_T ***lookup_tab, vec_vec_ulong& pair_ratio, long k, unsigned long thresh1, long **shamt_tab) { long r = W.length(); long i, j; ZZ_p a; ZZ p; p = ZZ_p::modulus(); ZZ aa; for (i = 0; i < r; i++) { long m = deg(W[i]); mul(a, W[i].rep[m-1], lc); LeftShift(aa, rep(a), NTL_BITS_PER_LONG); div(aa, aa, p); ratio[i] = to_ulong(aa); } InitTab(lookup_tab, ratio, r, k, thresh1, shamt_tab, pruning); for (i = 0; i < r; i++) for (j = 0; j < i; j++) { mul(a, W[i].rep[deg(W[i])-1], W[j].rep[deg(W[j])-1]); mul(a, a, lc); LeftShift(aa, rep(a), NTL_BITS_PER_LONG); div(aa, aa, p); pair_ratio[i][j] = to_ulong(aa); } for (i = 0; i < r; i++) { long m = deg(W[i]); if (m >= 2) { mul(a, W[i].rep[m-2], lc); LeftShift(aa, rep(a), NTL_BITS_PER_LONG); div(aa, aa, p); pair_ratio[i][i] = to_ulong(aa); } else pair_ratio[i][i] = 0; } } static long SecondOrderTest(const vec_long& I_vec, const vec_vec_ulong& pair_ratio_vec, vec_ulong& sum_stack_vec, long& SumLen) { long k = I_vec.length(); const long *I = I_vec.elts(); unsigned long *sum_stack = sum_stack_vec.elts(); unsigned long sum, thresh1; if (SumLen == 0) { unsigned long epsilon = (1UL << (NTL_BITS_PER_LONG-ZZX_OVERLIFT)); unsigned long delta = (unsigned long) ((k*(k+1)) >> 1); unsigned long thresh = epsilon + delta; thresh1 = (epsilon << 1) + delta; sum = thresh; sum_stack[k] = thresh1; } else { sum = sum_stack[SumLen-1]; thresh1 = sum_stack[k]; } long i, j; for (i = SumLen; i < k; i++) { const unsigned long *p = pair_ratio_vec[I[i]].elts(); for (j = 0; j <= i; j++) { sum += p[I[j]]; } sum_stack[i] = sum; } SumLen = k-1; return (sum <= thresh1); } static ZZ choose_fn(long r, long k) { ZZ a, b; a = 1; b = 1; long i; for (i = 0; i < k; i++) { a *= r-i; b *= k-i; } return a/b; } static void PrintInfo(const char *s, const ZZ& a, const ZZ& b) { cerr << s << a << " / " << b << " = "; double x = to_double(a)/to_double(b); if (x == 0) cerr << "0"; else { int n; double f; f = frexp(x, &n); cerr << f << "*2^" << n; } cerr << "\n"; } static void RemoveFactors1(vec_long& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } } static void RemoveFactors1(vec_vec_long& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } for (i = 0; i < r-k; i++) RemoveFactors1(W[i], I, r); } // should this swap go in tools.h? // Maybe not...I don't want to pollute the interface too much more. static inline void swap(unsigned long& a, unsigned long& b) { unsigned long t; t = a; a = b; b = t; } static void RemoveFactors1(vec_ulong& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } } static void RemoveFactors1(vec_vec_ulong& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } for (i = 0; i < r-k; i++) RemoveFactors1(W[i], I, r); } static void RemoveFactors1(vec_ZZ_p& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } } static void SumCoeffs(ZZ& sum, const ZZX& a) { ZZ res; res = 0; long i; long n = a.rep.length(); for (i = 0; i < n; i++) res += a.rep[i]; sum = res; } static void SumCoeffs(ZZ_p& sum, const ZZ_pX& a) { ZZ_p res; res = 0; long i; long n = a.rep.length(); for (i = 0; i < n; i++) res += a.rep[i]; sum = res; } static long ConstTermTest(const vec_ZZ_p& W, const vec_long& I, const ZZ& ct, const ZZ_p& lc, vec_ZZ_p& prod, long& ProdLen) { long k = I.length(); ZZ_p t; ZZ t1, t2; long i; if (ProdLen == 0) { mul(prod[0], lc, W[I[0]]); ProdLen++; } for (i = ProdLen; i < k; i++) mul(prod[i], prod[i-1], W[I[i]]); ProdLen = k-1; // should make this a routine in ZZ_p t1 = rep(prod[k-1]); RightShift(t2, ZZ_p::modulus(), 1); if (t1 > t2) sub(t1, t1, ZZ_p::modulus()); return divide(ct, t1); } NTL_THREAD_LOCAL long ZZXFac_MaxPrune = 10; static long pruning_bnd(long r, long k) { double x = 0; long i; for (i = 0; i < k; i++) { x += log(double(r-i)/double(k-i)); } return long((x/log(2.0)) * 0.75); } static long shamt_tab_init(long pos, long card, long pruning, long thresh1_len) { double x = 1; long i; for (i = 0; i < card; i++) { x *= double(pos-i)/double(card-i); } x *= pruning; // this can be adjusted to control the density if (pos <= 6) x *= 2; // a little boost that costs very little long t = long(ceil(log(x)/log(2.0))); t = max(t, TBL_SHAMT); t = min(t, NTL_BITS_PER_LONG-thresh1_len); return NTL_BITS_PER_LONG-t; } // The following routine should only be called for k > 1, // and is only worth calling for k > 2. static void CardinalitySearch1(vec_ZZX& factors, ZZX& f, vec_ZZ_pX& W, LocalInfoT& LocalInfo, long k, long bnd, long verbose) { double start_time, end_time; if (verbose) { start_time = GetTime(); cerr << "\n************ "; cerr << "start cardinality " << k << "\n"; } if (k <= 1) Error("internal error: call CardinalitySearch"); // This test is needed to ensure correcntes of "n-2" test if (NumBits(k) > NTL_BITS_PER_LONG/2-2) Error("Cardinality Search: k too large..."); vec_ZZ pdeg; CalcPossibleDegrees(pdeg, W, k); ZZ pd; bit_and(pd, pdeg[0], LocalInfo.PossibleDegrees); if (pd == 0) { if (verbose) cerr << "skipping\n"; return; } vec_long I, D; I.SetLength(k); D.SetLength(k); long r = W.length(); long initial_r = r; vec_ulong ratio, ratio_sum; ratio.SetLength(r); ratio_sum.SetLength(k); unsigned long epsilon = (1UL << (NTL_BITS_PER_LONG-ZZX_OVERLIFT)); unsigned long delta = (unsigned long) k; unsigned long thresh = epsilon + delta; unsigned long thresh1 = (epsilon << 1) + delta; long thresh1_len = NumBits(long(thresh1)); long pruning; pruning = min(r/2, ZZXFac_MaxPrune); pruning = min(pruning, pruning_bnd(r, k)); pruning = min(pruning, NTL_BITS_PER_LONG-EXTRA_BITS-thresh1_len); if (pruning <= 4) pruning = 0; long init_pruning = pruning; TBL_T ***lookup_tab = 0; long **shamt_tab = 0; if (pruning) { typedef long *long_p; long i, j; shamt_tab = NTL_NEW_OP long_p[pruning+1]; if (!shamt_tab) Error("out of mem"); shamt_tab[0] = shamt_tab[1] = 0; for (i = 2; i <= pruning; i++) { long len = min(k-1, i); shamt_tab[i] = NTL_NEW_OP long[len+1]; if (!shamt_tab[i]) Error("out of mem"); shamt_tab[i][0] = shamt_tab[i][1] = 0; for (j = 2; j <= len; j++) shamt_tab[i][j] = shamt_tab_init(i, j, pruning, thresh1_len); } typedef TBL_T *TBL_T_p; typedef TBL_T **TBL_T_pp; lookup_tab = NTL_NEW_OP TBL_T_pp[pruning+1]; if (!lookup_tab) Error("out of mem"); lookup_tab[0] = lookup_tab[1] = 0; for (i = 2; i <= pruning; i++) { long len = min(k-1, i); lookup_tab[i] = NTL_NEW_OP TBL_T_p[len+1]; if (!lookup_tab[i]) Error("out of mem"); lookup_tab[i][0] = lookup_tab[i][1] = 0; for (j = 2; j <= len; j++) { lookup_tab[i][j] = NTL_NEW_OP TBL_T[((1L << (NTL_BITS_PER_LONG-shamt_tab[i][j]))+TBL_MSK) >> TBL_SHAMT]; if (!lookup_tab[i][j]) Error("out of mem"); } } } if (verbose) { cerr << "pruning = " << pruning << "\n"; } vec_ZZ_p prod; prod.SetLength(k); long ProdLen; vec_ZZ_p prod1; prod1.SetLength(k); long ProdLen1; vec_ulong sum_stack; sum_stack.SetLength(k+1); long SumLen; vec_long upd; long i, state; long cnt = 0; ZZ ct; mul(ct, ConstTerm(f), LeadCoeff(f)); ZZ_p lc; conv(lc, LeadCoeff(f)); vec_vec_ulong pair_ratio; pair_ratio.SetLength(r); for (i = 0; i < r; i++) pair_ratio[i].SetLength(r); RatioInit1(ratio, W, lc, pruning, lookup_tab, pair_ratio, k, thresh1, shamt_tab); ZZ c1; SumCoeffs(c1, f); mul(c1, c1, LeadCoeff(f)); vec_ZZ_p sum_coeffs; sum_coeffs.SetLength(r); for (i = 0; i < r; i++) SumCoeffs(sum_coeffs[i], W[i]); vec_long degv; degv.SetLength(r); for (i = 0; i < r; i++) degv[i] = deg(W[i]); ZZ_pX gg; ZZX g, h; I[0] = 0; long loop_cnt = 0, degree_cnt = 0, n2_cnt = 0, sl_cnt = 0, ct_cnt = 0, pl_cnt = 0, c1_cnt = 0, pl1_cnt = 0, td_cnt = 0; ZZ loop_total, degree_total, n2_total, sl_total, ct_total, pl_total, c1_total, pl1_total, td_total; while (I[0] <= r-k) { bit_and(pd, pdeg[I[0]], LocalInfo.PossibleDegrees); if (IsZero(pd)) { if (verbose) cerr << "skipping\n"; goto done; } unpack(upd, pd, LocalInfo.n); D[0] = degv[I[0]]; ratio_sum[0] = ratio[I[0]] + thresh; i = 1; state = 0; ProdLen = 0; ProdLen1 = 0; SumLen = 0; for (;;) { cnt++; if (cnt > 2000000) { if (verbose) { loop_total += loop_cnt; loop_cnt = 0; degree_total += degree_cnt; degree_cnt = 0; n2_total += n2_cnt; n2_cnt = 0; sl_total += sl_cnt; sl_cnt = 0; ct_total += ct_cnt; ct_cnt = 0; pl_total += pl_cnt; pl_cnt = 0; c1_total += c1_cnt; c1_cnt = 0; pl1_total += pl1_cnt; pl1_cnt = 0; td_total += td_cnt; td_cnt = 0; } cnt = 0; UpdateLocalInfo(LocalInfo, pdeg, W, factors, f, k, verbose); bit_and(pd, pdeg[I[0]], LocalInfo.PossibleDegrees); if (IsZero(pd)) { if (verbose) cerr << "skipping\n"; goto done; } unpack(upd, pd, LocalInfo.n); } if (i == k-1) { unsigned long ratio_sum_last = ratio_sum[k-2]; long I_last = I[k-2]; { long D_last = D[k-2]; unsigned long rs; long I_this; long D_this; for (I_this = I_last+1; I_this < r; I_this++) { loop_cnt++; rs = ratio_sum_last + ratio[I_this]; if (rs > thresh1) { cnt++; continue; } degree_cnt++; D_this = D_last + degv[I_this]; if (!upd[D_this]) { cnt++; continue; } n2_cnt++; sl_cnt += (k-SumLen); I[k-1] = I_this; if (!SecondOrderTest(I, pair_ratio, sum_stack, SumLen)) { cnt += 2; continue; } c1_cnt++; pl1_cnt += (k-ProdLen1); if (!ConstTermTest(sum_coeffs, I, c1, lc, prod1, ProdLen1)) { cnt += 100; continue; } ct_cnt++; pl_cnt += (k-ProdLen); D[k-1] = D_this; if (!ConstTermTest(W, I, ct, lc, prod, ProdLen)) { cnt += 100; continue; } td_cnt++; if (verbose) { cerr << "+"; } cnt += 1000; if (2*D[k-1] <= deg(f)) { mul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if(MaxBits(g) > bnd) { continue; } if (verbose) { cerr << "*"; } PrimitivePart(g, g); if (!divide(h, f, g)) { continue; } // factor found! append(factors, g); if (verbose) { cerr << "degree " << deg(g) << " factor found\n"; } f = h; mul(ct, ConstTerm(f), LeadCoeff(f)); conv(lc, LeadCoeff(f)); } else { InvMul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if(MaxBits(g) > bnd) { continue; } if (verbose) { cerr << "*"; } PrimitivePart(g, g); if (!divide(h, f, g)) { continue; } // factor found! append(factors, h); if (verbose) { cerr << "degree " << deg(h) << " factor found\n"; } f = g; mul(ct, ConstTerm(f), LeadCoeff(f)); conv(lc, LeadCoeff(f)); } RemoveFactors(W, I); RemoveFactors1(degv, I, r); RemoveFactors1(sum_coeffs, I, r); RemoveFactors1(ratio, I, r); RemoveFactors1(pair_ratio, I, r); r = W.length(); cnt = 0; pruning = min(pruning, r/2); if (pruning <= 4) pruning = 0; InitTab(lookup_tab, ratio, r, k, thresh1, shamt_tab, pruning); if (2*k > r) goto done; else goto restart; } /* end of inner for loop */ } i--; state = 1; } else { if (state == 0) { long I_i = I[i-1] + 1; I[i] = I_i; long pruned; if (pruning && r-I_i <= pruning) { long pos = r-I_i; unsigned long rs = ratio_sum[i-1]; unsigned long index1 = (rs >> shamt_tab[pos][k-i]); if (lookup_tab[pos][k-i][index1 >> TBL_SHAMT] & (1UL << (index1&TBL_MSK))) pruned = 0; else pruned = 1; } else pruned = 0; if (pruned) { i--; state = 1; } else { D[i] = D[i-1] + degv[I_i]; ratio_sum[i] = ratio_sum[i-1] + ratio[I_i]; i++; } } else { // state == 1 loop_cnt++; if (i < ProdLen) ProdLen = i; if (i < ProdLen1) ProdLen1 = i; if (i < SumLen) SumLen = i; long I_i = (++I[i]); if (i == 0) break; if (I_i > r-k+i) { i--; } else { long pruned; if (pruning && r-I_i <= pruning) { long pos = r-I_i; unsigned long rs = ratio_sum[i-1]; unsigned long index1 = (rs >> shamt_tab[pos][k-i]); if (lookup_tab[pos][k-i][index1 >> TBL_SHAMT] & (1UL << (index1&TBL_MSK))) pruned = 0; else pruned = 1; } else pruned = 0; if (pruned) { i--; } else { D[i] = D[i-1] + degv[I_i]; ratio_sum[i] = ratio_sum[i-1] + ratio[I_i]; i++; state = 0; } } } } } restart: ; } done: if (lookup_tab) { long i, j; for (i = 2; i <= init_pruning; i++) { long len = min(k-1, i); for (j = 2; j <= len; j++) { delete [] lookup_tab[i][j]; } delete [] lookup_tab[i]; } delete [] lookup_tab; } if (shamt_tab) { long i; for (i = 2; i <= init_pruning; i++) { delete [] shamt_tab[i]; } delete [] shamt_tab; } if (verbose) { end_time = GetTime(); cerr << "\n************ "; cerr << "end cardinality " << k << "\n"; cerr << "time: " << (end_time-start_time) << "\n"; ZZ loops_max = choose_fn(initial_r+1, k); ZZ tuples_max = choose_fn(initial_r, k); loop_total += loop_cnt; degree_total += degree_cnt; n2_total += n2_cnt; sl_total += sl_cnt; ct_total += ct_cnt; pl_total += pl_cnt; c1_total += c1_cnt; pl1_total += pl1_cnt; td_total += td_cnt; cerr << "\n"; PrintInfo("loops: ", loop_total, loops_max); PrintInfo("degree tests: ", degree_total, tuples_max); PrintInfo("n-2 tests: ", n2_total, tuples_max); cerr << "ave sum len: "; if (n2_total == 0) cerr << "--"; else cerr << (to_double(sl_total)/to_double(n2_total)); cerr << "\n"; PrintInfo("f(1) tests: ", c1_total, tuples_max); cerr << "ave prod len: "; if (c1_total == 0) cerr << "--"; else cerr << (to_double(pl1_total)/to_double(c1_total)); cerr << "\n"; PrintInfo("f(0) tests: ", ct_total, tuples_max); cerr << "ave prod len: "; if (ct_total == 0) cerr << "--"; else cerr << (to_double(pl_total)/to_double(ct_total)); cerr << "\n"; PrintInfo("trial divs: ", td_total, tuples_max); } } static void FindTrueFactors(vec_ZZX& factors, const ZZX& ff, const vec_ZZX& w, const ZZ& P, LocalInfoT& LocalInfo, long verbose, long bnd) { ZZ_pBak bak; bak.save(); ZZ_p::init(P); long r = w.length(); vec_ZZ_pX W; W.SetLength(r); long i; for (i = 0; i < r; i++) conv(W[i], w[i]); ZZX f; f = ff; long k; k = 1; factors.SetLength(0); while (2*k <= W.length()) { if (k <= 1) CardinalitySearch(factors, f, W, LocalInfo, k, bnd, verbose); else CardinalitySearch1(factors, f, W, LocalInfo, k, bnd, verbose); k++; } append(factors, f); bak.restore(); } /**********************************************************************\ van Hoeij's algorithm \**********************************************************************/ const long van_hoeij_size_thresh = 12; // Use van Hoeij's algorithm if number of modular factors exceeds this bound. // Must be >= 1. const long van_hoeij_card_thresh = 3; // Switch to knapsack method if cardinality of candidate factors // exceeds this bound. // Must be >= 1. // This routine assumes that the input f is a non-zero polynomial // of degree n, and returns the value f(a). static ZZ PolyEval(const ZZX& f, const ZZ& a) { if (f == 0) Error("PolyEval: internal error"); long n = deg(f); ZZ acc, t1, t2; long i; acc = f.rep[n]; for (i = n-1; i >= 0; i--) { mul(t1, acc, a); add(acc, t1, f.rep[i]); } return acc; } // This routine assumes that the input f is a polynomial with non-zero constant // term, of degree n, and with leading coefficient c; it returns // an upper bound on the absolute value of the roots of the // monic, integer polynomial g(X) = c^{n-1} f(X/c). static ZZ RootBound(const ZZX& f) { if (ConstTerm(f) == 0) Error("RootBound: internal error"); long n = deg(f); ZZX g; long i; g = f; if (g.rep[n] < 0) negate(g.rep[n], g.rep[n]); for (i = 0; i < n; i++) { if (g.rep[i] > 0) negate(g.rep[i], g.rep[i]); } ZZ lb, ub, mb; lb = 0; ub = 1; while (PolyEval(g, ub) < 0) { ub = 2*ub; } // lb < root <= ub while (ub - lb > 1) { ZZ mb = (ub + lb)/2; if (PolyEval(g, mb) < 0) lb = mb; else ub = mb; } return ub*g.rep[n]; } // This routine takes as input an n x m integer matrix M, where the rows of M // are assumed to be linearly independent. // It is also required that both n and m are non-zero. // It computes an integer d, along with an n x m matrix R, such that // R*d^{-1} is the reduced row echelon form of M. // The routine is probabilistic: the output is always correct, but the // routine may abort the program with negligible probability // (specifically, if GenPrime returns a composite, and the modular // gauss routine can't invert a non-zero element). static void gauss(ZZ& d_out, mat_ZZ& R_out, const mat_ZZ& M) { long n = M.NumRows(); long m = M.NumCols(); if (n == 0 || m == 0) Error("gauss: internal error"); zz_pBak bak; bak.save(); for (;;) { long p = GenPrime_long(NTL_SP_NBITS); zz_p::init(p); mat_zz_p MM; conv(MM, M); long r = gauss(MM); if (r < n) continue; // compute pos(1..n), so that pos(i) is the index // of the i-th pivot column vec_long pos; pos.SetLength(n); long i, j; for (i = j = 1; i <= n; i++) { while (MM(i, j) == 0) j++; pos(i) = j; j++; } // compute the n x n sub-matrix consisting of the // pivot columns of M mat_ZZ S; S.SetDims(n, n); for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) S(i, j) = M(i, pos(j)); mat_ZZ S_inv; ZZ d; inv(d, S_inv, S); if (d == 0) continue; mat_ZZ R; mul(R, S_inv, M); // now check that R is of the right form, which it will be // if we were not unlucky long OK = 1; for (i = 1; i <= n && OK; i++) { for (j = 1; j < pos(i) && OK; j++) if (R(i, j) != 0) OK = 0; if (R(i, pos(i)) != d) OK = 0; for (j = 1; j < i && OK; j++) if (R(j, pos(i)) != 0) OK = 0; } if (!OK) continue; d_out = d; R_out = R; break; } } // The input polynomial f should be monic, and deg(f) > 0. // The input P should be > 1. // Tr.length() >= d, and Tr(i), for i = 1..d-1, should be the // Tr_i(f) mod P (in van Hoeij's notation). // The quantity Tr_d(f) mod P is computed, and stored in Tr(d). void ComputeTrace(vec_ZZ& Tr, const ZZX& f, long d, const ZZ& P) { long n = deg(f); // check arguments if (n <= 0 || LeadCoeff(f) != 1) Error("ComputeTrace: internal error (1)"); if (d <= 0) Error("ComputeTrace: internal error (2)"); if (Tr.length() < d) Error("ComputeTrace: internal error (3)"); if (P <= 1) Error("ComputeTrace: internal error (4)"); // treat d > deg(f) separately if (d > n) { ZZ t1, t2; long i; t1 = 0; for (i = 1; i <= n; i++) { mul(t2, Tr(i + d - n - 1), f.rep[i-1]); add(t1, t1, t2); } rem(t1, t1, P); NegateMod(t1, t1, P); Tr(d) = t1; } else { ZZ t1, t2; long i; mul(t1, f.rep[n-d], d); for (i = 1; i < d; i++) { mul(t2, Tr(i), f.rep[n-d+i]); add(t1, t1, t2); } rem(t1, t1, P); NegateMod(t1, t1, P); Tr(d) = t1; } } // Tr(1..d) are traces as computed above. // C and pb have length at least d. // For i = 1..d, pb(i) = p^{a_i} for a_i > 0. // pdelta = p^delta for delta > 0. // P = p^a for some a >= max{ a_i : i=1..d }. // This routine computes C(1..d), where // C(i) = C_{a_i}^{a_i + delta}( Tr(i)*lc^i ) for i = 1..d. void ChopTraces(vec_ZZ& C, const vec_ZZ& Tr, long d, const vec_ZZ& pb, const ZZ& pdelta, const ZZ& P, const ZZ& lc) { if (d <= 0) Error("ChopTraces: internal error (1)"); if (C.length() < d) Error("ChopTraces: internal error (2)"); if (Tr.length() < d) Error("ChopTraces: internal error (3)"); if (pb.length() < d) Error("ChopTraces: internal error (4)"); if (P <= 1) Error("ChopTraces: internal error (5)"); ZZ lcpow, lcred; lcpow = 1; rem(lcred, lc, P); ZZ pdelta_2; RightShift(pdelta_2, pdelta, 1); ZZ t1, t2; long i; for (i = 1; i <= d; i++) { MulMod(lcpow, lcpow, lcred, P); MulMod(t1, lcpow, Tr(i), P); RightShift(t2, pb(i), 1); add(t1, t1, t2); div(t1, t1, pb(i)); rem(t1, t1, pdelta); if (t1 > pdelta_2) sub(t1, t1, pdelta); C(i) = t1; } } // Similar to above, but computes a linear combination of traces. static void DenseChopTraces(vec_ZZ& C, const vec_ZZ& Tr, long d, long d1, const ZZ& pb_eff, const ZZ& pdelta, const ZZ& P, const ZZ& lc, const mat_ZZ& A) { ZZ pdelta_2; RightShift(pdelta_2, pdelta, 1); ZZ pb_eff_2; RightShift(pb_eff_2, pb_eff, 1); ZZ acc, t1, t2; long i, j; ZZ lcpow, lcred; rem(lcred, lc, P); for (i = 1; i <= d1; i++) { lcpow = 1; acc = 0; for (j = 1; j <= d; j++) { MulMod(lcpow, lcpow, lcred, P); MulMod(t1, lcpow, Tr(j), P); rem(t2, A(i, j), P); MulMod(t1, t1, t2, P); AddMod(acc, acc, t1, P); } t1 = acc; add(t1, t1, pb_eff_2); div(t1, t1, pb_eff); rem(t1, t1, pdelta); if (t1 > pdelta_2) sub(t1, t1, pdelta); C(i) = t1; } } static void Compute_pb(vec_long& b,vec_ZZ& pb, long p, long d, const ZZ& root_bound, long n) { ZZ t1, t2; long i; t1 = 2*power(root_bound, d)*n; if (d == 1) { i = 0; t2 = 1; } else { i = b(d-1); t2 = pb(d-1); } while (t2 <= t1) { i++; t2 *= p; } b.SetLength(d); b(d) = i; pb.SetLength(d); pb(d) = t2; } static void Compute_pdelta(long& delta, ZZ& pdelta, long p, long bit_delta) { ZZ t1; long i; i = delta; t1 = pdelta; while (NumBits(t1) <= bit_delta) { i++; t1 *= p; } delta = i; pdelta = t1; } static void BuildReductionMatrix(mat_ZZ& M, long& C, long r, long d, const ZZ& pdelta, const vec_vec_ZZ& chop_vec, const mat_ZZ& B_L, long verbose) { long s = B_L.NumRows(); C = long( sqrt(double(d) * double(r)) / 2.0 ) + 1; M.SetDims(s+d, r+d); clear(M); long i, j, k; ZZ t1, t2; for (i = 1; i <= s; i++) for (j = 1; j <= r; j++) mul(M(i, j), B_L(i, j), C); ZZ pdelta_2; RightShift(pdelta_2, pdelta, 1); long maxbits = 0; for (i = 1; i <= s; i++) for (j = 1; j <= d; j++) { t1 = 0; for (k = 1; k <= r; k++) { mul(t2, B_L(i, k), chop_vec(k)(j)); add(t1, t1, t2); } rem(t1, t1, pdelta); if (t1 > pdelta_2) sub(t1, t1, pdelta); maxbits = max(maxbits, NumBits(t1)); M(i, j+r) = t1; } for (i = 1; i <= d; i++) M(i+s, i+r) = pdelta; if (verbose) cerr << "ratio = " << double(maxbits)/double(NumBits(pdelta)) << "; "; } static void CutAway(mat_ZZ& B1, vec_ZZ& D, mat_ZZ& M, long C, long r, long d) { long k = M.NumRows(); ZZ bnd = 4*to_ZZ(C)*to_ZZ(C)*to_ZZ(r) + to_ZZ(d)*to_ZZ(r)*to_ZZ(r); while (k >= 1 && 4*D[k] > bnd*D[k-1]) k--; mat_ZZ B2; B2.SetDims(k, r); long i, j; for (i = 1; i <= k; i++) for (j = 1; j <= r; j++) div(B2(i, j), M(i, j), C); M.kill(); // save space D.kill(); ZZ det2; long rnk; rnk = image(det2, B2); B1.SetDims(rnk, r); for (i = 1; i <= rnk; i++) for (j = 1; j <= r; j++) B1(i, j) = B2(i + k - rnk, j); } static long GotThem(vec_ZZX& factors, const mat_ZZ& B_L, const vec_ZZ_pX& W, const ZZX& f, long bnd, long verbose) { double tt0, tt1; ZZ det; mat_ZZ R; long s, r; long i, j, cnt; if (verbose) { cerr << " checking A (s = " << B_L.NumRows() << "): gauss..."; } tt0 = GetTime(); gauss(det, R, B_L); tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "; "; // check if condition A holds s = B_L.NumRows(); r = B_L.NumCols(); for (j = 0; j < r; j++) { cnt = 0; for (i = 0; i < s; i++) { if (R[i][j] == 0) continue; if (R[i][j] != det) { if (verbose) cerr << "failed.\n"; return 0; } cnt++; } if (cnt != 1) { if (verbose) cerr << "failed.\n"; return 0; } } if (verbose) { cerr << "passed.\n"; cerr << " checking B..."; } // extract relevant information from R vec_vec_long I_vec; I_vec.SetLength(s); vec_long deg_vec; deg_vec.SetLength(s); for (i = 0; i < s; i++) { long dg = 0; for (j = 0; j < r; j++) { if (R[i][j] != 0) append(I_vec[i], j); dg += deg(W[j]); } deg_vec[i] = dg; } R.kill(); // save space // check if any candidate factor is the product of too few // modular factors for (i = 0; i < s; i++) if (I_vec[i].length() <= van_hoeij_card_thresh) { if (verbose) cerr << "X\n"; return 0; } if (verbose) cerr << "1"; // sort deg_vec, I_vec in order of increasing degree for (i = 0; i < s-1; i++) for (j = 0; j < s-1-i; j++) if (deg_vec[j] > deg_vec[j+1]) { swap(deg_vec[j], deg_vec[j+1]); swap(I_vec[j], I_vec[j+1]); } // perform constant term tests ZZ ct; mul(ct, LeadCoeff(f), ConstTerm(f)); ZZ half_P; RightShift(half_P, ZZ_p::modulus(), 1); ZZ_p lc, prod; conv(lc, LeadCoeff(f)); ZZ t1; for (i = 0; i < s; i++) { vec_long& I = I_vec[i]; prod = lc; for (j = 0; j < I.length(); j++) mul(prod, prod, ConstTerm(W[I[j]])); t1 = rep(prod); if (t1 > half_P) sub(t1, t1, ZZ_p::modulus()); if (!divide(ct, t1)) { if (verbose) cerr << "X\n"; return 0; } } if (verbose) cerr << "2"; // multiply out polynomials and perform size tests vec_ZZX fac; ZZ_pX gg; ZZX g; for (i = 0; i < s-1; i++) { vec_long& I = I_vec[i]; mul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if (MaxBits(g) > bnd) { if (verbose) cerr << "X\n"; return 0; } PrimitivePart(g, g); append(fac, g); } if (verbose) cerr << "3"; // finally...trial division ZZX f1 = f; ZZX h; for (i = 0; i < s-1; i++) { if (!divide(h, f1, fac[i])) { cerr << "X\n"; return 0; } f1 = h; } // got them! if (verbose) cerr << "$\n"; append(factors, fac); append(factors, f1); return 1; } void AdditionalLifting(ZZ& P1, long& e1, vec_ZZX& w1, long p, long new_bound, const ZZX& f, long doubling, long verbose) { long new_e1; if (doubling) new_e1 = max(2*e1, new_bound); // at least double e1 else new_e1 = new_bound; if (verbose) { cerr << ">>> additional hensel lifting to " << new_e1 << "...\n"; } ZZ new_P1; power(new_P1, p, new_e1); ZZX f1; ZZ t1, t2; long i; long n = deg(f); if (LeadCoeff(f) == 1) f1 = f; else if (LeadCoeff(f) == -1) negate(f1, f); else { rem(t1, LeadCoeff(f), new_P1); InvMod(t1, t1, new_P1); f1.rep.SetLength(n+1); for (i = 0; i <= n; i++) { mul(t2, f.rep[i], t1); rem(f1.rep[i], t2, new_P1); } } zz_pBak bak; bak.save(); zz_p::init(p, NextPowerOfTwo(n)+1); long r = w1.length(); vec_zz_pX ww1; ww1.SetLength(r); for (i = 0; i < r; i++) conv(ww1[i], w1[i]); w1.kill(); double tt0, tt1; tt0 = GetTime(); MultiLift(w1, ww1, f1, new_e1, verbose); tt1 = GetTime(); if (verbose) { cerr << "lifting time: " << (tt1-tt0) << "\n\n"; } P1 = new_P1; e1 = new_e1; bak.restore(); } static void Compute_pb_eff(long& b_eff, ZZ& pb_eff, long p, long d, const ZZ& root_bound, long n, long ran_bits) { ZZ t1, t2; long i; if (root_bound == 1) t1 = (to_ZZ(d)*to_ZZ(n)) << (ran_bits + 1); else t1 = (power(root_bound, d)*n) << (ran_bits + 2); i = 0; t2 = 1; while (t2 <= t1) { i++; t2 *= p; } b_eff = i; pb_eff = t2; } static long d1_val(long bit_delta, long r, long s) { return long( 0.30*double(r)*double(s)/double(bit_delta) ) + 1; } // Next comes van Hoeij's algorithm itself. // Some notation that differs from van Hoeij's paper: // n = deg(f) // r = # modular factors // s = dim(B_L) (gets smaller over time) // d = # traces used // d1 = number of "compressed" traces // // The algorithm starts with a "sparse" version of van Hoeij, so that // at first the traces d = 1, 2, ... are used in conjunction with // a d x d identity matrix for van Hoeij's matrix A. // The number of "excess" bits used for each trace, bit_delta, is initially // 2*r. // // When d*bit_delta exceeds 0.25*r*s, we switch to // a "dense" mode, where we use only about 0.25*r*s "compressed" traces. // These bounds follow from van Hoeij's heuristic estimates. // // In sparse mode, d and bit_delta increase exponentially (but gently). // In dense mode, but d increases somewhat more aggressively, // and bit_delta is increased more gently. static void FindTrueFactors_vH(vec_ZZX& factors, const ZZX& ff, const vec_ZZX& w, const ZZ& P, long p, long e, LocalInfoT& LocalInfo, long verbose, long bnd) { const long SkipSparse = 0; ZZ_pBak bak; bak.save(); ZZ_p::init(P); long r = w.length(); vec_ZZ_pX W; W.SetLength(r); long i, j; for (i = 0; i < r; i++) conv(W[i], w[i]); ZZX f; f = ff; long k; k = 1; factors.SetLength(0); while (2*k <= W.length() && (k <= van_hoeij_card_thresh || W.length() <= van_hoeij_size_thresh)) { if (k <= 1) CardinalitySearch(factors, f, W, LocalInfo, k, bnd, verbose); else CardinalitySearch1(factors, f, W, LocalInfo, k, bnd, verbose); k++; } if (2*k > W.length()) { // rest is irreducible, so we're done append(factors, f); } else { // now we apply van Hoeij's algorithm proper to f double time_start, time_stop, lll_time, tt0, tt1; time_start = GetTime(); lll_time = 0; if (verbose) { cerr << "\n\n*** starting knapsack procedure\n"; } ZZ P1 = P; long e1 = e; // invariant: P1 = p^{e1} r = W.length(); vec_ZZX w1; w1.SetLength(r); for (i = 0; i < r; i++) conv(w1[i], W[i]); long n = deg(f); mat_ZZ B_L; // van Hoeij's lattice ident(B_L, r); long d = 0; // number of traces long bit_delta = 0; // number of "excess" bits vec_long b; vec_ZZ pb; // pb(i) = p^{b(i)} long delta = 0; ZZ pdelta = to_ZZ(1); // pdelta = p^delta pdelta = 1; vec_vec_ZZ trace_vec; trace_vec.SetLength(r); vec_vec_ZZ chop_vec; chop_vec.SetLength(r); ZZ root_bound = RootBound(f); if (verbose) { cerr << "NumBits(root_bound) = " << NumBits(root_bound) << "\n"; } long dense = 0; long ran_bits = 32; long loop_cnt = 0; long s = r; for (;;) { loop_cnt++; // if we are using the power hack, then we do not try too hard... // this is really a hack on a hack! if (ok_to_abandon && ((d >= 2 && s > 128) || (d >= 3 && s > 32) || (d >= 4 && s > 8) || d >= 5) ) { if (verbose) cerr << " abandoning\n"; append(factors, f); break; } long d_last, d_inc, d_index; d_last = d; // set d_inc: if (!dense) { d_inc = 1 + d/8; } else { d_inc = 1 + d/4; } d_inc = min(d_inc, n-1-d); d += d_inc; // set bit_delta: if (bit_delta == 0) { // set initial value...don't make it any smaller than 2*r bit_delta = 2*r; } else { long extra_bits; if (!dense) { extra_bits = 1 + bit_delta/8; } else if (d_inc != 0) { if (d1_val(bit_delta, r, s) > 1) extra_bits = 1 + bit_delta/16; else extra_bits = 0; } else extra_bits = 1 + bit_delta/8; bit_delta += extra_bits; } if (d > d1_val(bit_delta, r, s)) dense = 1; Compute_pdelta(delta, pdelta, p, bit_delta); long d1; long b_eff; ZZ pb_eff; if (!dense) { for (d_index = d_last + 1; d_index <= d; d_index++) Compute_pb(b, pb, p, d_index, root_bound, n); d1 = d; b_eff = b(d); pb_eff = pb(d); } else { d1 = d1_val(bit_delta, r, s); Compute_pb_eff(b_eff, pb_eff, p, d, root_bound, n, ran_bits); } if (verbose) { cerr << "*** d = " << d << "; s = " << s << "; delta = " << delta << "; b_eff = " << b_eff; if (dense) cerr << "; dense [" << d1 << "]"; cerr << "\n"; } if (b_eff + delta > e1) { long doubling; doubling = 1; AdditionalLifting(P1, e1, w1, p, b_eff + delta, f, doubling, verbose); if (verbose) { cerr << ">>> recomputing traces..."; } tt0 = GetTime(); trace_vec.kill(); trace_vec.SetLength(r); for (i = 0; i < r; i++) { trace_vec[i].SetLength(d_last); for (d_index = 1; d_index <= d_last; d_index++) { ComputeTrace(trace_vec[i], w1[i], d_index, P1); } } tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "\n"; } if (verbose) cerr << " trace..."; tt0 = GetTime(); mat_ZZ A; if (dense) { A.SetDims(d1, d); for (i = 1; i <= d1; i++) for (j = 1; j <= d; j++) { RandomBits(A(i, j), ran_bits); if (RandomBnd(2)) negate(A(i, j), A(i, j)); } } for (i = 0; i < r; i++) { trace_vec[i].SetLength(d); for (d_index = d_last + 1; d_index <= d; d_index++) ComputeTrace(trace_vec[i], w1[i], d_index, P1); chop_vec[i].SetLength(d1); if (!dense) ChopTraces(chop_vec[i], trace_vec[i], d, pb, pdelta, P1, LeadCoeff(f)); else DenseChopTraces(chop_vec[i], trace_vec[i], d, d1, pb_eff, pdelta, P1, LeadCoeff(f), A); } A.kill(); tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "\n"; mat_ZZ M; long C; if (verbose) cerr << " building matrix..."; tt0 = GetTime(); BuildReductionMatrix(M, C, r, d1, pdelta, chop_vec, B_L, verbose); tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "\n"; if (SkipSparse) { if (!dense) { if (verbose) cerr << "skipping LLL\n"; continue; } } if (verbose) cerr << " LLL..."; tt0 = GetTime(); vec_ZZ D; long rnk = LLL_plus(D, M); tt1 = GetTime(); lll_time += (tt1-tt0); if (verbose) cerr << (tt1-tt0) << "\n"; if (rnk != s + d1) { Error("van Hoeij -- bad rank"); } mat_ZZ B1; if (verbose) cerr << " CutAway..."; tt0 = GetTime(); CutAway(B1, D, M, C, r, d1); tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "\n"; if (B1.NumRows() >= s) continue; // no progress...try again // otherwise, update B_L and test if we are done swap(B1, B_L); B1.kill(); s = B_L.NumRows(); if (s == 0) Error("oops! s == 0 should not happen!"); if (s == 1) { if (verbose) cerr << " irreducible!\n"; append(factors, f); break; } if (s > r / (van_hoeij_card_thresh + 1)) continue; // dimension too high...we can't be done if (GotThem(factors, B_L, W, f, bnd, verbose)) break; } time_stop = GetTime(); if (verbose) { cerr << "*** knapsack finished: total time = " << (time_stop - time_start) << "; LLL time = " << lll_time << "\n"; } } bak.restore(); } static void ll_SFFactor(vec_ZZX& factors, const ZZX& ff, long verbose, long bnd) // input is primitive and square-free, with positive leading // coefficient { if (deg(ff) <= 1) { factors.SetLength(1); factors[0] = ff; if (verbose) { cerr << "*** SFFactor, trivial case 1.\n"; } return; } // remove a factor of X, if necessary ZZX f; long xfac; long rev; double t; if (IsZero(ConstTerm(ff))) { RightShift(f, ff, 1); xfac = 1; } else { f = ff; xfac = 0; } // return a factor of X-1 if necessary long x1fac = 0; ZZ c1; SumCoeffs(c1, f); if (c1 == 0) { x1fac = 1; div(f, f, ZZX(1,1) - 1); } SumCoeffs(c1, f); if (deg(f) <= 1) { long r = 0; factors.SetLength(0); if (deg(f) > 0) { factors.SetLength(r+1); factors[r] = f; r++; } if (xfac) { factors.SetLength(r+1); SetX(factors[r]); r++; } if (x1fac) { factors.SetLength(r+1); factors[r] = ZZX(1,1) - 1; r++; } if (verbose) { cerr << "*** SFFactor: trivial case 2.\n"; } return; } if (verbose) { cerr << "*** start SFFactor.\n"; } // reverse f if this makes lead coefficient smaller ZZ t1, t2; abs(t1, LeadCoeff(f)); abs(t2, ConstTerm(f)); if (t1 > t2) { inplace_rev(f); rev = 1; } else rev = 0; // obtain factorization modulo small primes if (verbose) { cerr << "factorization modulo small primes...\n"; t = GetTime(); } LocalInfoT LocalInfo; zz_pBak bak; bak.save(); vec_zz_pX *spfactors = SmallPrimeFactorization(LocalInfo, f, verbose); if (!spfactors) { // f was found to be irreducible bak.restore(); if (verbose) { t = GetTime()-t; cerr << "small prime time: " << t << ", irreducible.\n"; } if (rev) inplace_rev(f); long r = 0; factors.SetLength(r+1); factors[r] = f; r++; if (xfac) { factors.SetLength(r+1); SetX(factors[r]); r++; } if (x1fac) { factors.SetLength(r+1); factors[r] = ZZX(1,1) - 1; r++; } return; } if (verbose) { t = GetTime()-t; cerr << "small prime time: "; cerr << t << ", number of factors = " << spfactors->length() << "\n"; } // prepare for Hensel lifting // first, calculate bit bound long bnd1; long n = deg(f); long i; long e; ZZ P; long p; bnd1 = MaxBits(f) + (NumBits(n+1)+1)/2; if (!bnd || bnd1 < bnd) bnd = bnd1; i = n/2; while (!bit(LocalInfo.PossibleDegrees, i)) i--; long lc_bnd = NumBits(LeadCoeff(f)); long coeff_bnd = bnd + lc_bnd + i; long lift_bnd; lift_bnd = coeff_bnd + 15; // +15 helps avoid trial divisions...can be any number >= 0 lift_bnd = max(lift_bnd, bnd + lc_bnd + 2*NumBits(n) + ZZX_OVERLIFT); // facilitates "n-1" and "n-2" tests lift_bnd = max(lift_bnd, lc_bnd + NumBits(c1)); // facilitates f(1) test lift_bnd += 2; // +2 needed to get inequalities right p = zz_p::modulus(); e = long(double(lift_bnd)/(log(double(p))/log(double(2)))); power(P, p, e); while (NumBits(P) <= lift_bnd) { mul(P, P, p); e++; } if (verbose) { cerr << "lifting bound = " << lift_bnd << " bits.\n"; cerr << "Hensel lifting to exponent " << e << "...\n"; t = GetTime(); } // third, compute f1 so that it is monic and equal to f mod P ZZX f1; if (LeadCoeff(f) == 1) f1 = f; else if (LeadCoeff(f) == -1) negate(f1, f); else { rem(t1, LeadCoeff(f), P); if (sign(P) < 0) Error("whoops!!!"); InvMod(t1, t1, P); f1.rep.SetLength(n+1); for (i = 0; i <= n; i++) { mul(t2, f.rep[i], t1); rem(f1.rep[i], t2, P); } } // Do Hensel lift vec_ZZX w; MultiLift(w, *spfactors, f1, e, verbose); if (verbose) { t = GetTime()-t; cerr << "\nlifting time: "; cerr << t << "\n\n"; } // We're done with zz_p...restore delete spfactors; bak.restore(); // search for true factors if (verbose) { cerr << "searching for true factors...\n"; t = GetTime(); } if (ZZXFac_van_Hoeij && w.length() > van_hoeij_size_thresh) FindTrueFactors_vH(factors, f, w, P, p, e, LocalInfo, verbose, coeff_bnd); else FindTrueFactors(factors, f, w, P, LocalInfo, verbose, coeff_bnd); if (verbose) { t = GetTime()-t; cerr << "factor search time " << t << "\n"; } long r = factors.length(); if (rev) { for (i = 0; i < r; i++) { inplace_rev(factors[i]); if (sign(LeadCoeff(factors[i])) < 0) negate(factors[i], factors[i]); } } if (xfac) { factors.SetLength(r+1); SetX(factors[r]); r++; } if (x1fac) { factors.SetLength(r+1); factors[r] = ZZX(1,1)-1; r++; } // that's it!! if (verbose) { cerr << "*** end SFFactor. degree sequence:\n"; for (i = 0; i < r; i++) cerr << deg(factors[i]) << " "; cerr << "\n"; } } static long DeflationFactor(const ZZX& f) { long n = deg(f); long m = 0; long i; for (i = 1; i <= n && m != 1; i++) { if (f.rep[i] != 0) m = GCD(m, i); } return m; } static void inflate(ZZX& g, const ZZX& f, long m) // input may not alias output { long n = deg(f); long i; g = 0; for (i = n; i >= 0; i--) SetCoeff(g, i*m, f.rep[i]); } static void deflate(ZZX& g, const ZZX& f, long m) // input may not alias output { long n = deg(f); long i; g = 0; for (i = n; i >= 0; i -= m) SetCoeff(g, i/m, f.rep[i]); } static void MakeFacList(vec_long& v, long m) { if (m <= 0) Error("internal error: MakeFacList"); v.SetLength(0); long p = 2; while (m > 1) { while (m % p == 0) { append(v, p); m = m / p; } p++; } } NTL_THREAD_LOCAL long ZZXFac_PowerHack = 1; void SFFactor(vec_ZZX& factors, const ZZX& ff, long verbose, long bnd) // input is primitive and square-free, with positive leading // coefficient { if (ff == 0) Error("SFFactor: bad args"); if (deg(ff) <= 0) { factors.SetLength(0); return; } if (!ZZXFac_PowerHack) { ok_to_abandon = 0; ll_SFFactor(factors, ff, verbose, bnd); return; } long m = DeflationFactor(ff); if (m == 1) { if (verbose) { cerr << "SFFactor -- no deflation\n"; } ok_to_abandon = 0; ll_SFFactor(factors, ff, verbose, bnd); return; } vec_long v; MakeFacList(v, m); long l = v.length(); if (verbose) { cerr << "SFFactor -- deflation: " << v << "\n"; } vec_ZZX res; res.SetLength(1); deflate(res[0], ff, m); long done; long j, k; done = 0; k = l-1; while (!done) { vec_ZZX res1; res1.SetLength(0); for (j = 0; j < res.length(); j++) { vec_ZZX res2; double t; if (verbose) { cerr << "begin - step " << k << ", " << j << "; deg = " << deg(res[j]) << "\n"; t = GetTime(); } if (k < 0) ok_to_abandon = 0; else ok_to_abandon = 1; ll_SFFactor(res2, res[j], verbose, k < 0 ? bnd : 0); if (verbose) { t = GetTime()-t; cerr << "end - step " << k << ", " << j << "; time = " << t << "\n\n"; } append(res1, res2); } if (k < 0) { done = 1; swap(res, res1); } else { vec_ZZX res2; res2.SetLength(res1.length()); for (j = 0; j < res1.length(); j++) inflate(res2[j], res1[j], v[k]); k--; swap(res, res2); } } factors = res; } void factor(ZZ& c, vec_pair_ZZX_long& factors, const ZZX& f, long verbose, long bnd) { ZZX ff = f; if (deg(ff) <= 0) { c = ConstTerm(ff); factors.SetLength(0); return; } content(c, ff); divide(ff, ff, c); long bnd1 = MaxBits(ff) + (NumBits(deg(ff)+1)+1)/2; if (!bnd || bnd > bnd1) bnd = bnd1; vec_pair_ZZX_long sfd; double t; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, ff); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); vec_ZZX x; long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; t = GetTime(); } SFFactor(x, sfd[i].a, verbose, bnd); if (verbose) { t = GetTime()-t; cerr << "total time for multiplicity " << sfd[i].b << ": " << t << "\n"; } for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } NTL_END_IMPL ntl-6.2.1/src/ZZ_p.c000644 000765 000024 00000015105 12377144456 014452 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL ZZ_pInfoT::ZZ_pInfoT(const ZZ& NewP) { if (NewP <= 1) Error("ZZ_pContext: p must be > 1"); ref_count = 1; p = NewP; size = p.size(); ExtendedModulusSize = 2*size + (NTL_BITS_PER_LONG + NTL_ZZ_NBITS - 1)/NTL_ZZ_NBITS; initialized = 0; x = 0; u = 0; } void ZZ_pInfoT::init() { ZZ B, M, M1, M2, M3; long n, i; long q, t; initialized = 1; sqr(B, p); LeftShift(B, B, NTL_FFTMaxRoot+NTL_FFTFudge); // FIXME: the following is quadratic time...would // be nice to get a faster solution... // One could estimate the # of primes by summing logs, // then multiply using a tree-based multiply, then // adjust up or down... // Assuming IEEE floating point, the worst case estimate // for error guarantees a correct answer +/- 1 for // numprimes up to 2^25...for sure we won't be // using that many primes...we can certainly put in // a sanity check, though. // If I want a more accuaruate summation (with using Kahan, // which has some portability issues), I could represent // numbers as x = a + f, where a is integer and f is the fractional // part. Summing in this representation introduces an *absolute* // error of 2 epsilon n, which is just as good as Kahan // for this application. // same strategy could also be used in the ZZX HomMul routine, // if we ever want to make that subquadratic set(M); n = 0; while (M <= B) { UseFFTPrime(n); q = FFTPrime[n]; n++; mul(M, M, q); } NumPrimes = n; MaxRoot = CalcMaxRoot(q); double fn = double(n); if (8.0*fn*(fn+32) > NTL_FDOUBLE_PRECISION) Error("modulus too big"); if (8.0*fn*(fn+32) > NTL_FDOUBLE_PRECISION/double(NTL_SP_BOUND)) QuickCRT = 0; else QuickCRT = 1; if (!(x = (double *) NTL_MALLOC(n, sizeof(double), 0))) Error("out of space"); if (!(u = (long *) NTL_MALLOC(n, sizeof(long), 0))) Error("out of space"); ZZ_p_rem_struct_init(&rem_struct, n, p, FFTPrime); ZZ_p_crt_struct_init(&crt_struct, n, p, FFTPrime); if (ZZ_p_crt_struct_special(crt_struct)) return; // FIXME: thread-safe impl: there is a problem here. // in addition to read-only tables, which can be shared across threads, // the rem and crt data structures hold scartch space which cannot. // So a viable solution is to allocate thread-local scratch space when // installing a modulus (assuming the tables are already initialized, // otherwise delay allocation until initialization), and free // it when uninstalling. This should be efficient enough...I just // want to avoid allocation and deallocation on *every* rem/crt ZZ qq, rr; DivRem(qq, rr, M, p); NegateMod(MinusMModP, rr, p); for (i = 0; i < n; i++) { q = FFTPrime[i]; long tt = rem(qq, q); mul(M2, p, tt); add(M2, M2, rr); div(M2, M2, q); // = (M/q) rem p div(M1, M, q); t = rem(M1, q); t = InvMod(t, q); mul(M3, M2, t); rem(M3, M3, p); ZZ_p_crt_struct_insert(crt_struct, i, M3); x[i] = ((double) t)/((double) q); u[i] = t; } } ZZ_pInfoT::~ZZ_pInfoT() { if (initialized) { ZZ_p_rem_struct_free(rem_struct); ZZ_p_crt_struct_free(crt_struct); free(x); free(u); } } NTL_THREAD_LOCAL ZZ_pInfoT *ZZ_pInfo = 0; typedef ZZ_pInfoT *ZZ_pInfoPtr; static void CopyPointer(ZZ_pInfoPtr& dst, ZZ_pInfoPtr src) { if (src == dst) return; if (dst) { dst->ref_count--; if (dst->ref_count < 0) Error("internal error: negative ZZ_pContext ref_count"); if (dst->ref_count == 0) delete dst; } if (src) { if (src->ref_count == NTL_MAX_LONG) Error("internal error: ZZ_pContext ref_count overflow"); src->ref_count++; } dst = src; } // FIXME: thread-safe impl: see FIXME in lzz_p.c regarding // foreign contexts void ZZ_p::init(const ZZ& p) { ZZ_pContext c(p); c.restore(); } ZZ_pContext::ZZ_pContext(const ZZ& p) { ptr = NTL_NEW_OP ZZ_pInfoT(p); } ZZ_pContext::ZZ_pContext(const ZZ_pContext& a) { ptr = 0; CopyPointer(ptr, a.ptr); } ZZ_pContext& ZZ_pContext::operator=(const ZZ_pContext& a) { CopyPointer(ptr, a.ptr); return *this; } ZZ_pContext::~ZZ_pContext() { CopyPointer(ptr, 0); } void ZZ_pContext::save() { CopyPointer(ptr, ZZ_pInfo); } void ZZ_pContext::restore() const { CopyPointer(ZZ_pInfo, ptr); } ZZ_pBak::~ZZ_pBak() { if (MustRestore) CopyPointer(ZZ_pInfo, ptr); CopyPointer(ptr, 0); } void ZZ_pBak::save() { MustRestore = 1; CopyPointer(ptr, ZZ_pInfo); } void ZZ_pBak::restore() { MustRestore = 0; CopyPointer(ZZ_pInfo, ptr); } const ZZ_p& ZZ_p::zero() { NTL_THREAD_LOCAL static ZZ_p z(INIT_NO_ALLOC); return z; } ZZ_p::DivHandlerPtr ZZ_p::DivHandler = 0; ZZ_p::ZZ_p(INIT_VAL_TYPE, const ZZ& a) // NO_ALLOC { conv(*this, a); } ZZ_p::ZZ_p(INIT_VAL_TYPE, long a) // NO_ALLOC { conv(*this, a); } void conv(ZZ_p& x, long a) { if (a == 0) clear(x); else if (a == 1) set(x); else { NTL_ZZRegister(y); conv(y, a); conv(x, y); } } istream& operator>>(istream& s, ZZ_p& x) { NTL_ZZRegister(y); s >> y; conv(x, y); return s; } void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b) { NTL_ZZ_pRegister(T); inv(T, b); mul(x, a, T); } void inv(ZZ_p& x, const ZZ_p& a) { if (InvModStatus(x._ZZ_p__rep, a._ZZ_p__rep, ZZ_p::modulus())) { if (IsZero(a._ZZ_p__rep)) Error("ZZ_p: division by zero"); else if (ZZ_p::DivHandler) (*ZZ_p::DivHandler)(a); else Error("ZZ_p: division by non-invertible element"); } } long operator==(const ZZ_p& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); NTL_ZZ_pRegister(T); conv(T, b); return a == T; } void add(ZZ_p& x, const ZZ_p& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); add(x, a, T); } void sub(ZZ_p& x, const ZZ_p& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); sub(x, a, T); } void sub(ZZ_p& x, long a, const ZZ_p& b) { NTL_ZZ_pRegister(T); conv(T, a); sub(x, T, b); } void mul(ZZ_p& x, const ZZ_p& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); mul(x, a, T); } void div(ZZ_p& x, const ZZ_p& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); div(x, a, T); } void div(ZZ_p& x, long a, const ZZ_p& b) { if (a == 1) { inv(x, b); } else { NTL_ZZ_pRegister(T); conv(T, a); div(x, T, b); } } NTL_END_IMPL ntl-6.2.1/src/ZZ_pE.c000644 000765 000024 00000005331 12377144456 014557 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL ZZ_pEInfoT::ZZ_pEInfoT(const ZZ_pX& NewP) { ref_count = 1; build(p, NewP); _card_init = 0; _card_base = ZZ_p::modulus(); _card_exp = deg(NewP); } const ZZ& ZZ_pE::cardinality() { if (!ZZ_pEInfo) Error("ZZ_pE::cardinality: undefined modulus"); // FIXME: in a thread-safe impl, the following needs to be mutexed if (!ZZ_pEInfo->_card_init) { power(ZZ_pEInfo->_card, ZZ_pEInfo->_card_base, ZZ_pEInfo->_card_exp); ZZ_pEInfo->_card_init = 1; } return ZZ_pEInfo->_card; } NTL_THREAD_LOCAL ZZ_pEInfoT *ZZ_pEInfo = 0; typedef ZZ_pEInfoT *ZZ_pEInfoPtr; static void CopyPointer(ZZ_pEInfoPtr& dst, ZZ_pEInfoPtr src) { if (src == dst) return; if (dst) { dst->ref_count--; if (dst->ref_count < 0) Error("internal error: negative ZZ_pEContext ref_count"); if (dst->ref_count == 0) delete dst; } if (src) { if (src->ref_count == NTL_MAX_LONG) Error("internal error: ZZ_pEContext ref_count overflow"); src->ref_count++; } dst = src; } void ZZ_pE::init(const ZZ_pX& p) { ZZ_pEContext c(p); c.restore(); } ZZ_pEContext::ZZ_pEContext(const ZZ_pX& p) { ptr = NTL_NEW_OP ZZ_pEInfoT(p); } ZZ_pEContext::ZZ_pEContext(const ZZ_pEContext& a) { ptr = 0; CopyPointer(ptr, a.ptr); } ZZ_pEContext& ZZ_pEContext::operator=(const ZZ_pEContext& a) { CopyPointer(ptr, a.ptr); return *this; } ZZ_pEContext::~ZZ_pEContext() { CopyPointer(ptr, 0); } void ZZ_pEContext::save() { CopyPointer(ptr, ZZ_pEInfo); } void ZZ_pEContext::restore() const { CopyPointer(ZZ_pEInfo, ptr); } ZZ_pEBak::~ZZ_pEBak() { if (MustRestore) CopyPointer(ZZ_pEInfo, ptr); CopyPointer(ptr, 0); } void ZZ_pEBak::save() { MustRestore = 1; CopyPointer(ptr, ZZ_pEInfo); } void ZZ_pEBak::restore() { MustRestore = 0; CopyPointer(ZZ_pEInfo, ptr); } const ZZ_pE& ZZ_pE::zero() { static ZZ_pE z(INIT_NO_ALLOC); return z; } istream& operator>>(istream& s, ZZ_pE& x) { ZZ_pX y; s >> y; conv(x, y); return s; } void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE t; inv(t, b); mul(x, a, t); } void div(ZZ_pE& x, const ZZ_pE& a, long b) { NTL_ZZ_pRegister(B); B = b; inv(B, B); mul(x, a, B); } void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b) { NTL_ZZ_pRegister(B); B = b; inv(B, B); mul(x, a, B); } void div(ZZ_pE& x, long a, const ZZ_pE& b) { ZZ_pE t; inv(t, b); mul(x, a, t); } void div(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b) { ZZ_pE t; inv(t, b); mul(x, a, t); } void inv(ZZ_pE& x, const ZZ_pE& a) { InvMod(x._ZZ_pE__rep, a._ZZ_pE__rep, ZZ_pE::modulus()); } NTL_END_IMPL ntl-6.2.1/src/ZZ_pEX.c000644 000765 000024 00000163661 12377144456 014722 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL const ZZ_pEX& ZZ_pEX::zero() { NTL_THREAD_LOCAL static ZZ_pEX z; return z; } istream& operator>>(istream& s, ZZ_pEX& x) { s >> x.rep; x.normalize(); return s; } ostream& operator<<(ostream& s, const ZZ_pEX& a) { return s << a.rep; } void ZZ_pEX::normalize() { long n; const ZZ_pE* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const ZZ_pEX& a) { return a.rep.length() == 0; } long IsOne(const ZZ_pEX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } long operator==(const ZZ_pEX& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); long da = deg(a); if (da > 0) return 0; NTL_ZZ_pRegister(bb); bb = b; if (da < 0) return IsZero(bb); return a.rep[0] == bb; } long operator==(const ZZ_pEX& a, const ZZ_p& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } long operator==(const ZZ_pEX& a, const ZZ_pE& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } void SetCoeff(ZZ_pEX& x, long i, const ZZ_pE& a) { long j, m; if (i < 0) Error("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { ZZ_pE aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(ZZ_pEX& x, long i, const ZZ_p& aa) { long j, m; if (i < 0) Error("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); NTL_ZZ_pRegister(a); // watch out for aliases! a = aa; m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } x.rep[i] = a; x.normalize(); } void SetCoeff(ZZ_pEX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else { NTL_ZZ_pRegister(T); T = a; SetCoeff(x, i, T); } } void SetCoeff(ZZ_pEX& x, long i) { long j, m; if (i < 0) Error("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(ZZ_pEX& x) { clear(x); SetCoeff(x, 1); } long IsX(const ZZ_pEX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const ZZ_pE& coeff(const ZZ_pEX& a, long i) { if (i < 0 || i > deg(a)) return ZZ_pE::zero(); else return a.rep[i]; } const ZZ_pE& LeadCoeff(const ZZ_pEX& a) { if (IsZero(a)) return ZZ_pE::zero(); else return a.rep[deg(a)]; } const ZZ_pE& ConstTerm(const ZZ_pEX& a) { if (IsZero(a)) return ZZ_pE::zero(); else return a.rep[0]; } void conv(ZZ_pEX& x, const ZZ_pE& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(ZZ_pEX& x, long a) { if (a == 0) clear(x); else if (a == 1) set(x); else { NTL_ZZ_pRegister(T); T = a; conv(x, T); } } void conv(ZZ_pEX& x, const ZZ& a) { NTL_ZZ_pRegister(T); conv(T, a); conv(x, T); } void conv(ZZ_pEX& x, const ZZ_p& a) { if (IsZero(a)) clear(x); else if (IsOne(a)) set(x); else { x.rep.SetLength(1); conv(x.rep[0], a); x.normalize(); } } void conv(ZZ_pEX& x, const ZZ_pX& aa) { ZZ_pX a = aa; // in case a aliases the rep of a coefficient of x long n = deg(a)+1; long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], coeff(a, i)); } void conv(ZZ_pEX& x, const vec_ZZ_pE& a) { x.rep = a; x.normalize(); } /* additional legacy conversions for v6 conversion regime */ void conv(ZZ_pEX& x, const ZZX& a) { long n = a.rep.length(); long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], a.rep[i]); x.normalize(); } /* ------------------------------------- */ void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ_pE *ap, *bp; ZZ_pE* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pE& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(ZZ_pEX& x, const ZZ_pEX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ_pE *ap, *bp; ZZ_pE* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pE& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_pEX& a, long b) { if (a.rep.length() == 0) { conv(x, b); negate(x, x); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_pE& b, const ZZ_pEX& a) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (x.rep.MaxLength() == 0) { negate(x, a); add(x.rep[0], x.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); sub(xp[0], b, a.rep[0]); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) negate(xp[i], ap[i]); x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_p& a, const ZZ_pEX& b) { NTL_ZZ_pRegister(T); // avoids aliasing problems T = a; negate(x, b); add(x, x, T); } void sub(ZZ_pEX& x, long a, const ZZ_pEX& b) { NTL_ZZ_pRegister(T); T = a; negate(x, b); add(x, x, T); } void mul(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEX& b) { if (&a == &b) { sqr(c, a); return; } if (IsZero(a) || IsZero(b)) { clear(c); return; } if (deg(a) == 0) { mul(c, b, ConstTerm(a)); return; } if (deg(b) == 0) { mul(c, a, ConstTerm(b)); return; } // general case...Kronecker subst ZZ_pX A, B, C; long da = deg(a); long db = deg(b); long n = ZZ_pE::degree(); long n2 = 2*n-1; if (NTL_OVERFLOW(da+db+1, n2, 0)) Error("overflow in ZZ_pEX mul"); long i, j; A.rep.SetLength((da+1)*n2); for (i = 0; i <= da; i++) { const ZZ_pX& coeff = rep(a.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) A.rep[n2*i + j] = coeff.rep[j]; } A.normalize(); B.rep.SetLength((db+1)*n2); for (i = 0; i <= db; i++) { const ZZ_pX& coeff = rep(b.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) B.rep[n2*i + j] = coeff.rep[j]; } B.normalize(); mul(C, A, B); long Clen = C.rep.length(); long lc = (Clen + n2 - 1)/n2; long dc = lc - 1; c.rep.SetLength(dc+1); ZZ_pX tmp; for (i = 0; i <= dc; i++) { tmp.rep.SetLength(n2); for (j = 0; j < n2 && n2*i + j < Clen; j++) tmp.rep[j] = C.rep[n2*i + j]; for (; j < n2; j++) clear(tmp.rep[j]); tmp.normalize(); conv(c.rep[i], tmp); } c.normalize(); } void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pE& b) { if (IsZero(b)) { clear(x); return; } ZZ_pE t; t = b; long i, da; const ZZ_pE *ap; ZZ_pE* xp; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_p& b) { if (IsZero(b)) { clear(x); return; } NTL_ZZ_pRegister(t); t = b; long i, da; const ZZ_pE *ap; ZZ_pE* xp; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(ZZ_pEX& x, const ZZ_pEX& a, long b) { NTL_ZZ_pRegister(t); t = b; mul(x, a, t); } void sqr(ZZ_pEX& c, const ZZ_pEX& a) { if (IsZero(a)) { clear(c); return; } if (deg(a) == 0) { ZZ_pE res; sqr(res, ConstTerm(a)); conv(c, res); return; } // general case...Kronecker subst ZZ_pX A, C; long da = deg(a); long n = ZZ_pE::degree(); long n2 = 2*n-1; if (NTL_OVERFLOW(2*da+1, n2, 0)) Error("overflow in ZZ_pEX sqr"); long i, j; A.rep.SetLength((da+1)*n2); for (i = 0; i <= da; i++) { const ZZ_pX& coeff = rep(a.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) A.rep[n2*i + j] = coeff.rep[j]; } A.normalize(); sqr(C, A); long Clen = C.rep.length(); long lc = (Clen + n2 - 1)/n2; long dc = lc - 1; c.rep.SetLength(dc+1); ZZ_pX tmp; for (i = 0; i <= dc; i++) { tmp.rep.SetLength(n2); for (j = 0; j < n2 && n2*i + j < Clen; j++) tmp.rep[j] = C.rep[n2*i + j]; for (; j < n2; j++) clear(tmp.rep[j]); tmp.normalize(); conv(c.rep[i], tmp); } c.normalize(); } void MulTrunc(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, long n) { if (n < 0) Error("MulTrunc: bad args"); ZZ_pEX t; mul(t, a, b); trunc(x, t, n); } void SqrTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n) { if (n < 0) Error("SqrTrunc: bad args"); ZZ_pEX t; sqr(t, a); trunc(x, t, n); } void CopyReverse(ZZ_pEX& x, const ZZ_pEX& a, long hi) // x[0..hi] = reverse(a[0..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi+1; m = a.rep.length(); x.rep.SetLength(n); const ZZ_pE* ap = a.rep.elts(); ZZ_pE* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void trunc(ZZ_pEX& x, const ZZ_pEX& a, long m) // x = a % X^m, output may alias input { if (m < 0) Error("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; ZZ_pE* xp; const ZZ_pE* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void random(ZZ_pEX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void negate(ZZ_pEX& x, const ZZ_pEX& a) { long n = a.rep.length(); x.rep.SetLength(n); const ZZ_pE* ap = a.rep.elts(); ZZ_pE* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } static void MulByXModAux(ZZ_pEX& h, const ZZ_pEX& a, const ZZ_pEX& f) { long i, n, m; ZZ_pE* hh; const ZZ_pE *aa, *ff; ZZ_pE t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) Error("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(ZZ_pEX& h, const ZZ_pEX& a, const ZZ_pEX& f) { if (&h == &f) { ZZ_pEX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void PlainMul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b) { long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } long d = da+db; const ZZ_pE *ap, *bp; ZZ_pE *xp; ZZ_pEX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; ZZ_pX t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(bp[i-j])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void SetSize(vec_ZZ_pX& x, long n, long m) { x.SetLength(n); long i; for (i = 0; i < n; i++) x[i].rep.SetMaxLength(m); } void PlainDivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pE *qp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pEX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZ_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_ZZ_pX x; SetSize(x, da+1, 2*ZZ_pE::degree()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainRem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b, vec_ZZ_pX& x) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pEX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b, vec_ZZ_pX& x) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pE *qp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pEX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZ_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDiv(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pE *qp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pEX: division by zero"); if (da < db) { clear(q); return; } ZZ_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_ZZ_pX x; SetSize(x, da+1-db, 2*ZZ_pE::degree()); for (i = db; i <= da; i++) x[i-db] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j-db], xp[i+j-db], s); } } } void PlainRem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pEX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_ZZ_pX x; SetSize(x, da + 1, 2*ZZ_pE::degree()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void RightShift(ZZ_pEX& x, const ZZ_pEX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) Error("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(ZZ_pEX& x, const ZZ_pEX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void NewtonInv(ZZ_pEX& c, const ZZ_pEX& a, long e) { ZZ_pE x; inv(x, ConstTerm(a)); if (e == 1) { conv(c, x); return; } vec_long E; E.SetLength(0); append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long L = E.length(); ZZ_pEX g, g0, g1, g2; g.rep.SetMaxLength(E[0]); g0.rep.SetMaxLength(E[0]); g1.rep.SetMaxLength((3*E[0]+1)/2); g2.rep.SetMaxLength(E[0]); conv(g, x); long i; for (i = L-1; i > 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); sub(g, g, g2); } c = g; } void InvTrunc(ZZ_pEX& c, const ZZ_pEX& a, long e) { if (e < 0) Error("InvTrunc: bad args"); if (e == 0) { clear(c); return; } if (NTL_OVERFLOW(e, 1, 0)) Error("overflow in InvTrunc"); NewtonInv(c, a, e); } const long ZZ_pEX_MOD_PLAIN = 0; const long ZZ_pEX_MOD_MUL = 1; void build(ZZ_pEXModulus& F, const ZZ_pEX& f) { long n = deg(f); if (n <= 0) Error("build(ZZ_pEXModulus,ZZ_pEX): deg(f) <= 0"); if (NTL_OVERFLOW(n, ZZ_pE::degree(), 0)) Error("build(ZZ_pEXModulus,ZZ_pEX): overflow"); F.tracevec.SetLength(0); F.f = f; F.n = n; if (F.n < ZZ_pE::ModCross()) { F.method = ZZ_pEX_MOD_PLAIN; } else { F.method = ZZ_pEX_MOD_MUL; ZZ_pEX P1; ZZ_pEX P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); trunc(F.f0, f, n); F.hlc = ConstTerm(P2); } } ZZ_pEXModulus::ZZ_pEXModulus() { n = -1; method = ZZ_pEX_MOD_PLAIN; } ZZ_pEXModulus::~ZZ_pEXModulus() { } ZZ_pEXModulus::ZZ_pEXModulus(const ZZ_pEX& ff) { n = -1; method = ZZ_pEX_MOD_PLAIN; build(*this, ff); } void UseMulRem21(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX P1; ZZ_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); sub(r, r, P1); } void UseMulDivRem21(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX P1; ZZ_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); sub(r, r, P1); q = P2; } void UseMulDiv21(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX P1; ZZ_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); q = P2; } void rem(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F) { if (F.method == ZZ_pEX_MOD_PLAIN) { PlainRem(x, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulRem21(x, a, F); return; } ZZ_pEX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulRem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F) { if (F.method == ZZ_pEX_MOD_PLAIN) { PlainDivRem(q, r, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDivRem21(q, r, a, F); return; } ZZ_pEX buf(INIT_SIZE, 2*n-1); ZZ_pEX qbuf(INIT_SIZE, n-1); ZZ_pEX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulDivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F) { if (F.method == ZZ_pEX_MOD_PLAIN) { PlainDiv(q, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDiv21(q, a, F); return; } ZZ_pEX buf(INIT_SIZE, 2*n-1); ZZ_pEX qbuf(INIT_SIZE, n-1); ZZ_pEX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) UseMulDivRem21(qbuf, buf, buf, F); else UseMulDiv21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F) { if (deg(a) >= F.n || deg(b) >= F.n) Error("MulMod: bad args"); ZZ_pEX t; mul(t, a, b); rem(c, t, F); } void SqrMod(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEXModulus& F) { if (deg(a) >= F.n) Error("MulMod: bad args"); ZZ_pEX t; sqr(t, a); rem(c, t, F); } void UseMulRem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX P1; ZZ_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); sub(P1, a, P1); r = P1; } void UseMulDivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX P1; ZZ_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); sub(P1, a, P1); r = P1; q = P2; } void UseMulDiv(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX P1; ZZ_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); q = P2; } void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < ZZ_pE::DivCross() || sa-sb < ZZ_pE::DivCross()) PlainDivRem(q, r, a, b); else if (sa < 4*sb) UseMulDivRem(q, r, a, b); else { ZZ_pEXModulus B; build(B, b); DivRem(q, r, a, B); } } void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < ZZ_pE::DivCross() || sa-sb < ZZ_pE::DivCross()) PlainDiv(q, a, b); else if (sa < 4*sb) UseMulDiv(q, a, b); else { ZZ_pEXModulus B; build(B, b); div(q, a, B); } } void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pE T; inv(T, b); mul(q, a, T); } void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_p& b) { NTL_ZZ_pRegister(T); inv(T, b); mul(q, a, T); } void div(ZZ_pEX& q, const ZZ_pEX& a, long b) { NTL_ZZ_pRegister(T); T = b; inv(T, T); mul(q, a, T); } void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < ZZ_pE::DivCross() || sa-sb < ZZ_pE::DivCross()) PlainRem(r, a, b); else if (sa < 4*sb) UseMulRem(r, a, b); else { ZZ_pEXModulus B; build(B, b); rem(r, a, B); } } void GCD(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pE t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; ZZ_pEX u(INIT_SIZE, n), v(INIT_SIZE, n); vec_ZZ_pX tmp; SetSize(tmp, n, 2*ZZ_pE::degree()); u = a; v = b; do { PlainRem(u, u, v, tmp); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } void XGCD(ZZ_pEX& d, ZZ_pEX& s, ZZ_pEX& t, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pE z; if (IsZero(b)) { set(s); clear(t); d = a; } else if (IsZero(a)) { clear(s); set(t); d = b; } else { long e = max(deg(a), deg(b)) + 1; ZZ_pEX temp(INIT_SIZE, e), u(INIT_SIZE, e), v(INIT_SIZE, e), u0(INIT_SIZE, e), v0(INIT_SIZE, e), u1(INIT_SIZE, e), v1(INIT_SIZE, e), u2(INIT_SIZE, e), v2(INIT_SIZE, e), q(INIT_SIZE, e); set(u1); clear(v1); clear(u2); set(v2); u = a; v = b; do { DivRem(q, u, u, v); swap(u, v); u0 = u2; v0 = v2; mul(temp, q, u2); sub(u2, u1, temp); mul(temp, q, v2); sub(v2, v1, temp); u1 = u0; v1 = v0; } while (!IsZero(v)); d = u; s = u1; t = v1; } if (IsZero(d)) return; if (IsOne(LeadCoeff(d))) return; /* make gcd monic */ inv(z, LeadCoeff(d)); mul(d, d, z); mul(s, s, z); mul(t, t, z); } void IterBuild(ZZ_pE* a, long n) { long i, k; ZZ_pE b, t; if (n <= 0) return; negate(a[0], a[0]); for (k = 1; k <= n-1; k++) { negate(b, a[k]); add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void BuildFromRoots(ZZ_pEX& x, const vec_ZZ_pE& a) { long n = a.length(); if (n == 0) { set(x); return; } x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); } void eval(ZZ_pE& b, const ZZ_pEX& f, const ZZ_pE& a) // does a Horner evaluation { ZZ_pE acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_ZZ_pE& b, const ZZ_pEX& f, const vec_ZZ_pE& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_ZZ_pE bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(ZZ_pEX& f, const vec_ZZ_pE& a, const vec_ZZ_pE& b) { long m = a.length(); if (b.length() != m) Error("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_ZZ_pE prod; prod = a; ZZ_pE t1, t2; long k, i; vec_ZZ_pE res; res.SetLength(m); for (k = 0; k < m; k++) { const ZZ_pE& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(ZZ_pEX& x, const vec_ZZ_pE& v, long low, long high, const vec_ZZ_pEX& H, long n, vec_ZZ_pX& t) { ZZ_pX s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_ZZ_pE& h = H[i-low].rep; long m = h.length(); const ZZ_pX& w = rep(v[i]); for (j = 0; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) conv(x.rep[j], t[j]); x.normalize(); } void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEXArgument& A, const ZZ_pEXModulus& F) { if (deg(g) <= 0) { x = g; return; } ZZ_pEX s, t; vec_ZZ_pX scratch; SetSize(scratch, deg(F), 2*ZZ_pE::degree()); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const ZZ_pEX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(ZZ_pEXArgument& A, const ZZ_pEX& h, const ZZ_pEXModulus& F, long m) { long i; if (m <= 0 || deg(h) >= F.n) Error("build: bad args"); if (m > F.n) m = F.n; if (ZZ_pEXArgBound > 0) { double sz = ZZ_p::storage(); sz = sz*ZZ_pE::degree(); sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_pE); sz = sz/1024; m = min(m, long(ZZ_pEXArgBound/sz)); m = max(m, 1); } A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], h, F); } NTL_THREAD_LOCAL long ZZ_pEXArgBound = 0; void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } ZZ_pEXArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(ZZ_pEX& x1, ZZ_pEX& x2, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& h, const ZZ_pEXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } ZZ_pEXArgument A; build(A, h, F, m); ZZ_pEX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(ZZ_pEX& x1, ZZ_pEX& x2, ZZ_pEX& x3, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& g3, const ZZ_pEX& h, const ZZ_pEXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } ZZ_pEXArgument A; build(A, h, F, m); ZZ_pEX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } void build(ZZ_pEXTransMultiplier& B, const ZZ_pEX& b, const ZZ_pEXModulus& F) { long db = deg(b); if (db >= F.n) Error("build TransMultiplier: bad args"); ZZ_pEX t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, d); // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, d); if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, db); } void TransMulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F) { if (deg(a) >= F.n) Error("TransMulMod: bad args"); ZZ_pEX t1, t2; mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); LeftShift(t2, t2, 1); sub(x, t1, t2); } void ShiftSub(ZZ_pEX& U, const ZZ_pEX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void UpdateMap(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F) { ZZ_pEX xx; TransMulMod(xx, to_ZZ_pEX(a), B, F); x = xx.rep; } static void ProjectPowers(vec_ZZ_pE& x, const ZZ_pEX& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F) { if (k < 0 || NTL_OVERFLOW(k, 1, 0) || deg(a) >= F.n) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; ZZ_pEXTransMultiplier M; build(M, H.H[m], F); ZZ_pEX s; s = a; x.SetLength(k); long i; for (i = 0; i <= l; i++) { long m1 = min(m, k-i*m); for (long j = 0; j < m1; j++) InnerProduct(x[i*m+j], H.H[j].rep, s.rep); if (i < l) TransMulMod(s, s, M, F); } } static void ProjectPowers(vec_ZZ_pE& x, const ZZ_pEX& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F) { if (k < 0 || deg(a) >= F.n || deg(h) >= F.n) Error("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0);; return; } long m = SqrRoot(k); ZZ_pEXArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F) { ProjectPowers(x, to_ZZ_pEX(a), k, H, F); } void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F) { ProjectPowers(x, to_ZZ_pEX(a), k, h, F); } void BerlekampMassey(ZZ_pEX& h, const vec_ZZ_pE& a, long m) { ZZ_pEX Lambda, Sigma, Temp; long L; ZZ_pE Delta, Delta1, t1; long shamt; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(Delta1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(t1, Lambda.rep[i], a[r-i-1]); add(Delta1, Delta1, t1); } if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftSub(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftSub(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void MinPolySeq(ZZ_pEX& h, const vec_ZZ_pE& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) Error("MinPoly: bad args"); if (a.length() < 2*m) Error("MinPoly: sequence too short"); BerlekampMassey(h, a, m); } void DoMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m, const ZZ_pEX& R) { vec_ZZ_pE x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) Error("ProbMinPoly: bad args"); ZZ_pEX R; random(R, n); DoMinPolyMod(h, g, F, m, R); } void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } void MinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pEX h, h1; long n = F.n; if (m < 1 || m > n) Error("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ ZZ_pEX h2, h3; ZZ_pEX R; ZZ_pEXTransMultiplier H1; for (;;) { random(R, n); build(H1, h1, F); TransMulMod(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { if (m < 1 || m > F.n) Error("IrredPoly: bad args"); ZZ_pEX R; set(R); DoMinPolyMod(h, g, F, m, R); } void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { IrredPolyMod(h, g, F, F.n); } void MinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F) { MinPolyMod(hh, g, F, F.n); } void diff(ZZ_pEX& x, const ZZ_pEX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void MakeMonic(ZZ_pEX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; ZZ_pE t; inv(t, LeadCoeff(x)); mul(x, x, t); } long divide(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } ZZ_pEX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const ZZ_pEX& a, const ZZ_pEX& b) { if (IsZero(b)) return IsZero(a); ZZ_pEX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } static long OptWinSize(long n) // finds k that minimizes n/(k+1) + 2^{k-1} { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/(double(k+2)) + double(1L << k); if (v_new >= v) break; v = v_new; k++; } return k; } void PowerMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ& e, const ZZ_pEXModulus& F) // h = g^e mod f using "sliding window" algorithm { if (deg(g) >= F.n) Error("PowerMod: bad args"); if (e == 0) { set(h); return; } if (e == 1) { h = g; return; } if (e == -1) { InvMod(h, g, F); return; } if (e == 2) { SqrMod(h, g, F); return; } if (e == -2) { SqrMod(h, g, F); InvMod(h, h, F); return; } long n = NumBits(e); ZZ_pEX res; res.SetMaxLength(F.n); set(res); long i; if (n < 16) { // plain square-and-multiply algorithm for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, g, F); } if (e < 0) InvMod(res, res, F); h = res; return; } long k = OptWinSize(n); k = min(k, 3); vec_ZZ_pEX v; v.SetLength(1L << (k-1)); v[0] = g; if (k > 1) { ZZ_pEX t; SqrMod(t, g, F); for (i = 1; i < (1L << (k-1)); i++) MulMod(v[i], v[i-1], t, F); } long val; long cnt; long m; val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | bit(e, i); if (val == 0) SqrMod(res, res, F); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { SqrMod(res, res, F); m = m >> 1; } MulMod(res, res, v[val >> 1], F); while (cnt > 0) { SqrMod(res, res, F); cnt--; } val = 0; } } if (e < 0) InvMod(res, res, F); h = res; } void InvMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvMod: bad args"); ZZ_pEX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) Error("ZZ_pEX InvMod: can't compute multiplicative inverse"); } long InvModStatus(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvModStatus: bad args"); ZZ_pEX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) Error("MulMod: bad args"); ZZ_pEX t; mul(t, a, b); rem(x, t, f); } void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("SqrMod: bad args"); ZZ_pEX t; sqr(t, a); rem(x, t, f); } void PowerXMod(ZZ_pEX& hh, const ZZ& e, const ZZ_pEXModulus& F) { if (F.n < 0) Error("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; ZZ_pEX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) MulByXMod(h, h, F.f); } if (e < 0) InvMod(h, h, F); hh = h; } void reverse(ZZ_pEX& x, const ZZ_pEX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) Error("overflow in reverse"); if (&x == &a) { ZZ_pEX tmp; CopyReverse(tmp, a, hi); x = tmp; } else CopyReverse(x, a, hi); } void power(ZZ_pEX& x, const ZZ_pEX& a, long e) { if (e < 0) { Error("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) Error("overflow in power"); ZZ_pEX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } static void FastTraceVec(vec_ZZ_pE& S, const ZZ_pEXModulus& f) { long n = deg(f); ZZ_pEX x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); S.SetLength(n); S[0] = n; long i; for (i = 1; i < n; i++) S[i] = coeff(x, i); } void PlainTraceVec(vec_ZZ_pE& S, const ZZ_pEX& ff) { if (deg(ff) <= 0) Error("TraceVec: bad args"); ZZ_pEX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; ZZ_pX acc, t; ZZ_pE t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } } void TraceVec(vec_ZZ_pE& S, const ZZ_pEX& f) { if (deg(f) < ZZ_pE::DivCross()) PlainTraceVec(S, f); else FastTraceVec(S, f); } static void ComputeTraceVec(const ZZ_pEXModulus& F) { vec_ZZ_pE& S = *((vec_ZZ_pE *) &F.tracevec); if (S.length() > 0) return; if (F.method == ZZ_pEX_MOD_PLAIN) { PlainTraceVec(S, F.f); } else { FastTraceVec(S, F); } } void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEXModulus& F) { long n = F.n; if (deg(a) >= n) Error("trace: bad args"); // FIXME: in a thread-safe version, this needs to be mutexed if (F.tracevec.length() == 0) ComputeTraceVec(F); InnerProduct(x, a.rep, F.tracevec); } void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) Error("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(ZZ_pE& rres, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pE res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; ZZ_pE lc; set(res); long n = max(deg(a),deg(b)) + 1; ZZ_pEX u(INIT_SIZE, n), v(INIT_SIZE, n); vec_ZZ_pX tmp; SetSize(tmp, n, 2*ZZ_pE::degree()); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v, tmp); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } } rres = res; } void resultant(ZZ_pE& rres, const ZZ_pEX& a, const ZZ_pEX& b) { PlainResultant(rres, a, b); } void NormMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) Error("norm: bad args"); if (IsZero(a)) { clear(x); return; } ZZ_pE t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { ZZ_pE t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } // tower stuff... void InnerProduct(ZZ_pEX& x, const vec_ZZ_p& v, long low, long high, const vec_ZZ_pEX& H, long n, vec_ZZ_pE& t) { ZZ_pE s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_ZZ_pE& h = H[i-low].rep; long m = h.length(); const ZZ_p& w = v[i]; for (j = 0; j < m; j++) { mul(s, h[j], w); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) x.rep[j] = t[j]; x.normalize(); } void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEXArgument& A, const ZZ_pEXModulus& F) { if (deg(g) <= 0) { conv(x, g); return; } ZZ_pEX s, t; vec_ZZ_pE scratch; scratch.SetLength(deg(F)); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const ZZ_pEX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } ZZ_pEXArgument A; build(A, h, F, m); CompTower(x, g, A, F); } void PrepareProjection(vec_vec_ZZ_p& tt, const vec_ZZ_pE& s, const vec_ZZ_p& proj) { long l = s.length(); tt.SetLength(l); ZZ_pXMultiplier M; long i; for (i = 0; i < l; i++) { build(M, rep(s[i]), ZZ_pE::modulus()); UpdateMap(tt[i], proj, M, ZZ_pE::modulus()); } } void ProjectedInnerProduct(ZZ_p& x, const vec_ZZ_pE& a, const vec_vec_ZZ_p& b) { long n = min(a.length(), b.length()); ZZ_p t, res; res = 0; long i; for (i = 0; i < n; i++) { project(t, b[i], rep(a[i])); res += t; } x = res; } void PrecomputeProj(vec_ZZ_p& proj, const ZZ_pX& f) { long n = deg(f); if (n <= 0) Error("PrecomputeProj: bad args"); if (ConstTerm(f) != 0) { proj.SetLength(1); proj[0] = 1; } else { proj.SetLength(n); clear(proj); proj[n-1] = 1; } } void ProjectPowersTower(vec_ZZ_p& x, const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F, const vec_ZZ_p& proj) { long n = F.n; if (a.length() > n || k < 0 || NTL_OVERFLOW(k, 1, 0)) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; ZZ_pEXTransMultiplier M; build(M, H.H[m], F); vec_ZZ_pE s(INIT_SIZE, n); s = a; x.SetLength(k); vec_vec_ZZ_p tt; for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); ZZ_p* w = &x[i*m]; PrepareProjection(tt, s, proj); for (long j = 0; j < m1; j++) ProjectedInnerProduct(w[j], H.H[j].rep, tt); if (i < l) UpdateMap(s, s, M, F); } } void ProjectPowersTower(vec_ZZ_p& x, const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F, const vec_ZZ_p& proj) { if (a.length() > F.n || k < 0) Error("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); ZZ_pEXArgument H; build(H, h, F, m); ProjectPowersTower(x, a, k, H, F, proj); } void DoMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m, const vec_ZZ_pE& R, const vec_ZZ_p& proj) { vec_ZZ_p x; ProjectPowersTower(x, R, 2*m, g, F, proj); MinPolySeq(h, x, m); } void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { long n = F.n; if (m < 1 || m > n*ZZ_pE::degree()) Error("MinPoly: bad args"); vec_ZZ_pE R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); vec_ZZ_p proj; PrecomputeProj(proj, ZZ_pE::modulus()); DoMinPolyTower(h, g, F, m, R, proj); } void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m, const vec_ZZ_p& proj) { long n = F.n; if (m < 1 || m > n*ZZ_pE::degree()) Error("MinPoly: bad args"); vec_ZZ_pE R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); DoMinPolyTower(h, g, F, m, R, proj); } void MinPolyTower(ZZ_pX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pX h; ZZ_pEX h1; long n = F.n; if (m < 1 || m > n*ZZ_pE::degree()) Error("MinPoly: bad args"); vec_ZZ_p proj; PrecomputeProj(proj, ZZ_pE::modulus()); /* probabilistically compute min-poly */ ProbMinPolyTower(h, g, F, m, proj); if (deg(h) == m) { hh = h; return; } CompTower(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; ZZ_pX h2; ZZ_pEX h3; vec_ZZ_pE R; ZZ_pEXTransMultiplier H1; for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyTower(h2, g, F, m-deg(h), R, proj); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompTower(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { if (m < 1 || m > deg(F)*ZZ_pE::degree()) Error("IrredPoly: bad args"); vec_ZZ_pE R; R.SetLength(1); R[0] = 1; vec_ZZ_p proj; proj.SetLength(1); proj[0] = 1; DoMinPolyTower(h, g, F, m, R, proj); } NTL_END_IMPL ntl-6.2.1/src/ZZ_pEXFactoring.c000644 000765 000024 00000067424 12377144456 016557 0ustar00shoupstaff000000 000000 #include #include #include #include #include NTL_START_IMPL static void IterPower(ZZ_pE& c, const ZZ_pE& a, long n) { ZZ_pE res; long i; res = a; for (i = 0; i < n; i++) power(res, res, ZZ_p::modulus()); c = res; } void SquareFreeDecomp(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& ff) { ZZ_pEX f = ff; if (!IsOne(LeadCoeff(f))) Error("SquareFreeDecomp: bad args"); ZZ_pEX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long k, d; long p = to_long(ZZ_p::modulus()); d = deg(r)/p; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) IterPower(f.rep[k], r.rep[k*p], ZZ_pE::degree()-1); m = m*p; } } while (!finished); } static void AbsTraceMap(ZZ_pEX& h, const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX res, tmp; long k = NumBits(ZZ_pE::cardinality())-1; res = a; tmp = a; long i; for (i = 0; i < k-1; i++) { SqrMod(tmp, tmp, F); add(res, res, tmp); } h = res; } void FrobeniusMap(ZZ_pEX& h, const ZZ_pEXModulus& F) { PowerXMod(h, ZZ_pE::cardinality(), F); } static void RecFindRoots(vec_ZZ_pE& x, const ZZ_pEX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } ZZ_pEX h; ZZ_pEX r; { ZZ_pEXModulus F; build(F, f); do { random(r, deg(F)); if (IsOdd(ZZ_pE::cardinality())) { PowerMod(h, r, RightShift(ZZ_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_ZZ_pE& x, const ZZ_pEX& ff) { ZZ_pEX f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoots: bad args"); x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } void split(ZZ_pEX& f1, ZZ_pEX& g1, ZZ_pEX& f2, ZZ_pEX& g2, const ZZ_pEX& f, const ZZ_pEX& g, const vec_ZZ_pE& roots, long lo, long mid) { long r = mid-lo+1; ZZ_pEXModulus F; build(F, f); vec_ZZ_pE lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; ZZ_pEX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } void RecFindFactors(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& g, const vec_ZZ_pE& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } ZZ_pEX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } void FindFactors(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& g, const vec_ZZ_pE& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } void IterFindFactors(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& g, const vec_ZZ_pE& roots) { long r = roots.length(); long i; ZZ_pEX h; factors.SetLength(r); for (i = 0; i < r; i++) { sub(h, g, roots[i]); GCD(factors[i], f, h); } } void TraceMap(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& b) { if (d < 0) Error("TraceMap: bad args"); ZZ_pEX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(ZZ_pEX& y, const ZZ_pEX& h, long q, const ZZ_pEXModulus& F) { if (q < 0) Error("PowerCompose: bad args"); ZZ_pEX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const ZZ_pEX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; ZZ_pEXModulus F; build(F, f); ZZ_pEX b, r, s; FrobeniusMap(b, F); long all_zero = 1; long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); all_zero = all_zero && IsZero(s); if (deg(s) > 0) return 0; } if (!all_zero || (n & 1)) return 1; PowerCompose(s, b, n/2, F); return !IsX(s); } NTL_THREAD_LOCAL long ZZ_pEX_BlockingFactor = 10; void RootEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose) { vec_ZZ_pE roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); sub(factors[j], factors[j], roots[j]); } } void EDFSplit(vec_ZZ_pEX& v, const ZZ_pEX& f, const ZZ_pEX& b, long d) { ZZ_pEX a, g, h; ZZ_pEXModulus F; vec_ZZ_pE roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } void RecEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& b, long d, long verbose) { vec_ZZ_pEX v; long i; ZZ_pEX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { ZZ_pEX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_ZZ_pEX& factors, const ZZ_pEX& ff, const ZZ_pEX& bb, long d, long verbose) { ZZ_pEX f = ff; ZZ_pEX b = bb; if (!IsOne(LeadCoeff(f))) Error("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_ZZ_pEX& factors, const ZZ_pEX& ff, long verbose) { ZZ_pEX f = ff; if (!IsOne(LeadCoeff(f))) Error("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; ZZ_pEXModulus F; build(F, f); ZZ_pEX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } FrobeniusMap(h, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_ZZ_pEX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } ZZ_pEX hh; vec_ZZ_pEX v; long i; for (i = 0; i < u.length(); i++) { const ZZ_pEX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, long verbose) { if (!IsOne(LeadCoeff(f))) Error("CanZass: bad args"); double t; vec_pair_ZZ_pEX_long sfd; vec_ZZ_pEX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(ZZ_pEX& f, const vec_pair_ZZ_pEX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); ZZ_pEX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } long BaseCase(const ZZ_pEX& h, long q, long a, const ZZ_pEXModulus& F) { long b, e; ZZ_pEX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } void TandemPowerCompose(ZZ_pEX& y1, ZZ_pEX& y2, const ZZ_pEX& h, long q1, long q2, const ZZ_pEXModulus& F) { ZZ_pEX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } long RecComputeDegree(long u, const ZZ_pEX& h, const ZZ_pEXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); ZZ_pEX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long RecComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } void FindRoot(ZZ_pE& root, const ZZ_pEX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { ZZ_pEXModulus F; ZZ_pEX h, h1, f; ZZ_pEX r; f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoot: bad args"); if (deg(f) == 0) Error("FindRoot: bad args"); while (deg(f) > 1) { build(F, f); random(r, deg(F)); if (IsOdd(ZZ_pE::cardinality())) { PowerMod(h, r, RightShift(ZZ_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const ZZ_pEX& h, long q, long a, const ZZ_pEXModulus& F) { long e; ZZ_pEX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); sub(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const ZZ_pEX& h, const ZZ_pEXModulus& F, const FacVec& fvec) { long q1, q2; ZZ_pEX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const ZZ_pEX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; ZZ_pEXModulus F; build(F, f); ZZ_pEX h; FrobeniusMap(h, F); ZZ_pEX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const ZZ_pEX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; ZZ_pEXModulus F; build(F, f); ZZ_pEX h; FrobeniusMap(h, F); long CompTableSize = 2*SqrRoot(deg(f)); ZZ_pEXArgument H; build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; ZZ_pEX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { sub(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { CompMod(g, g, H, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_ZZ_pEX& h, const ZZ_pEX& f, const ZZ_pEX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { ZZ_pEX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); sub(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); sub(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(ZZ_pEX& x, const ZZ_pEX& f, const ZZ_pEX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_ZZ_pEX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_ZZ_pE a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(ZZ_pEX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(ZZ_pEX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { ZZ_pEX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(ZZ_pEX& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } #if 0 void BuildIrred(ZZ_pEX& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (n == 1) { SetX(f); return; } ZZ_pEX g; do { random(g, n); SetCoeff(g, n); } while (!IterIrredTest(g)); f = g; } #endif void BuildRandomIrred(ZZ_pEX& f, const ZZ_pEX& g) { ZZ_pEXModulus G; ZZ_pEX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_THREAD_LOCAL long ZZ_pEX_GCDTableSize = 4; NTL_THREAD_LOCAL char ZZ_pEX_stem[256] = ""; NTL_THREAD_LOCAL double ZZ_pEXFileThresh = NTL_FILE_THRESH; NTL_THREAD_LOCAL static vec_ZZ_pEX BabyStepFile; NTL_THREAD_LOCAL static vec_ZZ_pEX GiantStepFile; NTL_THREAD_LOCAL static long use_files; // FIXME: in a thread-safe impl, we should be careful // with external file names. static double CalcTableSize(long n, long k) { double sz = ZZ_p::storage(); sz = sz*ZZ_pE::degree(); sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz*n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_pE); sz = sz * k; sz = sz/1024; return sz; } static void GenerateBabySteps(ZZ_pEX& h1, const ZZ_pEX& f, const ZZ_pEX& h, long k, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } ZZ_pEXModulus F; build(F, f); ZZ_pEXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); h1 = h; long i; if (!use_files) { BabyStepFile.kill(); BabyStepFile.SetLength(k-1); } for (i = 1; i <= k-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName(ZZ_pEX_stem, "baby", i)); s << h1 << "\n"; s.close(); } else BabyStepFile(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const ZZ_pEX& f, const ZZ_pEX& h, long l, long verbose) { double t; if (verbose) { cerr << "generating giant steps..."; t = GetTime(); } ZZ_pEXModulus F; build(F, f); ZZ_pEXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); ZZ_pEX h1; h1 = h; long i; if (!use_files) { GiantStepFile.kill(); GiantStepFile.SetLength(l); } for (i = 1; i <= l-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName(ZZ_pEX_stem, "giant", i)); s << h1 << "\n"; s.close(); } else GiantStepFile(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (use_files) { ofstream s; OpenWrite(s, FileName(ZZ_pEX_stem, "giant", i)); s << h1 << "\n"; s.close(); } else GiantStepFile(i) = h1; if (verbose) cerr << (GetTime()-t) << "\n"; } static void FileCleanup(long k, long l) { if (use_files) { long i; for (i = 1; i <= k-1; i++) remove(FileName(ZZ_pEX_stem, "baby", i)); for (i = 1; i <= l; i++) remove(FileName(ZZ_pEX_stem, "giant", i)); } else { BabyStepFile.kill(); GiantStepFile.kill(); } } static void NewAddFactor(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_ZZ_pEX_long& u, ZZ_pEX& f, const ZZ_pEXModulus& F, vec_ZZ_pEX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; ZZ_pEX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(ZZ_pEX& g, long gs, const ZZ_pEXModulus& F) { if (use_files) { ifstream s; OpenRead(s, FileName(ZZ_pEX_stem, "giant", gs)); s >> g; s.close(); } else g = GiantStepFile(gs); rem(g, g, F); } static void FetchBabySteps(vec_ZZ_pEX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { if (use_files) { ifstream s; OpenRead(s, FileName(ZZ_pEX_stem, "baby", i)); s >> v[i]; s.close(); } else v[i] = BabyStepFile(i); } } static void GiantRefine(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_ZZ_pEX BabyStep; FetchBabySteps(BabyStep, k); vec_ZZ_pEX buf(INIT_SIZE, ZZ_pEX_GCDTableSize); ZZ_pEX f; f = ff; ZZ_pEXModulus F; build(F, f); ZZ_pEX g; ZZ_pEX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); sub(buf[size-1], g, BabyStep[bs]); } else { sub(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == ZZ_pEX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& ff, long k, long gs, const vec_ZZ_pEX& BabyStep, long verbose) { vec_ZZ_pEX buf(INIT_SIZE, ZZ_pEX_GCDTableSize); ZZ_pEX f; f = ff; ZZ_pEXModulus F; build(F, f); ZZ_pEX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); sub(buf[size], buf[size], g); size++; if (size == ZZ_pEX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_ZZ_pEX_long& factors, const vec_pair_ZZ_pEX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_ZZ_pEX BabyStep; long i; for (i = 0; i < u.length(); i++) { const ZZ_pEX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, const ZZ_pEX& h, long verbose) { if (!IsOne(LeadCoeff(f))) Error("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } if (!ZZ_pEX_stem[0]) sprintf(ZZ_pEX_stem, "ddf-%ld", RandomBnd(10000)); long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; ZZ_pEX h1; if (CalcTableSize(deg(f), k + l - 1) > ZZ_pEXFileThresh) use_files = 1; else use_files = 0; GenerateBabySteps(h1, f, h, k, verbose); GenerateGiantSteps(f, h1, l, verbose); vec_pair_ZZ_pEX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); FileCleanup(k, l); } long IterComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F) { long n = deg(F); if (n == 1 || IsX(h)) return 1; long B = n/2; long k = SqrRoot(B); long l = (B+k-1)/k; ZZ_pEXArgument H; #if 0 double n2 = sqrt(double(n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); ZZ_pEX h1; h1 = h; vec_ZZ_pEX baby; baby.SetLength(k); SetX(baby[0]); long i; for (i = 1; i <= k-1; i++) { baby[i] = h1; CompMod(h1, h1, H, F); if (IsX(h1)) return i+1; } build(H, h1, F, sz); long j; for (j = 2; j <= l; j++) { CompMod(h1, h1, H, F); for (i = k-1; i >= 0; i--) { if (h1 == baby[i]) return j*k-i; } } return n; } NTL_END_IMPL ntl-6.2.1/src/ZZ_pEXTest.c000644 000765 000024 00000001500 12377144457 015542 0ustar00shoupstaff000000 000000 #include #include NTL_CLIENT int main() { ZZ_p::init(to_ZZ(17)); ZZ_pX P; BuildIrred(P, 10); ZZ_pE::init(P); ZZ_pEX f, g, h; random(f, 20); SetCoeff(f, 20); random(h, 20); g = MinPolyMod(h, f); if (deg(g) < 0) Error("bad ZZ_pEXTest (1)"); if (CompMod(g, h, f) != 0) Error("bad ZZ_pEXTest (2)"); vec_pair_ZZ_pEX_long v; long i; for (i = 0; i < 5; i++) { long n = RandomBnd(20)+1; cerr << n << " "; random(f, n); SetCoeff(f, n); v = CanZass(f); g = mul(v); if (f != g) cerr << "oops1\n"; long i; for (i = 0; i < v.length(); i++) if (!DetIrredTest(v[i].a)) Error("bad ZZ_pEXTest (3)"); } cerr << "\n"; cerr << "ZZ_pEXTest OK\n"; } ntl-6.2.1/src/ZZ_pX.c000644 000765 000024 00000152276 12377144456 014615 0ustar00shoupstaff000000 000000 #include // The mul & sqr routines use routines from ZZX, // which is faster for small degree polynomials. // Define this macro to revert to old strategy. #ifndef NTL_WIZARD_HACK #include #endif #include #if (defined(NTL_GMP_LIP)) #define KARX 200 #else #define KARX 80 #endif NTL_START_IMPL const ZZ_pX& ZZ_pX::zero() { NTL_THREAD_LOCAL static ZZ_pX z; return z; } ZZ_pX& ZZ_pX::operator=(long a) { conv(*this, a); return *this; } ZZ_pX& ZZ_pX::operator=(const ZZ_p& a) { conv(*this, a); return *this; } istream& operator>>(istream& s, ZZ_pX& x) { s >> x.rep; x.normalize(); return s; } ostream& operator<<(ostream& s, const ZZ_pX& a) { return s << a.rep; } void ZZ_pX::normalize() { long n; const ZZ_p* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const ZZ_pX& a) { return a.rep.length() == 0; } long IsOne(const ZZ_pX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } void GetCoeff(ZZ_p& x, const ZZ_pX& a, long i) { if (i < 0 || i > deg(a)) clear(x); else x = a.rep[i]; } void SetCoeff(ZZ_pX& x, long i, const ZZ_p& a) { long j, m; if (i < 0) Error("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { NTL_ZZ_pRegister(aa); aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(ZZ_pX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else { NTL_ZZ_pRegister(T); conv(T, a); SetCoeff(x, i, T); } } void SetCoeff(ZZ_pX& x, long i) { long j, m; if (i < 0) Error("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(ZZ_pX& x) { clear(x); SetCoeff(x, 1); } long IsX(const ZZ_pX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const ZZ_p& coeff(const ZZ_pX& a, long i) { if (i < 0 || i > deg(a)) return ZZ_p::zero(); else return a.rep[i]; } const ZZ_p& LeadCoeff(const ZZ_pX& a) { if (IsZero(a)) return ZZ_p::zero(); else return a.rep[deg(a)]; } const ZZ_p& ConstTerm(const ZZ_pX& a) { if (IsZero(a)) return ZZ_p::zero(); else return a.rep[0]; } void conv(ZZ_pX& x, const ZZ_p& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; // note: if a aliases x.rep[i], i > 0, this code // will still work, since is is assumed that // SetLength(1) will not relocate or destroy x.rep[i] } } void conv(ZZ_pX& x, long a) { if (a == 0) clear(x); else if (a == 1) set(x); else { NTL_ZZ_pRegister(T); conv(T, a); conv(x, T); } } void conv(ZZ_pX& x, const ZZ& a) { if (IsZero(a)) clear(x); else { NTL_ZZ_pRegister(T); conv(T, a); conv(x, T); } } void conv(ZZ_pX& x, const vec_ZZ_p& a) { x.rep = a; x.normalize(); } void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ_p *ap, *bp; ZZ_p* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_p *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_p *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(ZZ_pX& x, const ZZ_pX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ_p *ap, *bp; ZZ_p* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_p *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_p *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(ZZ_pX& x, const ZZ_pX& a, long b) { if (b == 0) { x = a; return; } if (a.rep.length() == 0) { x.rep.SetLength(1); x.rep[0] = b; negate(x.rep[0], x.rep[0]); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); } x.normalize(); } void sub(ZZ_pX& x, const ZZ_p& a, const ZZ_pX& b) { NTL_ZZ_pRegister(T); T = a; negate(x, b); add(x, x, T); } void sub(ZZ_pX& x, long a, const ZZ_pX& b) { NTL_ZZ_pRegister(T); T = a; negate(x, b); add(x, x, T); } void negate(ZZ_pX& x, const ZZ_pX& a) { long n = a.rep.length(); x.rep.SetLength(n); const ZZ_p* ap = a.rep.elts(); ZZ_p* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } #ifndef NTL_WIZARD_HACK // These crossovers are tuned for a Pentium, but hopefully // they should be OK on other machines as well. const long SS_kbound = 40; const double SS_rbound = 1.25; void mul(ZZ_pX& c, const ZZ_pX& a, const ZZ_pX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { sqr(c, a); return; } long k = ZZ_p::ModulusSize(); long s = min(deg(a), deg(b)) + 1; if (s == 1 || (k == 1 && s < 40) || (k == 2 && s < 20) || (k == 3 && s < 12) || (k <= 5 && s < 8) || (k <= 12 && s < 4) ) { PlainMul(c, a, b); } else if (s < KARX) { ZZX A, B, C; conv(A, a); conv(B, b); KarMul(C, A, B); conv(c, C); } else { long mbits; mbits = NumBits(ZZ_p::modulus()); if (k >= SS_kbound && SSRatio(deg(a), mbits, deg(b), mbits) < SS_rbound) { ZZX A, B, C; conv(A, a); conv(B, b); SSMul(C, A, B); conv(c, C); } else { FFTMul(c, a, b); } } } void sqr(ZZ_pX& c, const ZZ_pX& a) { if (IsZero(a)) { clear(c); return; } long k = ZZ_p::ModulusSize(); long s = deg(a) + 1; if (s == 1 || (k == 1 && s < 50) || (k == 2 && s < 25) || (k == 3 && s < 25) || (k <= 6 && s < 12) || (k <= 8 && s < 8) || (k == 9 && s < 6) || (k <= 30 && s < 4) ) { PlainSqr(c, a); } else if (s < 80) { ZZX C, A; conv(A, a); KarSqr(C, A); conv(c, C); } else { long mbits; mbits = NumBits(ZZ_p::modulus()); if (k >= SS_kbound && SSRatio(deg(a), mbits, deg(a), mbits) < SS_rbound) { ZZX A, C; conv(A, a); SSSqr(C, A); conv(c, C); } else { FFTSqr(c, a); } } } #else void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { if (&a == &b) { sqr(x, a); return; } if (deg(a) > NTL_ZZ_pX_FFT_CROSSOVER && deg(b) > NTL_ZZ_pX_FFT_CROSSOVER) FFTMul(x, a, b); else PlainMul(x, a, b); } void sqr(ZZ_pX& x, const ZZ_pX& a) { if (deg(a) > NTL_ZZ_pX_FFT_CROSSOVER) FFTSqr(x, a); else PlainSqr(x, a); } #endif void PlainMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } if (da == 0) { mul(x, b, a.rep[0]); return; } if (db == 0) { mul(x, a, b.rep[0]); return; } long d = da+db; const ZZ_p *ap, *bp; ZZ_p *xp; ZZ_pX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; NTL_ZZRegister(t); NTL_ZZRegister(accum); for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(bp[i-j])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void PlainSqr(ZZ_pX& x, const ZZ_pX& a) { long da = deg(a); if (da < 0) { clear(x); return; } long d = 2*da; const ZZ_p *ap; ZZ_p *xp; ZZ_pX la; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; long m, m2; NTL_ZZRegister(t); NTL_ZZRegister(accum); for (i = 0; i <= d; i++) { jmin = max(0, i-da); jmax = min(da, i); m = jmax - jmin + 1; m2 = m >> 1; jmax = jmin + m2 - 1; clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(ap[i-j])); add(accum, accum, t); } add(accum, accum, accum); if (m & 1) { sqr(t, rep(ap[jmax + 1])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void PlainDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ_p *qp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZ_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } ZZVec x(da + 1, ZZ_pInfo->ExtendedModulusSize); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b, ZZVec& x) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b, ZZVec& x) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ_p *qp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZ_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDiv(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ_p *qp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pX: division by zero"); if (da < db) { clear(q); return; } ZZ_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } ZZVec x(da + 1 - db, ZZ_pInfo->ExtendedModulusSize); for (i = db; i <= da; i++) x[i-db] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j-db], xp[i+j-db], s); } } } void PlainRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) Error("ZZ_pX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } ZZVec x(da + 1, ZZ_pInfo->ExtendedModulusSize); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b) { if (IsZero(b)) { clear(x); return; } if (IsOne(b)) { x = a; return; } NTL_ZZ_pRegister(t); long i, da; const ZZ_p *ap; ZZ_p* xp; t = b; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(ZZ_pX& x, const ZZ_pX& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); mul(x, a, T); } void PlainGCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { ZZ_p t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; ZZ_pX u(INIT_SIZE, n), v(INIT_SIZE, n); ZZVec tmp(n, ZZ_pInfo->ExtendedModulusSize); u = a; v = b; do { PlainRem(u, u, v, tmp); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } void PlainXGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b) { ZZ_p z; if (IsZero(b)) { set(s); clear(t); d = a; } else if (IsZero(a)) { clear(s); set(t); d = b; } else { long e = max(deg(a), deg(b)) + 1; ZZ_pX temp(INIT_SIZE, e), u(INIT_SIZE, e), v(INIT_SIZE, e), u0(INIT_SIZE, e), v0(INIT_SIZE, e), u1(INIT_SIZE, e), v1(INIT_SIZE, e), u2(INIT_SIZE, e), v2(INIT_SIZE, e), q(INIT_SIZE, e); set(u1); clear(v1); clear(u2); set(v2); u = a; v = b; do { DivRem(q, u, u, v); swap(u, v); u0 = u2; v0 = v2; mul(temp, q, u2); sub(u2, u1, temp); mul(temp, q, v2); sub(v2, v1, temp); u1 = u0; v1 = v0; } while (!IsZero(v)); d = u; s = u1; t = v1; } if (IsZero(d)) return; if (IsOne(LeadCoeff(d))) return; /* make gcd monic */ inv(z, LeadCoeff(d)); mul(d, d, z); mul(s, s, z); mul(t, t, z); } void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) Error("MulMod: bad args"); ZZ_pX t; mul(t, a, b); rem(x, t, f); } void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("SqrMod: bad args"); ZZ_pX t; sqr(t, a); rem(x, t, f); } void InvMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvMod: bad args"); ZZ_pX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) Error("ZZ_pX InvMod: can't compute multiplicative inverse"); } long InvModStatus(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvModStatus: bad args"); ZZ_pX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } static void MulByXModAux(ZZ_pX& h, const ZZ_pX& a, const ZZ_pX& f) { long i, n, m; ZZ_p* hh; const ZZ_p *aa, *ff; ZZ_p t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) Error("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(ZZ_pX& h, const ZZ_pX& a, const ZZ_pX& f) { if (&h == &f) { ZZ_pX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void random(ZZ_pX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void FFTRep::SetSize(long NewK) { if (NewK < -1 || NewK >= NTL_BITS_PER_LONG-1) Error("bad arg to FFTRep::SetSize()"); if (NewK <= MaxK) { k = NewK; return; } ZZ_pInfo->check(); if (MaxK == -1) NumPrimes = ZZ_pInfo->NumPrimes; else { if (NumPrimes != ZZ_pInfo->NumPrimes) Error("FFTRep: inconsistent use"); } long i, n; if (MaxK == -1) { tbl = (long **) NTL_MALLOC(NumPrimes, sizeof(long *), 0); if (!tbl) Error("out of space in FFTRep::SetSize()"); } else { for (i = 0; i < NumPrimes; i++) free(tbl[i]); } n = 1L << NewK; for (i = 0; i < NumPrimes; i++) { if ( !(tbl[i] = (long *) NTL_MALLOC(n, sizeof(long), 0)) ) Error("out of space in FFTRep::SetSize()"); } k = MaxK = NewK; } FFTRep::FFTRep(const FFTRep& R) { k = MaxK = R.k; tbl = 0; NumPrimes = 0; if (k < 0) return; NumPrimes = R.NumPrimes; long i, j, n; tbl = (long **) NTL_MALLOC(NumPrimes, sizeof(long *), 0); if (!tbl) Error("out of space in FFTRep"); n = 1L << k; for (i = 0; i < NumPrimes; i++) { if ( !(tbl[i] = (long *) NTL_MALLOC(n, sizeof(long), 0)) ) Error("out of space in FFTRep"); for (j = 0; j < n; j++) tbl[i][j] = R.tbl[i][j]; } } FFTRep& FFTRep::operator=(const FFTRep& R) { if (this == &R) return *this; if (MaxK >= 0 && R.MaxK >= 0 && NumPrimes != R.NumPrimes) Error("FFTRep: inconsistent use"); if (R.k < 0) { k = -1; return *this; } NumPrimes = R.NumPrimes; if (R.k > MaxK) { long i, n; if (MaxK == -1) { tbl = (long **) NTL_MALLOC(NumPrimes, sizeof(long *), 0); if (!tbl) Error("out of space in FFTRep"); } else { for (i = 0; i < NumPrimes; i++) free(tbl[i]); } n = 1L << R.k; for (i = 0; i < NumPrimes; i++) { if ( !(tbl[i] = (long *) NTL_MALLOC(n, sizeof(long), 0)) ) Error("out of space in FFTRep"); } k = MaxK = R.k; } else { k = R.k; } long i, j, n; n = 1L << k; for (i = 0; i < NumPrimes; i++) for (j = 0; j < n; j++) tbl[i][j] = R.tbl[i][j]; return *this; } FFTRep::~FFTRep() { if (MaxK == -1) return; for (long i = 0; i < NumPrimes; i++) free(tbl[i]); free(tbl); } void ZZ_pXModRep::SetSize(long NewN) { ZZ_pInfo->check(); NumPrimes = ZZ_pInfo->NumPrimes; if (NewN < 0) Error("bad arg to ZZ_pXModRep::SetSize()"); if (NewN <= MaxN) { n = NewN; return; } long i; if (MaxN == 0) { tbl = (long **) NTL_MALLOC(ZZ_pInfo->NumPrimes, sizeof(long *), 0); if (!tbl) Error("out of space in ZZ_pXModRep::SetSize()"); } else { for (i = 0; i < ZZ_pInfo->NumPrimes; i++) free(tbl[i]); } for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { if ( !(tbl[i] = (long *) NTL_MALLOC(NewN, sizeof(long), 0)) ) Error("out of space in ZZ_pXModRep::SetSize()"); } n = MaxN = NewN; } ZZ_pXModRep::~ZZ_pXModRep() { if (MaxN == 0) return; long i; for (i = 0; i < NumPrimes; i++) free(tbl[i]); free(tbl); } NTL_THREAD_LOCAL static vec_long ModularRepBuf; // FIXME: I may want to consider putting this in // the thread local scratch space associated with ZZ_p contexts. void ToModularRep(vec_long& x, const ZZ_p& a) { ZZ_pInfo->check(); ZZ_p_rem_struct_eval(ZZ_pInfo->rem_struct, &x[0], rep(a)); } // NOTE: earlier versions used Kahan summation... // we no longer do this, as it is less portable than I thought. void FromModularRep(ZZ_p& x, const vec_long& a) { ZZ_pInfo->check(); long n = ZZ_pInfo->NumPrimes; NTL_ZZRegister(q); NTL_ZZRegister(s); NTL_ZZRegister(t); long i; double y; if (ZZ_p_crt_struct_special(ZZ_pInfo->crt_struct)) { ZZ_p_crt_struct_eval(ZZ_pInfo->crt_struct, t, &a[0]); x.LoopHole() = t; return; } if (ZZ_pInfo->QuickCRT) { y = 0; for (i = 0; i < n; i++) y += ((double) a[i])*ZZ_pInfo->x[i]; conv(q, (y + 0.5)); } else { long Q, r; NTL_ZZRegister(qq); y = 0; clear(q); for (i = 0; i < n; i++) { r = MulDivRem(Q, a[i], ZZ_pInfo->u[i], FFTPrime[i], ZZ_pInfo->x[i]); add(q, q, Q); y += r*FFTPrimeInv[i]; } conv(qq, (y + 0.5)); add(q, q, qq); } ZZ_p_crt_struct_eval(ZZ_pInfo->crt_struct, t, &a[0]); mul(s, q, ZZ_pInfo->MinusMModP); add(t, t, s); conv(x, t); } void ToFFTRep(FFTRep& y, const ZZ_pX& x, long k, long lo, long hi) // computes an n = 2^k point convolution. // if deg(x) >= 2^k, then x is first reduced modulo X^n-1. { ZZ_pInfo->check(); long n, i, j, m, j1; vec_long& t = ModularRepBuf; ZZ_p accum; if (k > ZZ_pInfo->MaxRoot) Error("Polynomial too big for FFT"); if (lo < 0) Error("bad arg to ToFFTRep"); t.SetLength(ZZ_pInfo->NumPrimes); hi = min(hi, deg(x)); y.SetSize(k); n = 1L << k; m = max(hi-lo + 1, 0); const ZZ_p *xx = x.rep.elts(); for (j = 0; j < n; j++) { if (j >= m) { for (i = 0; i < ZZ_pInfo->NumPrimes; i++) y.tbl[i][j] = 0; } else { accum = xx[j+lo]; for (j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); ToModularRep(t, accum); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { y.tbl[i][j] = t[i]; } } } // FIXME: something to think about...part of the above logic // is essentially a matrix transpose, which could lead to bad // cache performance. I don't really know if that is an issue. for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTFwd(yp, yp, k, i); } } void RevToFFTRep(FFTRep& y, const vec_ZZ_p& x, long k, long lo, long hi, long offset) // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. { ZZ_pInfo->check(); long n, i, j, m, j1; vec_long& t = ModularRepBuf; ZZ_p accum; if (k > ZZ_pInfo->MaxRoot) Error("Polynomial too big for FFT"); if (lo < 0) Error("bad arg to ToFFTRep"); t.SetLength(ZZ_pInfo->NumPrimes); hi = min(hi, x.length()-1); y.SetSize(k); n = 1L << k; m = max(hi-lo + 1, 0); const ZZ_p *xx = x.elts(); offset = offset & (n-1); for (j = 0; j < n; j++) { if (j >= m) { for (i = 0; i < ZZ_pInfo->NumPrimes; i++) y.tbl[i][offset] = 0; } else { accum = xx[j+lo]; for (j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); ToModularRep(t, accum); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { y.tbl[i][offset] = t[i]; } } offset = (offset + 1) & (n-1); } for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } } void FromFFTRep(ZZ_pX& x, FFTRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { ZZ_pInfo->check(); long k, n, i, j, l; vec_long& t = ModularRepBuf; t.SetLength(ZZ_pInfo->NumPrimes); k = y.k; n = (1L << k); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.rep.SetLength(l); for (j = 0; j < l; j++) { for (i = 0; i < ZZ_pInfo->NumPrimes; i++) t[i] = y.tbl[i][j+lo]; FromModularRep(x.rep[j], t); } x.normalize(); } void RevFromFFTRep(vec_ZZ_p& x, FFTRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // using "inverted" evaluation points. // only the coefficients lo..hi are computed { ZZ_pInfo->check(); long k, n, i, j, l; vec_long& t = ModularRepBuf; k = y.k; n = (1L << k); t.SetLength(ZZ_pInfo->NumPrimes); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTFwd(yp, yp, k, i); } hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.SetLength(l); for (j = 0; j < l; j++) { for (i = 0; i < ZZ_pInfo->NumPrimes; i++) t[i] = y.tbl[i][j+lo]; FromModularRep(x[j], t); } } void NDFromFFTRep(ZZ_pX& x, const FFTRep& y, long lo, long hi, FFTRep& z) { ZZ_pInfo->check(); long k, n, i, j, l; vec_long& t = ModularRepBuf; t.SetLength(ZZ_pInfo->NumPrimes); k = y.k; n = (1L << k); z.SetSize(k); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *yp = &y.tbl[i][0]; FFTRev1(zp, yp, k, i); } hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.rep.SetLength(l); for (j = 0; j < l; j++) { for (i = 0; i < ZZ_pInfo->NumPrimes; i++) t[i] = z.tbl[i][j+lo]; FromModularRep(x.rep[j], t); } x.normalize(); } void NDFromFFTRep(ZZ_pX& x, FFTRep& y, long lo, long hi) { FFTRep z; NDFromFFTRep(x, y, lo, hi, z); } void FromFFTRep(ZZ_p* x, FFTRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { ZZ_pInfo->check(); long k, n, i, j; vec_long& t = ModularRepBuf; k = y.k; n = (1L << k); t.SetLength(ZZ_pInfo->NumPrimes); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } for (j = lo; j <= hi; j++) { if (j >= n) clear(x[j-lo]); else { for (i = 0; i < ZZ_pInfo->NumPrimes; i++) t[i] = y.tbl[i][j]; FromModularRep(x[j-lo], t); } } } void mul(FFTRep& z, const FFTRep& x, const FFTRep& y) { ZZ_pInfo->check(); long k, n, i, j; if (x.k != y.k) Error("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = FFTPrime[i]; double qinv = ((double) 1)/((double) q); for (j = 0; j < n; j++) zp[j] = MulMod(xp[j], yp[j], q, qinv); } } void sub(FFTRep& z, const FFTRep& x, const FFTRep& y) { ZZ_pInfo->check(); long k, n, i, j; if (x.k != y.k) Error("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = FFTPrime[i]; for (j = 0; j < n; j++) zp[j] = SubMod(xp[j], yp[j], q); } } void add(FFTRep& z, const FFTRep& x, const FFTRep& y) { ZZ_pInfo->check(); long k, n, i, j; if (x.k != y.k) Error("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = FFTPrime[i]; for (j = 0; j < n; j++) zp[j] = AddMod(xp[j], yp[j], q); } } void reduce(FFTRep& x, const FFTRep& a, long k) // reduces a 2^l point FFT-rep to a 2^k point FFT-rep // input may alias output { ZZ_pInfo->check(); long i, j, l, n; long* xp; const long* ap; l = a.k; n = 1L << k; if (l < k) Error("reduce: bad operands"); x.SetSize(k); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { ap = &a.tbl[i][0]; xp = &x.tbl[i][0]; for (j = 0; j < n; j++) xp[j] = ap[j << (l-k)]; } } void AddExpand(FFTRep& x, const FFTRep& a) // x = x + (an "expanded" version of a) { ZZ_pInfo->check(); long i, j, l, k, n; l = x.k; k = a.k; n = 1L << k; if (l < k) Error("AddExpand: bad args"); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) { long q = FFTPrime[i]; const long *ap = &a.tbl[i][0]; long *xp = &x.tbl[i][0]; for (j = 0; j < n; j++) { long j1 = j << (l-k); xp[j1] = AddMod(xp[j1], ap[j], q); } } } void ToZZ_pXModRep(ZZ_pXModRep& y, const ZZ_pX& x, long lo, long hi) { ZZ_pInfo->check(); long n, i, j; vec_long& t = ModularRepBuf; t.SetLength(ZZ_pInfo->NumPrimes); if (lo < 0) Error("bad arg to ToZZ_pXModRep"); hi = min(hi, deg(x)); n = max(hi-lo+1, 0); y.SetSize(n); const ZZ_p *xx = x.rep.elts(); for (j = 0; j < n; j++) { ToModularRep(t, xx[j+lo]); for (i = 0; i < ZZ_pInfo->NumPrimes; i++) y.tbl[i][j] = t[i]; } } void ToFFTRep(FFTRep& x, const ZZ_pXModRep& a, long k, long lo, long hi) { ZZ_pInfo->check(); vec_long s; long n, m, i, j; if (k < 0 || lo < 0) Error("bad args to ToFFTRep"); if (hi > a.n-1) hi = a.n-1; n = 1L << k; m = max(hi-lo+1, 0); if (m > n) Error("bad args to ToFFTRep"); s.SetLength(n); long *sp = s.elts(); x.SetSize(k); long NumPrimes = ZZ_pInfo->NumPrimes; for (i = 0; i < NumPrimes; i++) { long *xp = &x.tbl[i][0]; long *ap = (m == 0 ? 0 : &a.tbl[i][0]); for (j = 0; j < m; j++) sp[j] = ap[lo+j]; for (j = m; j < n; j++) sp[j] = 0; FFTFwd(xp, sp, k, i); } } void FFTMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { long k, d; if (IsZero(a) || IsZero(b)) { clear(x); return; } d = deg(a) + deg(b); k = NextPowerOfTwo(d+1); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); ToFFTRep(R1, a, k); ToFFTRep(R2, b, k); mul(R1, R1, R2); FromFFTRep(x, R1, 0, d); } void FFTSqr(ZZ_pX& x, const ZZ_pX& a) { long k, d; if (IsZero(a)) { clear(x); return; } d = 2*deg(a); k = NextPowerOfTwo(d+1); FFTRep R1(INIT_SIZE, k); ToFFTRep(R1, a, k); mul(R1, R1, R1); FromFFTRep(x, R1, 0, d); } void CopyReverse(ZZ_pX& x, const ZZ_pX& a, long lo, long hi) // x[0..hi-lo] = reverse(a[lo..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const ZZ_p* ap = a.rep.elts(); ZZ_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void copy(ZZ_pX& x, const ZZ_pX& a, long lo, long hi) // x[0..hi-lo] = a[lo..hi], with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const ZZ_p* ap = a.rep.elts(); ZZ_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = lo + i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void rem21(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long i, da, ds, n, kk; da = deg(a); n = F.n; if (da > 2*n-2) Error("bad args to rem(ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (da < n) { x = a; return; } if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainRem(x, a, F.f); return; } FFTRep R1(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep(R1, a, F.l, n, 2*(n-1)); mul(R1, R1, F.HRep); FromFFTRep(P1, R1, n-2, 2*n-4); ToFFTRep(R1, P1, F.k); mul(R1, R1, F.FRep); FromFFTRep(P1, R1, 0, n-1); ds = deg(P1); kk = 1L << F.k; x.rep.SetLength(n); const ZZ_p* aa = a.rep.elts(); const ZZ_p* ss = P1.rep.elts(); ZZ_p* xx = x.rep.elts(); for (i = 0; i < n; i++) { if (i <= ds) sub(xx[i], aa[i], ss[i]); else xx[i] = aa[i]; if (i + kk <= da) add(xx[i], xx[i], aa[i+kk]); } x.normalize(); } void DivRem21(ZZ_pX& q, ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long i, da, ds, n, kk; da = deg(a); n = F.n; if (da > 2*n-2) Error("bad args to rem(ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (da < n) { x = a; clear(q); return; } if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainDivRem(q, x, a, F.f); return; } FFTRep R1(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n), qq; ToFFTRep(R1, a, F.l, n, 2*(n-1)); mul(R1, R1, F.HRep); FromFFTRep(P1, R1, n-2, 2*n-4); qq = P1; ToFFTRep(R1, P1, F.k); mul(R1, R1, F.FRep); FromFFTRep(P1, R1, 0, n-1); ds = deg(P1); kk = 1L << F.k; x.rep.SetLength(n); const ZZ_p* aa = a.rep.elts(); const ZZ_p* ss = P1.rep.elts(); ZZ_p* xx = x.rep.elts(); for (i = 0; i < n; i++) { if (i <= ds) sub(xx[i], aa[i], ss[i]); else xx[i] = aa[i]; if (i + kk <= da) add(xx[i], xx[i], aa[i+kk]); } x.normalize(); q = qq; } void div21(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long da, n; da = deg(a); n = F.n; if (da > 2*n-2) Error("bad args to rem(ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (da < n) { clear(x); return; } if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainDiv(x, a, F.f); return; } FFTRep R1(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep(R1, a, F.l, n, 2*(n-1)); mul(R1, R1, F.HRep); FromFFTRep(x, R1, n-2, 2*n-4); } void rem(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) Error("rem: unitialized modulus"); if (da <= 2*n-2) { rem21(x, a, F); return; } else if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainRem(x, a, F.f); return; } ZZ_pX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); rem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) Error("uninitialized modulus"); if (da <= 2*n-2) { DivRem21(q, r, a, F); return; } else if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainDivRem(q, r, a, F.f); return; } ZZ_pX buf(INIT_SIZE, 2*n-1); ZZ_pX qbuf(INIT_SIZE, n-1); ZZ_pX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); DivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) Error("uninitialized modulus"); if (da <= 2*n-2) { div21(q, a, F); return; } else if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainDiv(q, a, F.f); return; } ZZ_pX buf(INIT_SIZE, 2*n-1); ZZ_pX qbuf(INIT_SIZE, n-1); ZZ_pX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) DivRem21(qbuf, buf, buf, F); else div21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F) { long da, db, d, n, k; da = deg(a); db = deg(b); n = F.n; if (n < 0) Error("MulMod: uninitialized modulus"); if (da >= n || db >= n) Error("bad args to MulMod(ZZ_pX,ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (da < 0 || db < 0) { clear(x); return; } if (!F.UseFFT || da <= NTL_ZZ_pX_FFT_CROSSOVER || db <= NTL_ZZ_pX_FFT_CROSSOVER) { ZZ_pX P1; mul(P1, a, b); rem(x, P1, F); return; } d = da + db + 1; k = NextPowerOfTwo(d); k = max(k, F.k); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep(R1, a, k); ToFFTRep(R2, b, k); mul(R1, R1, R2); NDFromFFTRep(P1, R1, n, d-1, R2); // save R1 for future use ToFFTRep(R2, P1, F.l); mul(R2, R2, F.HRep); FromFFTRep(P1, R2, n-2, 2*n-4); ToFFTRep(R2, P1, F.k); mul(R2, R2, F.FRep); reduce(R1, R1, F.k); sub(R1, R1, R2); FromFFTRep(x, R1, 0, n-1); } void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long da, d, n, k; da = deg(a); n = F.n; if (n < 0) Error("SqrMod: uninitailized modulus"); if (da >= n) Error("bad args to SqrMod(ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (!F.UseFFT || da <= NTL_ZZ_pX_FFT_CROSSOVER) { ZZ_pX P1; sqr(P1, a); rem(x, P1, F); return; } d = 2*da + 1; k = NextPowerOfTwo(d); k = max(k, F.k); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep(R1, a, k); mul(R1, R1, R1); NDFromFFTRep(P1, R1, n, d-1, R2); // save R1 for future use ToFFTRep(R2, P1, F.l); mul(R2, R2, F.HRep); FromFFTRep(P1, R2, n-2, 2*n-4); ToFFTRep(R2, P1, F.k); mul(R2, R2, F.FRep); reduce(R1, R1, F.k); sub(R1, R1, R2); FromFFTRep(x, R1, 0, n-1); } void PlainInvTrunc(ZZ_pX& x, const ZZ_pX& a, long m) /* x = (1/a) % X^m, input not output, constant term a is nonzero */ { long i, k, n, lb; NTL_ZZRegister(v); NTL_ZZRegister(t); ZZ_p s; const ZZ_p* ap; ZZ_p* xp; n = deg(a); if (n < 0) Error("division by zero"); inv(s, ConstTerm(a)); if (n == 0) { conv(x, s); return; } ap = a.rep.elts(); x.rep.SetLength(m); xp = x.rep.elts(); xp[0] = s; long is_one = IsOne(s); for (k = 1; k < m; k++) { clear(v); lb = max(k-n, 0); for (i = lb; i <= k-1; i++) { mul(t, rep(xp[i]), rep(ap[k-i])); add(v, v, t); } conv(xp[k], v); negate(xp[k], xp[k]); if (!is_one) mul(xp[k], xp[k], s); } x.normalize(); } void trunc(ZZ_pX& x, const ZZ_pX& a, long m) // x = a % X^m, output may alias input { if (m < 0) Error("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; ZZ_p* xp; const ZZ_p* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void CyclicReduce(ZZ_pX& x, const ZZ_pX& a, long m) // computes x = a mod X^m-1 { long n = deg(a); long i, j; ZZ_p accum; if (n < m) { x = a; return; } if (&x != &a) x.rep.SetLength(m); for (i = 0; i < m; i++) { accum = a.rep[i]; for (j = i + m; j <= n; j += m) add(accum, accum, a.rep[j]); x.rep[i] = accum; } if (&x == &a) x.rep.SetLength(m); x.normalize(); } void InvTrunc(ZZ_pX& x, const ZZ_pX& a, long m) { if (m < 0) Error("InvTrunc: bad args"); if (m == 0) { clear(x); return; } if (NTL_OVERFLOW(m, 1, 0)) Error("overflow in InvTrunc"); if (&x == &a) { ZZ_pX la; la = a; if (m > NTL_ZZ_pX_NEWTON_CROSSOVER && deg(a) > 0) NewtonInvTrunc(x, la, m); else PlainInvTrunc(x, la, m); } else { if (m > NTL_ZZ_pX_NEWTON_CROSSOVER && deg(a) > 0) NewtonInvTrunc(x, a, m); else PlainInvTrunc(x, a, m); } } void build(ZZ_pXModulus& x, const ZZ_pX& f) { x.f = f; x.n = deg(f); x.tracevec.SetLength(0); if (x.n <= 0) Error("build: deg(f) must be at least 1"); if (x.n <= NTL_ZZ_pX_FFT_CROSSOVER + 1) { x.UseFFT = 0; return; } x.UseFFT = 1; x.k = NextPowerOfTwo(x.n); x.l = NextPowerOfTwo(2*x.n - 3); ToFFTRep(x.FRep, f, x.k); ZZ_pX P1(INIT_SIZE, x.n+1), P2(INIT_SIZE, x.n); CopyReverse(P1, f, 0, x.n); InvTrunc(P2, P1, x.n-1); CopyReverse(P1, P2, 0, x.n-2); ToFFTRep(x.HRep, P1, x.l); } ZZ_pXModulus::ZZ_pXModulus(const ZZ_pX& ff) { build(*this, ff); } ZZ_pXMultiplier::ZZ_pXMultiplier(const ZZ_pX& b, const ZZ_pXModulus& F) { build(*this, b, F); } void build(ZZ_pXMultiplier& x, const ZZ_pX& b, const ZZ_pXModulus& F) { long db; long n = F.n; if (n < 0) Error("build ZZ_pXMultiplier: uninitialized modulus"); x.b = b; db = deg(b); if (db >= n) Error("build ZZ_pXMultiplier: deg(b) >= deg(f)"); if (!F.UseFFT || db <= NTL_ZZ_pX_FFT_CROSSOVER) { x.UseFFT = 0; return; } x.UseFFT = 1; FFTRep R1(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep(R1, b, F.l); reduce(x.B2, R1, F.k); mul(R1, R1, F.HRep); FromFFTRep(P1, R1, n-1, 2*n-3); ToFFTRep(x.B1, P1, F.l); } void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F) { long n = F.n; long da; da = deg(a); if (da >= n) Error(" bad args to MulMod(ZZ_pX,ZZ_pX,ZZ_pXMultiplier,ZZ_pXModulus)"); if (da < 0) { clear(x); return; } if (!B.UseFFT || !F.UseFFT || da <= NTL_ZZ_pX_FFT_CROSSOVER) { ZZ_pX P1; mul(P1, a, B.b); rem(x, P1, F); return; } ZZ_pX P1(INIT_SIZE, n), P2(INIT_SIZE, n); FFTRep R1(INIT_SIZE, F.l), R2(INIT_SIZE, F.l); ToFFTRep(R1, a, F.l); mul(R2, R1, B.B1); FromFFTRep(P1, R2, n-1, 2*n-3); reduce(R1, R1, F.k); mul(R1, R1, B.B2); ToFFTRep(R2, P1, F.k); mul(R2, R2, F.FRep); sub(R1, R1, R2); FromFFTRep(x, R1, 0, n-1); } void PowerXMod(ZZ_pX& hh, const ZZ& e, const ZZ_pXModulus& F) { if (F.n < 0) Error("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; ZZ_pX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) MulByXMod(h, h, F); } if (e < 0) InvMod(h, h, F); hh = h; } void PowerXPlusAMod(ZZ_pX& hh, const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F) { if (F.n < 0) Error("PowerXPlusAMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } ZZ_pX t1(INIT_SIZE, F.n), t2(INIT_SIZE, F.n); long n = NumBits(e); long i; ZZ_pX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) { MulByXMod(t1, h, F); mul(t2, h, a); add(h, t1, t2); } } if (e < 0) InvMod(h, h, F); hh = h; } void PowerMod(ZZ_pX& h, const ZZ_pX& g, const ZZ& e, const ZZ_pXModulus& F) { if (deg(g) >= F.n) Error("PowerMod: bad args"); if (IsZero(e)) { set(h); return; } ZZ_pXMultiplier G; ZZ_pX res; long n = NumBits(e); long i; build(G, g, F); res.SetMaxLength(F.n); set(res); for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, G, F); } if (e < 0) InvMod(res, res, F); h = res; } void NewtonInvTrunc(ZZ_pX& x, const ZZ_pX& a, long m) { x.SetMaxLength(m); long i, t, k; long log2_newton = NextPowerOfTwo(NTL_ZZ_pX_NEWTON_CROSSOVER)-1; PlainInvTrunc(x, a, 1L << log2_newton); t = NextPowerOfTwo(m); FFTRep R1(INIT_SIZE, t), R2(INIT_SIZE, t); ZZ_pX P1(INIT_SIZE, m/2); long a_len = min(m, a.rep.length()); ZZ_pXModRep a_rep; ToZZ_pXModRep(a_rep, a, 0, a_len-1); k = 1L << log2_newton; t = log2_newton; while (k < m) { long l = min(2*k, m); ToFFTRep(R1, x, t+1); ToFFTRep(R2, a_rep, t+1, 0, l-1); mul(R2, R2, R1); FromFFTRep(P1, R2, k, l-1); ToFFTRep(R2, P1, t+1); mul(R2, R2, R1); FromFFTRep(P1, R2, 0, l-k-1); x.rep.SetLength(l); long y_len = P1.rep.length(); for (i = k; i < l; i++) { if (i-k >= y_len) clear(x.rep[i]); else negate(x.rep[i], P1.rep[i-k]); } x.normalize(); t++; k = l; } } void FFTDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { long n = deg(b); long m = deg(a); long k, l; if (m < n) { clear(q); r = a; return; } if (m >= 3*n) { ZZ_pXModulus B; build(B, b); DivRem(q, r, a, B); return; } ZZ_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); long k1 = NextPowerOfTwo(n); long mx = max(k1, k); FFTRep R1(INIT_SIZE, mx), R2(INIT_SIZE, mx); ToFFTRep(R1, P1, k); ToFFTRep(R2, a, k, n, m); mul(R1, R1, R2); FromFFTRep(P3, R1, m-n, 2*(m-n)); l = 1L << k1; ToFFTRep(R1, b, k1); ToFFTRep(R2, P3, k1); mul(R1, R1, R2); FromFFTRep(P1, R1, 0, n-1); CyclicReduce(P2, a, l); trunc(r, P2, n); sub(r, r, P1); q = P3; } void FFTDiv(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b) { long n = deg(b); long m = deg(a); long k; if (m < n) { clear(q); return; } if (m >= 3*n) { ZZ_pXModulus B; build(B, b); div(q, a, B); return; } ZZ_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); ToFFTRep(R1, P1, k); ToFFTRep(R2, a, k, n, m); mul(R1, R1, R2); FromFFTRep(q, R1, m-n, 2*(m-n)); } void FFTRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { long n = deg(b); long m = deg(a); long k, l; if (m < n) { r = a; return; } if (m >= 3*n) { ZZ_pXModulus B; build(B, b); rem(r, a, B); return; } ZZ_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); long k1 = NextPowerOfTwo(n); long mx = max(k, k1); FFTRep R1(INIT_SIZE, mx), R2(INIT_SIZE, mx); ToFFTRep(R1, P1, k); ToFFTRep(R2, a, k, n, m); mul(R1, R1, R2); FromFFTRep(P3, R1, m-n, 2*(m-n)); l = 1L << k1; ToFFTRep(R1, b, k1); ToFFTRep(R2, P3, k1); mul(R1, R1, R2); FromFFTRep(P3, R1, 0, n-1); CyclicReduce(P2, a, l); trunc(r, P2, n); sub(r, r, P3); } void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { if (deg(b) > NTL_ZZ_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_ZZ_pX_DIV_CROSSOVER) FFTDivRem(q, r, a, b); else PlainDivRem(q, r, a, b); } void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b) { if (deg(b) > NTL_ZZ_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_ZZ_pX_DIV_CROSSOVER) FFTDiv(q, a, b); else PlainDiv(q, a, b); } void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_p& b) { NTL_ZZ_pRegister(T); inv(T, b); mul(q, a, T); } void div(ZZ_pX& q, const ZZ_pX& a, long b) { NTL_ZZ_pRegister(T); T = b; inv(T, T); mul(q, a, T); } void rem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { if (deg(b) > NTL_ZZ_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_ZZ_pX_DIV_CROSSOVER) FFTRem(r, a, b); else PlainRem(r, a, b); } long operator==(const ZZ_pX& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); long da = deg(a); if (da > 0) return 0; NTL_ZZ_pRegister(bb); bb = b; if (da < 0) return IsZero(bb); return a.rep[0] == bb; } long operator==(const ZZ_pX& a, const ZZ_p& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } void power(ZZ_pX& x, const ZZ_pX& a, long e) { if (e < 0) { Error("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) Error("overflow in power"); ZZ_pX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } void reverse(ZZ_pX& x, const ZZ_pX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) Error("overflow in reverse"); if (&x == &a) { ZZ_pX tmp; CopyReverse(tmp, a, 0, hi); x = tmp; } else CopyReverse(x, a, 0, hi); } NTL_END_IMPL ntl-6.2.1/src/ZZ_pX1.c000644 000765 000024 00000105211 12377144456 014661 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } ZZ_pX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const ZZ_pX& a, const ZZ_pX& b) { if (IsZero(b)) return IsZero(a); ZZ_pX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } void ZZ_pXMatrix::operator=(const ZZ_pXMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } void RightShift(ZZ_pX& x, const ZZ_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) Error("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void ShiftAdd(ZZ_pX& U, const ZZ_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) add(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void ShiftSub(ZZ_pX& U, const ZZ_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void mul(ZZ_pX& U, ZZ_pX& V, const ZZ_pXMatrix& M) // (U, V)^T = M*(U, V)^T { long d = deg(U) - deg(M(1,1)); long k = NextPowerOfTwo(d - 1); // When the GCD algorithm is run on polynomials of degree n, n-1, // where n is a power of two, then d-1 is likely to be a power of two. // It would be more natural to set k = NextPowerOfTwo(d+1), but this // would be much less efficient in this case. // We optimize this case, as it does sometimes arise naturally // in some situations. long n = (1L << k); long xx; ZZ_p a0, a1, b0, b1, c0, d0, u0, u1, v0, v1, nu0, nu1, nv0; NTL_ZZRegister(t1); NTL_ZZRegister(t2); if (n == d-1) xx = 1; else if (n == d) xx = 2; else xx = 3; switch (xx) { case 1: GetCoeff(a0, M(0,0), 0); GetCoeff(a1, M(0,0), 1); GetCoeff(b0, M(0,1), 0); GetCoeff(b1, M(0,1), 1); GetCoeff(c0, M(1,0), 0); GetCoeff(d0, M(1,1), 0); GetCoeff(u0, U, 0); GetCoeff(u1, U, 1); GetCoeff(v0, V, 0); GetCoeff(v1, V, 1); mul(t1, rep(a0), rep(u0)); mul(t2, rep(b0), rep(v0)); add(t1, t1, t2); conv(nu0, t1); mul(t1, rep(a1), rep(u0)); mul(t2, rep(a0), rep(u1)); add(t1, t1, t2); mul(t2, rep(b1), rep(v0)); add(t1, t1, t2); mul(t2, rep(b0), rep(v1)); add(t1, t1, t2); conv(nu1, t1); mul(t1, rep(c0), rep(u0)); mul(t2, rep(d0), rep(v0)); add (t1, t1, t2); conv(nv0, t1); break; case 2: GetCoeff(a0, M(0,0), 0); GetCoeff(b0, M(0,1), 0); GetCoeff(u0, U, 0); GetCoeff(v0, V, 0); mul(t1, rep(a0), rep(u0)); mul(t2, rep(b0), rep(v0)); add(t1, t1, t2); conv(nu0, t1); break; case 3: break; } FFTRep RU(INIT_SIZE, k), RV(INIT_SIZE, k), R1(INIT_SIZE, k), R2(INIT_SIZE, k); ToFFTRep(RU, U, k); ToFFTRep(RV, V, k); ToFFTRep(R1, M(0,0), k); mul(R1, R1, RU); ToFFTRep(R2, M(0,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromFFTRep(U, R1, 0, d); ToFFTRep(R1, M(1,0), k); mul(R1, R1, RU); ToFFTRep(R2, M(1,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromFFTRep(V, R1, 0, d-1); // now fix-up results switch (xx) { case 1: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d-1, u0); SetCoeff(U, 0, nu0); GetCoeff(u1, U, 1); sub(u1, u1, nu1); SetCoeff(U, d, u1); SetCoeff(U, 1, nu1); GetCoeff(v0, V, 0); sub(v0, v0, nv0); SetCoeff(V, d-1, v0); SetCoeff(V, 0, nv0); break; case 2: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d, u0); SetCoeff(U, 0, nu0); break; } } void mul(ZZ_pXMatrix& A, ZZ_pXMatrix& B, ZZ_pXMatrix& C) // A = B*C, B and C are destroyed { long db = deg(B(1,1)); long dc = deg(C(1,1)); long da = db + dc; long k = NextPowerOfTwo(da+1); FFTRep B00, B01, B10, B11, C0, C1, T1, T2; ToFFTRep(B00, B(0,0), k); B(0,0).kill(); ToFFTRep(B01, B(0,1), k); B(0,1).kill(); ToFFTRep(B10, B(1,0), k); B(1,0).kill(); ToFFTRep(B11, B(1,1), k); B(1,1).kill(); ToFFTRep(C0, C(0,0), k); C(0,0).kill(); ToFFTRep(C1, C(1,0), k); C(1,0).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromFFTRep(A(0,0), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromFFTRep(A(1,0), T1, 0, da); ToFFTRep(C0, C(0,1), k); C(0,1).kill(); ToFFTRep(C1, C(1,1), k); C(1,1).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromFFTRep(A(0,1), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromFFTRep(A(1,1), T1, 0, da); } void IterHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; ZZVec tmp(deg(U)+1, ZZ_pInfo->ExtendedModulusSize); ZZ_pX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { PlainDivRem(Q, U, U, V, tmp); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } void HalfGCD(ZZ_pXMatrix& M_out, const ZZ_pX& U, const ZZ_pX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; ZZ_pX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } ZZ_pX Q; ZZ_pXMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } ZZ_pX Q; ZZ_pXMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void HalfGCD(ZZ_pX& U, ZZ_pX& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); ZZ_pX Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(ZZ_pX& d, const ZZ_pX& u, const ZZ_pX& v) { ZZ_pX u1, v1; u1 = u; v1 = v; if (deg(u1) == deg(v1)) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (deg(u1) < deg(v1)) { swap(u1, v1); } // deg(u1) > deg(v1) while (deg(u1) > NTL_ZZ_pX_GCD_CROSSOVER && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } } PlainGCD(d, u1, v1); } void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b) { ZZ_p w; if (IsZero(a) && IsZero(b)) { clear(d); set(s); clear(t); return; } ZZ_pX U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } ZZ_pXMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize inv(w, LeadCoeff(d)); mul(d, d, w); mul(s, s, w); mul(t, t, w); } void IterBuild(ZZ_p* a, long n) { long i, k; ZZ_p b, t; if (n <= 0) return; negate(a[0], a[0]); for (k = 1; k <= n-1; k++) { negate(b, a[k]); add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void mul(ZZ_p* x, const ZZ_p* a, const ZZ_p* b, long n) { NTL_ZZRegister(t); NTL_ZZRegister(accum); long i, j, jmin, jmax; long d = 2*n-1; for (i = 0; i <= d; i++) { jmin = max(0, i-(n-1)); jmax = min(n-1, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(a[j]), rep(b[i-j])); add(accum, accum, t); } if (i >= n) { add(accum, accum, rep(a[i-n])); add(accum, accum, rep(b[i-n])); } conv(x[i], accum); } } void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a) { long n = a.length(); if (n == 0) { set(x); return; } long k0 = NextPowerOfTwo(NTL_ZZ_pX_FFT_CROSSOVER); long crossover = 1L << k0; if (n <= crossover) { x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); return; } long k = NextPowerOfTwo(n); long m = 1L << k; long i, j; long l, width; ZZ_pX b(INIT_SIZE, m+1); b.rep = a; b.rep.SetLength(m+1); for (i = n; i < m; i++) clear(b.rep[i]); set(b.rep[m]); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); ZZ_p t1, one; set(one); vec_ZZ_p G(INIT_SIZE, crossover), H(INIT_SIZE, crossover); ZZ_p *g = G.elts(); ZZ_p *h = H.elts(); ZZ_p *tmp; for (i = 0; i < m; i+= crossover) { for (j = 0; j < crossover; j++) negate(g[j], b.rep[i+j]); if (k0 > 0) { for (j = 0; j < crossover; j+=2) { mul(t1, g[j], g[j+1]); add(g[j+1], g[j], g[j+1]); g[j] = t1; } } for (l = 1; l < k0; l++) { width = 1L << l; for (j = 0; j < crossover; j += 2*width) mul(&h[j], &g[j], &g[j+width], width); tmp = g; g = h; h = tmp; } for (j = 0; j < crossover; j++) b.rep[i+j] = g[j]; } for (l = k0; l < k; l++) { width = 1L << l; for (i = 0; i < m; i += 2*width) { t1 = b.rep[i+width]; set(b.rep[i+width]); ToFFTRep(R1, b, l+1, i, i+width); b.rep[i+width] = t1; t1 = b.rep[i+2*width]; set(b.rep[i+2*width]); ToFFTRep(R2, b, l+1, i+width, i+2*width); b.rep[i+2*width] = t1; mul(R1, R1, R2); FromFFTRep(&b.rep[i], R1, 0, 2*width-1); sub(b.rep[i], b.rep[i], one); } } x.rep.SetLength(n+1); long delta = m-n; for (i = 0; i <= n; i++) x.rep[i] = b.rep[i+delta]; // no need to normalize } void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a) // does a Horner evaluation { ZZ_p acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_ZZ_p bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b) { long m = a.length(); if (b.length() != m) Error("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_ZZ_p prod; prod = a; ZZ_p t1, t2; long k, i; vec_ZZ_p res; res.SetLength(m); for (k = 0; k < m; k++) { const ZZ_p& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(ZZ_pX& x, const vec_ZZ_p& v, long low, long high, const vec_ZZ_pX& H, long n, ZZVec& t) { NTL_ZZRegister(s); long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_ZZ_p& h = H[i-low].rep; long m = h.length(); const ZZ& w = rep(v[i]); for (j = 0; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) conv(x.rep[j], t[j]); x.normalize(); } void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& A, const ZZ_pXModulus& F) { if (deg(g) <= 0) { x = g; return; } ZZ_pX s, t; ZZVec scratch(F.n, ZZ_pInfo->ExtendedModulusSize); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; ZZ_pXMultiplier M; build(M, A.H[m], F); InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(ZZ_pXArgument& A, const ZZ_pX& h, const ZZ_pXModulus& F, long m) { if (m <= 0 || deg(h) >= F.n) Error("build: bad args"); if (m > F.n) m = F.n; long i; if (ZZ_pXArgBound > 0) { double sz = ZZ_p::storage(); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz/1024; m = min(m, long(ZZ_pXArgBound/sz)); m = max(m, 1); } ZZ_pXMultiplier M; build(M, h, F); A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], M, F); } NTL_THREAD_LOCAL long ZZ_pXArgBound = 0; void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } ZZ_pXArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& h, const ZZ_pXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } ZZ_pXArgument A; build(A, h, F, m); ZZ_pX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3, const ZZ_pX& h, const ZZ_pXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } ZZ_pXArgument A; build(A, h, F, m); ZZ_pX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } static void StripZeroes(vec_ZZ_p& x) { long n = x.length(); while (n > 0 && IsZero(x[n-1])) n--; x.SetLength(n); } void PlainUpdateMap(vec_ZZ_p& xx, const vec_ZZ_p& a, const ZZ_pX& b, const ZZ_pX& f) { long n = deg(f); long i, m; if (IsZero(b)) { xx.SetLength(0); return; } m = n-1 - deg(b); vec_ZZ_p x(INIT_SIZE, n); for (i = 0; i <= m; i++) InnerProduct(x[i], a, b.rep, i); if (deg(b) != 0) { ZZ_pX c(INIT_SIZE, n); LeftShift(c, b, m); for (i = m+1; i < n; i++) { MulByXMod(c, c, f); InnerProduct(x[i], a, c.rep); } } xx = x; } void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& aa, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F) { long n = F.n; long i; vec_ZZ_p a; a = aa; StripZeroes(a); if (a.length() > n) Error("UpdateMap: bad args"); if (!B.UseFFT) { PlainUpdateMap(x, a, B.b, F.f); StripZeroes(x); return; } FFTRep R1(INIT_SIZE, F.k), R2(INIT_SIZE, F.l); vec_ZZ_p V1(INIT_SIZE, n); RevToFFTRep(R1, a, F.k, 0, a.length()-1, 0); mul(R2, R1, F.FRep); RevFromFFTRep(V1, R2, 0, n-2); for (i = 0; i <= n-2; i++) negate(V1[i], V1[i]); RevToFFTRep(R2, V1, F.l, 0, n-2, n-1); mul(R2, R2, B.B1); mul(R1, R1, B.B2); AddExpand(R2, R1); RevFromFFTRep(x, R2, 0, n-1); StripZeroes(x); } void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F) { long n = F.n; if (a.length() > n || k < 0 || NTL_OVERFLOW(k, 1, 0)) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; ZZ_pXMultiplier M; build(M, H.H[m], F); vec_ZZ_p s(INIT_SIZE, n); s = a; StripZeroes(s); x.SetLength(k); for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); ZZ_p* w = &x[i*m]; for (long j = 0; j < m1; j++) InnerProduct(w[j], H.H[j].rep, s); if (i < l) UpdateMap(s, s, M, F); } } void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F) { if (a.length() > F.n || k < 0) Error("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); ZZ_pXArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void BerlekampMassey(ZZ_pX& h, const vec_ZZ_p& a, long m) { ZZ_pX Lambda, Sigma, Temp; long L; ZZ_p Delta, Delta1, t1; long shamt; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(Delta1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(t1, Lambda.rep[i], a[r-i-1]); add(Delta1, Delta1, t1); } if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftSub(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftSub(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void GCDMinPolySeq(ZZ_pX& h, const vec_ZZ_p& x, long m) { long i; ZZ_pX a, b; ZZ_pXMatrix M; ZZ_p t; a.rep.SetLength(2*m); for (i = 0; i < 2*m; i++) a.rep[i] = x[2*m-1-i]; a.normalize(); SetCoeff(b, 2*m); HalfGCD(M, b, a, m+1); /* make monic */ inv(t, LeadCoeff(M(1,1))); mul(h, M(1,1), t); } void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) Error("MinPoly: bad args"); if (a.length() < 2*m) Error("MinPoly: sequence too short"); if (m > NTL_ZZ_pX_BERMASS_CROSSOVER) GCDMinPolySeq(h, a, m); else BerlekampMassey(h, a, m); } void DoMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m, const vec_ZZ_p& R) { vec_ZZ_p x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) Error("ProbMinPoly: bad args"); long i; vec_ZZ_p R(INIT_SIZE, n); for (i = 0; i < n; i++) random(R[i]); DoMinPolyMod(h, g, F, m, R); } void MinPolyMod(ZZ_pX& hh, const ZZ_pX& g, const ZZ_pXModulus& F, long m) { ZZ_pX h, h1; long n = F.n; if (m < 1 || m > n) Error("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; ZZ_pX h2, h3; ZZ_pXMultiplier H1; vec_ZZ_p R(INIT_SIZE, n); for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, H1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m) { vec_ZZ_p R(INIT_SIZE, 1); if (m < 1 || m > F.n) Error("IrredPoly: bad args"); set(R[0]); DoMinPolyMod(h, g, F, m, R); } void diff(ZZ_pX& x, const ZZ_pX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void MakeMonic(ZZ_pX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; ZZ_p t; inv(t, LeadCoeff(x)); mul(x, x, t); } void PlainMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n) { ZZ_pX y; mul(y, a, b); trunc(x, y, n); } void FFTMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n) { if (IsZero(a) || IsZero(b)) { clear(x); return; } long d = deg(a) + deg(b); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); ToFFTRep(R1, a, k); ToFFTRep(R2, b, k); mul(R1, R1, R2); FromFFTRep(x, R1, 0, n-1); } void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n) { if (n < 0) Error("MulTrunc: bad args"); if (deg(a) <= NTL_ZZ_pX_FFT_CROSSOVER || deg(b) <= NTL_ZZ_pX_FFT_CROSSOVER) PlainMulTrunc(x, a, b, n); else FFTMulTrunc(x, a, b, n); } void PlainSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n) { ZZ_pX y; sqr(y, a); trunc(x, y, n); } void FFTSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n) { if (IsZero(a)) { clear(x); return; } long d = 2*deg(a); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); FFTRep R1(INIT_SIZE, k); ToFFTRep(R1, a, k); mul(R1, R1, R1); FromFFTRep(x, R1, 0, n-1); } void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n) { if (n < 0) Error("SqrTrunc: bad args"); if (deg(a) <= NTL_ZZ_pX_FFT_CROSSOVER) PlainSqrTrunc(x, a, n); else FFTSqrTrunc(x, a, n); } void FastTraceVec(vec_ZZ_p& S, const ZZ_pX& f) { long n = deg(f); if (n <= 0) Error("FastTraceVec: bad args"); if (n == 0) { S.SetLength(0); return; } if (n == 1) { S.SetLength(1); set(S[0]); return; } long i; ZZ_pX f1; f1.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) f1.rep[i] = f.rep[n-i]; f1.normalize(); ZZ_pX f2; f2.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) mul(f2.rep[i], f.rep[n-1-i], i+1); f2.normalize(); ZZ_pX f3; InvTrunc(f3, f1, n-1); MulTrunc(f3, f3, f2, n-1); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(f3, i-1)); } void PlainTraceVec(vec_ZZ_p& S, const ZZ_pX& ff) { if (deg(ff) <= 0) Error("TraceVec: bad args"); ZZ_pX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; ZZ acc, t; ZZ_p t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } } void TraceVec(vec_ZZ_p& S, const ZZ_pX& f) { if (deg(f) <= NTL_ZZ_pX_TRACE_CROSSOVER) PlainTraceVec(S, f); else FastTraceVec(S, f); } void ComputeTraceVec(const ZZ_pXModulus& F) { vec_ZZ_p& S = *((vec_ZZ_p *) &F.tracevec); if (S.length() > 0) return; if (!F.UseFFT) { PlainTraceVec(S, F.f); return; } long i; long n = F.n; FFTRep R; ZZ_pX P, g; g.rep.SetLength(n-1); for (i = 1; i < n; i++) mul(g.rep[n-i-1], F.f.rep[n-i], i); g.normalize(); ToFFTRep(R, g, F.l); mul(R, R, F.HRep); FromFFTRep(P, R, n-2, 2*n-4); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(P, n-1-i)); } void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long n = F.n; if (deg(a) >= n) Error("trace: bad args"); // FIXME: in a thread safe version, we should use // some kind of mutex if (F.tracevec.length() == 0) ComputeTraceVec(F); InnerProduct(x, a.rep, F.tracevec); } void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) Error("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(ZZ_p& rres, const ZZ_pX& a, const ZZ_pX& b) { ZZ_p res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; ZZ_p lc; set(res); long n = max(deg(a),deg(b)) + 1; ZZ_pX u(INIT_SIZE, n), v(INIT_SIZE, n); ZZVec tmp(n, ZZ_pInfo->ExtendedModulusSize); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v, tmp); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } } rres = res; } void ResIterHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red, vec_ZZ_p& cvec, vec_long& dvec) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; ZZVec tmp(deg(U)+1, ZZ_pInfo->ExtendedModulusSize); ZZ_pX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { append(cvec, LeadCoeff(V)); append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V)); PlainDivRem(Q, U, U, V, tmp); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } void ResHalfGCD(ZZ_pXMatrix& M_out, const ZZ_pX& U, const ZZ_pX& V, long d_red, vec_ZZ_p& cvec, vec_long& dvec) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; ZZ_pX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) { ResIterHalfGCD(M_out, U1, V1, d_red, cvec, dvec); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; ResHalfGCD(M1, U1, V1, d1, cvec, dvec); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } ZZ_pX Q; ZZ_pXMatrix M2; append(cvec, LeadCoeff(V1)); append(dvec, dvec[dvec.length()-1]-deg(U1)+deg(V1)); DivRem(Q, U1, U1, V1); swap(U1, V1); ResHalfGCD(M2, U1, V1, d2, cvec, dvec); ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void ResHalfGCD(ZZ_pX& U, ZZ_pX& V, vec_ZZ_p& cvec, vec_long& dvec) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; ResHalfGCD(M1, U, V, d1, cvec, dvec); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); ZZ_pX Q; append(cvec, LeadCoeff(V)); append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V)); DivRem(Q, U, U, V); swap(U, V); ResHalfGCD(M1, U, V, d2, cvec, dvec); mul(U, V, M1); } void resultant(ZZ_p& rres, const ZZ_pX& u, const ZZ_pX& v) { if (deg(u) <= NTL_ZZ_pX_GCD_CROSSOVER || deg(v) <= NTL_ZZ_pX_GCD_CROSSOVER) { PlainResultant(rres, u, v); return; } ZZ_pX u1, v1; u1 = u; v1 = v; ZZ_p res, t; set(res); if (deg(u1) == deg(v1)) { rem(u1, u1, v1); swap(u1, v1); if (IsZero(v1)) { clear(rres); return; } power(t, LeadCoeff(u1), deg(u1) - deg(v1)); mul(res, res, t); if (deg(u1) & 1) negate(res, res); } else if (deg(u1) < deg(v1)) { swap(u1, v1); if (deg(u1) & deg(v1) & 1) negate(res, res); } // deg(u1) > deg(v1) && v1 != 0 vec_ZZ_p cvec; vec_long dvec; cvec.SetMaxLength(deg(v1)+2); dvec.SetMaxLength(deg(v1)+2); append(cvec, LeadCoeff(u1)); append(dvec, deg(u1)); while (deg(u1) > NTL_ZZ_pX_GCD_CROSSOVER && !IsZero(v1)) { ResHalfGCD(u1, v1, cvec, dvec); if (!IsZero(v1)) { append(cvec, LeadCoeff(v1)); append(dvec, deg(v1)); rem(u1, u1, v1); swap(u1, v1); } } if (IsZero(v1) && deg(u1) > 0) { clear(rres); return; } long i, l; l = dvec.length(); if (deg(u1) == 0) { // we went all the way... for (i = 0; i <= l-3; i++) { power(t, cvec[i+1], dvec[i]-dvec[i+2]); mul(res, res, t); if (dvec[i] & dvec[i+1] & 1) negate(res, res); } power(t, cvec[l-1], dvec[l-2]); mul(res, res, t); } else { for (i = 0; i <= l-3; i++) { power(t, cvec[i+1], dvec[i]-dvec[i+2]); mul(res, res, t); if (dvec[i] & dvec[i+1] & 1) negate(res, res); } power(t, cvec[l-1], dvec[l-2]-deg(v1)); mul(res, res, t); if (dvec[l-2] & dvec[l-1] & 1) negate(res, res); PlainResultant(t, u1, v1); mul(res, res, t); } rres = res; } void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) Error("norm: bad args"); if (IsZero(a)) { clear(x); return; } ZZ_p t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { ZZ_p t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } NTL_END_IMPL ntl-6.2.1/src/ZZ_pXCharPoly.c000644 000765 000024 00000002246 12377144456 016246 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL static void HessCharPoly(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& f) { long n = deg(f); if (n <= 0 || deg(a) >= n) Error("HessCharPoly: bad args"); mat_ZZ_p M; M.SetDims(n, n); long i, j; ZZ_pX t; t = a; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) M[i][j] = coeff(t, j); if (i < n-1) MulByXMod(t, t, f); } CharPoly(g, M); } void CharPolyMod(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& ff) { ZZ_pX f = ff; MakeMonic(f); long n = deg(f); if (n <= 0 || deg(a) >= n) Error("CharPoly: bad args"); if (IsZero(a)) { clear(g); SetCoeff(g, n); return; } if (n > 25) { ZZ_pX h; MinPolyMod(h, a, f); if (deg(h) == n) { g = h; return; } } if (ZZ_p::modulus() < n+1) { HessCharPoly(g, a, f); return; } vec_ZZ_p u(INIT_SIZE, n+1), v(INIT_SIZE, n+1); ZZ_pX h, h1; negate(h, a); long i; for (i = 0; i <= n; i++) { u[i] = i; add(h1, h, u[i]); resultant(v[i], f, h1); } interpolate(g, u, v); } NTL_END_IMPL ntl-6.2.1/src/ZZ_pXFactoring.c000644 000765 000024 00000103133 12377144456 016436 0ustar00shoupstaff000000 000000 #include #include #include #include #include #include NTL_START_IMPL void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& ff) { ZZ_pX f = ff; if (!IsOne(LeadCoeff(f))) Error("SquareFreeDecomp: bad args"); ZZ_pX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long p, k, d; conv(p, ZZ_p::modulus()); d = deg(r)/p; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) f.rep[k] = r.rep[k*p]; m = m*p; } } while (!finished); } static void NullSpace(long& r, vec_long& D, vec_ZZVec& M, long verbose) { long k, l, n; long i, j; long pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); n = M.length(); D.SetLength(n); for (j = 0; j < n; j++) D[j] = -1; r = 0; l = 0; for (k = 0; k < n; k++) { if (verbose && k % 10 == 0) cerr << "+"; pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { swap(M[pos], M[l]); // make M[l, k] == -1 mod p, and make row l reduced InvMod(t1, M[l][k], p); NegateMod(t1, t1, p); for (j = k+1; j < n; j++) { rem(t2, M[l][j], p); MulMod(M[l][j], t2, t1, p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } D[k] = l; // variable k is defined by row l l++; } else { r++; } } } static void BuildMatrix(vec_ZZVec& M, long n, const ZZ_pX& g, const ZZ_pXModulus& F, long verbose) { long i, j, m; ZZ_pXMultiplier G; ZZ_pX h; ZZ t; sqr(t, ZZ_p::modulus()); mul(t, t, n); long size = t.size(); M.SetLength(n); for (i = 0; i < n; i++) M[i].SetSize(n, size); build(G, g, F); set(h); for (j = 0; j < n; j++) { if (verbose && j % 10 == 0) cerr << "+"; m = deg(h); for (i = 0; i < n; i++) { if (i <= m) M[i][j] = rep(h.rep[i]); else clear(M[i][j]); } if (j < n-1) MulMod(h, h, G, F); } for (i = 0; i < n; i++) AddMod(M[i][i], M[i][i], -1, ZZ_p::modulus()); } static void RecFindRoots(vec_ZZ_p& x, const ZZ_pX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } ZZ_pX h; ZZ_p r; ZZ p1; RightShift(p1, ZZ_p::modulus(), 1); { ZZ_pXModulus F; build(F, f); do { random(r); PowerXPlusAMod(h, r, p1, F); add(h, h, -1); GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_ZZ_p& x, const ZZ_pX& ff) { ZZ_pX f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoots: bad args"); x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } static void RandomBasisElt(ZZ_pX& g, const vec_long& D, const vec_ZZVec& M) { ZZ t1, t2; long n = D.length(); long i, j, s; g.rep.SetLength(n); vec_ZZ_p& v = g.rep; for (j = n-1; j >= 0; j--) { if (D[j] == -1) random(v[j]); else { i = D[j]; // v[j] = sum_{s=j+1}^{n-1} v[s]*M[i,s] clear(t1); for (s = j+1; s < n; s++) { mul(t2, rep(v[s]), M[i][s]); add(t1, t1, t2); } conv(v[j], t1); } } g.normalize(); } static void split(ZZ_pX& f1, ZZ_pX& g1, ZZ_pX& f2, ZZ_pX& g2, const ZZ_pX& f, const ZZ_pX& g, const vec_ZZ_p& roots, long lo, long mid) { long r = mid-lo+1; ZZ_pXModulus F; build(F, f); vec_ZZ_p lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; ZZ_pX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } static void RecFindFactors(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& g, const vec_ZZ_p& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } ZZ_pX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } static void FindFactors(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& g, const vec_ZZ_p& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } #if 0 static void IterFindFactors(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& g, const vec_ZZ_p& roots) { long r = roots.length(); long i; ZZ_pX h; factors.SetLength(r); for (i = 0; i < r; i++) { sub(h, g, roots[i]); GCD(factors[i], f, h); } } #endif void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& ff, long verbose) { ZZ_pX f = ff; if (!IsOne(LeadCoeff(f))) Error("SFBerlekamp: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } double t; const ZZ& p = ZZ_p::modulus(); long n = deg(f); ZZ_pXModulus F; build(F, f); ZZ_pX g, h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(g, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_long D; long r; vec_ZZVec M; if (verbose) { cerr << "building matrix..."; t = GetTime(); } BuildMatrix(M, n, g, F, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "diagonalizing..."; t = GetTime(); } NullSpace(r, D, M, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) cerr << "number of factors = " << r << "\n"; if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (verbose) { cerr << "factor extraction..."; t = GetTime(); } vec_ZZ_p roots; RandomBasisElt(g, D, M); MinPolyMod(h, g, F, r); if (deg(h) == r) M.kill(); FindRoots(roots, h); FindFactors(factors, f, g, roots); ZZ_pX g1; vec_ZZ_pX S, S1; long i; while (factors.length() < r) { if (verbose) cerr << "+"; RandomBasisElt(g, D, M); S.kill(); for (i = 0; i < factors.length(); i++) { const ZZ_pX& f = factors[i]; if (deg(f) == 1) { append(S, f); continue; } build(F, f); rem(g1, g, F); if (deg(g1) <= 0) { append(S, f); continue; } MinPolyMod(h, g1, F, min(deg(f), r-factors.length()+1)); FindRoots(roots, h); S1.kill(); FindFactors(S1, f, g1, roots); append(S, S1); } swap(factors, S); } if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "degrees:"; long i; for (i = 0; i < factors.length(); i++) cerr << " " << deg(factors[i]); cerr << "\n"; } } void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose) { double t; vec_pair_ZZ_pX_long sfd; vec_ZZ_pX x; if (!IsOne(LeadCoeff(f))) Error("berlekamp: bad args"); if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFBerlekamp(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } static void AddFactor(vec_pair_ZZ_pX_long& factors, const ZZ_pX& g, long d, long verbose) { if (verbose) cerr << "degree=" << d << ", number=" << deg(g)/d << "\n"; append(factors, cons(g, d)); } static void ProcessTable(ZZ_pX& f, vec_pair_ZZ_pX_long& factors, const ZZ_pXModulus& F, long limit, const vec_ZZ_pX& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; ZZ_pX t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); ZZ_pX t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); } void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& b) { if (d < 0) Error("TraceMap: bad args"); ZZ_pX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(ZZ_pX& y, const ZZ_pX& h, long q, const ZZ_pXModulus& F) { if (q < 0) Error("PowerCompose: bad args"); ZZ_pX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const ZZ_pX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; const ZZ& p = ZZ_p::modulus(); ZZ_pXModulus F; build(F, f); ZZ_pX b, r, s; PowerXMod(b, p, F); long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); if (deg(s) > 0) return 0; } if (p >= n) return 1; long pp; conv(pp, p); if (n % pp != 0) return 1; PowerCompose(s, b, n/pp, F); return !IsX(s); } NTL_THREAD_LOCAL long ZZ_pX_BlockingFactor = 10; void DDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& ff, const ZZ_pX& hh, long verbose) { ZZ_pX f = ff; ZZ_pX h = hh; if (!IsOne(LeadCoeff(f))) Error("DDF: bad args"); factors.SetLength(0); if (deg(f) == 0) return; if (deg(f) == 1) { AddFactor(factors, f, 1, verbose); return; } long CompTableSize = 2*SqrRoot(deg(f)); long GCDTableSize = ZZ_pX_BlockingFactor; ZZ_pXModulus F; build(F, f); ZZ_pXArgument H; build(H, h, F, min(CompTableSize, deg(f))); long i, d, limit, old_n; ZZ_pX g, X; vec_ZZ_pX tbl(INIT_SIZE, GCDTableSize); SetX(X); i = 0; g = h; d = 1; limit = GCDTableSize; while (2*d <= deg(f)) { old_n = deg(f); sub(tbl[i], g, X); i++; if (i == limit) { ProcessTable(f, factors, F, i, tbl, d, verbose); i = 0; } d = d + 1; if (2*d <= deg(f)) { // we need to go further if (deg(f) < old_n) { // f has changed build(F, f); rem(h, h, f); rem(g, g, f); build(H, h, F, min(CompTableSize, deg(f))); } CompMod(g, g, H, F); } } ProcessTable(f, factors, F, i, tbl, d-1, verbose); if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose); } void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose) { vec_ZZ_p roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); sub(factors[j], factors[j], roots[j]); } } static void EDFSplit(vec_ZZ_pX& v, const ZZ_pX& f, const ZZ_pX& b, long d) { ZZ_pX a, g, h; ZZ_pXModulus F; vec_ZZ_p roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } static void RecEDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& b, long d, long verbose) { vec_ZZ_pX v; long i; ZZ_pX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { ZZ_pX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_ZZ_pX& factors, const ZZ_pX& ff, const ZZ_pX& bb, long d, long verbose) { ZZ_pX f = ff; ZZ_pX b = bb; if (!IsOne(LeadCoeff(f))) Error("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& ff, long verbose) { ZZ_pX f = ff; if (!IsOne(LeadCoeff(f))) Error("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; const ZZ& p = ZZ_p::modulus(); ZZ_pXModulus F; build(F, f); ZZ_pX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(h, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_ZZ_pX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } ZZ_pX hh; vec_ZZ_pX v; long i; for (i = 0; i < u.length(); i++) { const ZZ_pX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose) { if (!IsOne(LeadCoeff(f))) Error("CanZass: bad args"); double t; vec_pair_ZZ_pX_long sfd; vec_ZZ_pX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); ZZ_pX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } static long BaseCase(const ZZ_pX& h, long q, long a, const ZZ_pXModulus& F) { long b, e; ZZ_pX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } static void TandemPowerCompose(ZZ_pX& y1, ZZ_pX& y2, const ZZ_pX& h, long q1, long q2, const ZZ_pXModulus& F) { ZZ_pX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } static long RecComputeDegree(long u, const ZZ_pX& h, const ZZ_pXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); ZZ_pX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F) { if (F.n == 1 || IsX(h)) return 1; long n = F.n; ZZ_pX P1, P2, P3; random(P1, n); TraceMap(P2, P1, n, F, h); ProbMinPolyMod(P3, P2, F, n/2); long r = deg(P3); if (r <= 0 || n % r != 0) return 0; else return n/r; } void FindRoot(ZZ_p& root, const ZZ_pX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { ZZ_pXModulus F; ZZ_pX h, h1, f; ZZ_p r; ZZ p1; f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoot: bad args"); if (deg(f) == 0) Error("FindRoot: bad args"); RightShift(p1, ZZ_p::modulus(), 1); h1 = 1; while (deg(f) > 1) { build(F, f); random(r); PowerXPlusAMod(h, r, p1, F); sub(h, h, h1); GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const ZZ_pX& h, long q, long a, const ZZ_pXModulus& F) { long e; ZZ_pX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); sub(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const ZZ_pX& h, const ZZ_pXModulus& F, const FacVec& fvec) { long q1, q2; ZZ_pX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const ZZ_pX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; ZZ_pXModulus F; build(F, f); ZZ_pX h; PowerXMod(h, ZZ_p::modulus(), F); ZZ_pX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const ZZ_pX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; ZZ_pXModulus F; build(F, f); ZZ_pX h; PowerXMod(h, ZZ_p::modulus(), F); long CompTableSize = 2*SqrRoot(deg(f)); ZZ_pXArgument H; build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; ZZ_pX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { sub(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { CompMod(g, g, H, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_ZZ_pX& h, const ZZ_pX& f, const ZZ_pX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { ZZ_pX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); sub(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); sub(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(ZZ_pX& x, const ZZ_pX& f, const ZZ_pX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_ZZ_pX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_ZZ_p a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(ZZ_pX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(ZZ_pX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { ZZ_pX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(ZZ_pX& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g) { ZZ_pXModulus G; ZZ_pX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_THREAD_LOCAL long ZZ_pX_GCDTableSize = 4; NTL_THREAD_LOCAL char ZZ_pX_stem[256] = ""; NTL_THREAD_LOCAL double ZZ_pXFileThresh = NTL_FILE_THRESH; NTL_THREAD_LOCAL static vec_ZZ_pX BabyStepFile; NTL_THREAD_LOCAL static vec_ZZ_pX GiantStepFile; NTL_THREAD_LOCAL static long use_files; // FIXME: in a thread-safe impl, we have to worry about // file name clashes static double CalcTableSize(long n, long k) { double sz = ZZ_p::storage(); sz = sz * n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz * k; sz = sz/1024; return sz; } static void GenerateBabySteps(ZZ_pX& h1, const ZZ_pX& f, const ZZ_pX& h, long k, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } ZZ_pXModulus F; build(F, f); ZZ_pXArgument H; build(H, h, F, 2*SqrRoot(F.n)); h1 = h; long i; if (!use_files) { BabyStepFile.kill(); BabyStepFile.SetLength(k-1); } for (i = 1; i <= k-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName(ZZ_pX_stem, "baby", i)); s << h1 << "\n"; s.close(); } else BabyStepFile(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const ZZ_pX& f, const ZZ_pX& h, long l, long verbose) { double t; if (verbose) { cerr << "generating giant steps..."; t = GetTime(); } ZZ_pXModulus F; build(F, f); ZZ_pXArgument H; build(H, h, F, 2*SqrRoot(F.n)); ZZ_pX h1; h1 = h; long i; if (!use_files) { GiantStepFile.kill(); GiantStepFile.SetLength(l); } for (i = 1; i <= l-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName(ZZ_pX_stem, "giant", i)); s << h1 << "\n"; s.close(); } else GiantStepFile(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (use_files) { ofstream s; OpenWrite(s, FileName(ZZ_pX_stem, "giant", i)); s << h1 << "\n"; s.close(); } else GiantStepFile(i) = h1; if (verbose) cerr << (GetTime()-t) << "\n"; } static void FileCleanup(long k, long l) { if (use_files) { long i; for (i = 1; i <= k-1; i++) remove(FileName(ZZ_pX_stem, "baby", i)); for (i = 1; i <= l; i++) remove(FileName(ZZ_pX_stem, "giant", i)); } else { BabyStepFile.kill(); GiantStepFile.kill(); } } static void NewAddFactor(vec_pair_ZZ_pX_long& u, const ZZ_pX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_ZZ_pX_long& u, ZZ_pX& f, const ZZ_pXModulus& F, vec_ZZ_pX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; ZZ_pX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(ZZ_pX& g, long gs, const ZZ_pXModulus& F) { if (use_files) { ifstream s; OpenRead(s, FileName(ZZ_pX_stem, "giant", gs)); s >> g; s.close(); } else g = GiantStepFile(gs); rem(g, g, F); } static void FetchBabySteps(vec_ZZ_pX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { if (use_files) { ifstream s; OpenRead(s, FileName(ZZ_pX_stem, "baby", i)); s >> v[i]; s.close(); } else v[i] = BabyStepFile(i); } } static void GiantRefine(vec_pair_ZZ_pX_long& u, const ZZ_pX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_ZZ_pX BabyStep; FetchBabySteps(BabyStep, k); vec_ZZ_pX buf(INIT_SIZE, ZZ_pX_GCDTableSize); ZZ_pX f; f = ff; ZZ_pXModulus F; build(F, f); ZZ_pX g; ZZ_pX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); sub(buf[size-1], g, BabyStep[bs]); } else { sub(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == ZZ_pX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_ZZ_pX_long& factors, const ZZ_pX& ff, long k, long gs, const vec_ZZ_pX& BabyStep, long verbose) { vec_ZZ_pX buf(INIT_SIZE, ZZ_pX_GCDTableSize); ZZ_pX f; f = ff; ZZ_pXModulus F; build(F, f); ZZ_pX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); sub(buf[size], buf[size], g); size++; if (size == ZZ_pX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_ZZ_pX_long& factors, const vec_pair_ZZ_pX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_ZZ_pX BabyStep; long i; for (i = 0; i < u.length(); i++) { const ZZ_pX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h, long verbose) { if (!IsOne(LeadCoeff(f))) Error("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } if (!ZZ_pX_stem[0]) sprintf(ZZ_pX_stem, "ddf-%ld", RandomBnd(10000)); long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; ZZ_pX h1; if (CalcTableSize(deg(f), k + l - 1) > ZZ_pXFileThresh) use_files = 1; else use_files = 0; GenerateBabySteps(h1, f, h, k, verbose); GenerateGiantSteps(f, h1, l, verbose); vec_pair_ZZ_pX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); FileCleanup(k, l); } NTL_END_IMPL ntl-6.2.1/src/c_lip_impl.h000644 000765 000024 00000412744 12377144456 015716 0ustar00shoupstaff000000 000000 #include #include #include #include #include #define MustAlloc(c, len) (!(c) || ((c)[-1] >> 1) < (len)) /* Fast test to determine if allocation is necessary */ static void zhalt(const char *c) { fprintf(stderr,"fatal error:\n %s\nexit...\n",c); fflush(stderr); _ntl_abort(); } class _ntl_verylong_watcher { public: _ntl_verylong *watched; explicit _ntl_verylong_watcher(_ntl_verylong *_watched) : watched(_watched) {} ~_ntl_verylong_watcher() { if (*watched && ((*watched)[-1] >> 1) > NTL_RELEASE_THRESH) _ntl_zfree(watched); } }; #define CRegister(x) NTL_THREAD_LOCAL static _ntl_verylong x = 0; _ntl_verylong_watcher _WATCHER__ ## x(&x) // FIXME: when we implement thread safe code, we may want to define // this so that we also attach a thread-local watcher that unconditionally // releases memory when the thread terminates #define MIN_SETL (4) /* _ntl_zsetlength allocates a multiple of MIN_SETL digits */ #define MulLo(rres,a,b) rres = (a)*(b) /* * definitions of zaddmulp, zxmulp, zaddmulpsq for the various * long integer arithmentic implementation options. */ #if (defined(NTL_LONG_LONG)) #if (!defined(NTL_CLEAN_INT)) /* * One might get slightly better code with this version. */ #define zaddmulp(a, b, d, t) { \ NTL_LL_TYPE _pp = ((NTL_LL_TYPE) (b)) * ((NTL_LL_TYPE) (d)) + ((t)+(a)); \ (a) = ((long)(_pp)) & NTL_RADIXM; \ (t) = (long) (_pp >> NTL_NBITS); \ } #define zxmulp(a, b, d, t) { \ NTL_LL_TYPE _pp = ((NTL_LL_TYPE) (b)) * ((NTL_LL_TYPE) (d)) + (t); \ (a) = ((long)(_pp)) & NTL_RADIXM; \ (t) = (long) (_pp >> NTL_NBITS); \ } #define zaddmulpsq(a,b,t) { \ NTL_LL_TYPE _pp = ((NTL_LL_TYPE) (b)) * ((NTL_LL_TYPE) (b)) + (a); \ (a) = ((long)(_pp)) & NTL_RADIXM; \ (t) = (long) (_pp >> NTL_NBITS); \ } #else /* * This version conforms to the language standard when d is non-negative. * Some compilers may emit sub-optimal code, though. */ #define zaddmulp(a, b, d, t) { \ NTL_LL_TYPE _pp = ((NTL_LL_TYPE) (b)) * ((NTL_LL_TYPE) (d)) + ((t)+(a)); \ (a) = (long) (_pp & NTL_RADIXM); \ (t) = (long) (_pp >> NTL_NBITS); \ } #define zxmulp(a, b, d, t) { \ NTL_LL_TYPE _pp = ((NTL_LL_TYPE) (b)) * ((NTL_LL_TYPE) (d)) + (t); \ (a) = (long) (_pp & NTL_RADIXM); \ (t) = (long) (_pp >> NTL_NBITS); \ } #define zaddmulpsq(a,b,t) { \ NTL_LL_TYPE _pp = ((NTL_LL_TYPE) (b)) * ((NTL_LL_TYPE) (b)) + (a); \ (a) = (long) (_pp & NTL_RADIXM); \ (t) = (long) (_pp >> NTL_NBITS); \ } #endif #elif (defined(NTL_AVOID_FLOAT)) #define zaddmulp( a, b, d, t) { \ unsigned long _b1 = b & NTL_RADIXROOTM; \ unsigned long _d1 = d & NTL_RADIXROOTM; \ unsigned long _bd,_b1d1,_m,_aa= (a) + (t); \ unsigned long _ld = (d>>NTL_NBITSH); \ unsigned long _lb = (b>>NTL_NBITSH); \ \ _bd=_lb*_ld; \ _b1d1=_b1*_d1; \ _m=(_lb+_b1)*(_ld+_d1) - _bd - _b1d1; \ _aa += ( _b1d1+ ((_m&NTL_RADIXROOTM)<> NTL_NBITS) + _bd + (_m>>NTL_NBITSH); \ (a) = _aa & NTL_RADIXM; \ } #define zxmulp( a, b, d, t) { \ unsigned long _b1 = b & NTL_RADIXROOTM; \ unsigned long _d1 = d & NTL_RADIXROOTM; \ unsigned long _bd,_b1d1,_m,_aa= (t); \ unsigned long _ld = (d>>NTL_NBITSH); \ unsigned long _lb = (b>>NTL_NBITSH); \ \ _bd=_lb*_ld; \ _b1d1=_b1*_d1; \ _m=(_lb+_b1)*(_ld+_d1) - _bd - _b1d1; \ _aa += ( _b1d1+ ((_m&NTL_RADIXROOTM)<> NTL_NBITS) + _bd + (_m>>NTL_NBITSH); \ (a) = _aa & NTL_RADIXM; \ } #define zaddmulpsq(_a, _b, _t) \ { \ long _lb = (_b); \ long _b1 = (_b) & NTL_RADIXROOTM; \ long _aa = (_a) + _b1 * _b1; \ \ _b1 = (_b1 * (_lb >>= NTL_NBITSH) << 1) + (_aa >> NTL_NBITSH); \ _aa = (_aa & NTL_RADIXROOTM) + ((_b1 & NTL_RADIXROOTM) << NTL_NBITSH); \ (_t) = _lb * _lb + (_b1 >> NTL_NBITSH) + (_aa >> NTL_NBITS); \ (_a) = (_aa & NTL_RADIXM); \ } #else /* default long integer arithemtic */ /* various "software pipelining" routines are also defined */ /* * The macros CARRY_TYPE and CARRY_CONV are only used in the submul * logic. */ #if (defined(NTL_CLEAN_INT)) #define CARRY_TYPE unsigned long #define CARRY_CONV(x) (-((long)(-x))) #else #define CARRY_TYPE long #define CARRY_CONV(x) (x) #endif #if (NTL_BITS_PER_LONG <= NTL_NBITS + 2) #if (NTL_ARITH_RIGHT_SHIFT && !defined(NTL_CLEAN_INT)) /* value right-shifted is -1..1 */ #define zaddmulp(a, b, d, t) \ { \ long _a = (a), _b = (b), _d = (d), _t = (t); \ long _t1 = _b*_d; \ long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ); \ _t2 = _t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS); \ _t1 = (_t1 & NTL_RADIXM) + _a +_t; \ (t) = _t2 + (((unsigned long)_t1) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } #define zxmulp(a, b, d, t) \ { \ long _b = (b), _d = (d), _t = (t); \ long _t1 = _b*_d + _t; \ long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ (t) = _t2 + (((unsigned long)(_t1 - (_t2 << NTL_NBITS))) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } /* value shifted is -1..1 */ #define zaddmulpsq(a, b, t) \ { \ long _a = (a), _b = (b); \ long _t1 = _b*_b; \ long _t2 = (long) ( ((double) _b)*(((double) _b)*NTL_FRADIX_INV) ); \ _t2 = _t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS); \ _t1 = (_t1 & NTL_RADIXM) + _a; \ (t) = _t2 + (((unsigned long)_t1) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } /* * In the following definition of zam_init, the value _ds is computed so that * it is slightly bigger than s*NTL_RADIX_INV. This has the consequence that * the value _hi is equal to floor(_b*_s/NTL_RADIX) or * floor(_b*_s/NTL_RADIX) + 1, assuming only that (1) conversion of "small" * integer to doubles is exact, (2) multiplication by powers of 2 is exact, and * (3) multiplication of two general doubles yields a result with relative * error 1/2^{NTL_DOUBLE_PRECISION-1}. These assumptions are very * conservative, and in fact, the IEEE floating point standard would guarantee * this result *without* making _ds slightly bigger. */ #define zam_decl double _ds; long _hi, _lo, _s; #define zam_init(b,s) \ { \ long _b = (b); \ _s = (s); \ _ds = ((_s << 1)+1)*(NTL_FRADIX_INV/2.0); \ _lo = _b*_s; \ _hi = (long) (((double) _b)*_ds); \ } /* value shifted is 0..3 */ #define zam_loop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _lo = _lo + _a + _t; \ _hi--; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is -1..+1 */ #define zsx_loop(a,t,nb) \ { \ long _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _lo = _lo + _t; \ (t) = _hi + ((_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* value shifted is -2..+1 */ #define zam_subloop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _lo = _a + _t - _lo; \ (t) = ((_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* value shifted is 0..3 */ #define zam_finish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _lo + _a + _t; \ _hi--; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ } /* value shifted is -1..+1 */ #define zsx_finish(a,t) \ { \ long _t = (t); \ _lo = _lo + _t; \ (t) = _hi + ((_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ } /* value shifted is -2..+1 */ #define zam_subfinish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _a + _t - _lo; \ (t) = ((_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = _lo & NTL_RADIXM; \ } #elif (!defined(NTL_CLEAN_INT)) /* right shift is not arithmetic */ /* value right-shifted is 0..2 */ #define zaddmulp(a, b, d, t) \ { \ long _a = (a), _b = (b), _d = (d), _t = (t); \ long _t1 = _b*_d; \ long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ _t2 = _t2 + ( ((unsigned long) (_t1 - (_t2 << NTL_NBITS))) >> NTL_NBITS ); \ _t1 = (_t1 & NTL_RADIXM) + _a +_t; \ (t) = _t2 + (((unsigned long)_t1) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } #define zxmulp(a, b, d, t) \ { \ long _b = (b), _d = (d), _t = (t); \ long _t1 = _b*_d + _t; \ long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ (t) = _t2 + (((unsigned long)(_t1 - (_t2 << NTL_NBITS))) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } /* value shifted is 0..2 */ #define zaddmulpsq(a, b, t) \ { \ long _a = (a), _b = (b); \ long _t1 = _b*_b; \ long _t2 = (long) ( ((double) _b)*(((double) _b)*NTL_FRADIX_INV) ) - 1; \ _t2 = _t2 + ( ((unsigned long) (_t1 - (_t2 << NTL_NBITS))) >> NTL_NBITS ); \ _t1 = (_t1 & NTL_RADIXM) + _a; \ (t) = _t2 + (((unsigned long)_t1) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } #define zam_decl double _ds; long _hi, _lo, _s; #define zam_init(b,s) \ { \ long _b = (b); \ _s = (s); \ _ds = ((_s << 1)+1)*(NTL_FRADIX_INV/2.0); \ _lo = _b*_s; \ _hi = (long) (((double) _b)*_ds); \ } /* value shifted is 0..3 */ #define zam_loop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _lo = _lo + _a + _t; \ _hi--; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* value shifted is 0..2 */ #define zsx_loop(a,t,nb) \ { \ long _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _lo = _lo + _t; \ _hi--; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* value shifted is 0..3 */ #define zam_subloop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _hi += 2; \ _lo = _a + _t - _lo; \ (t) = (((unsigned long)(_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* value shifted is 0..3 */ #define zam_finish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _lo + _a + _t; \ _hi--; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ } /* value shifted is 0..2 */ #define zsx_finish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _lo + _t; \ _hi--; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ } /* value shifted is 0..3 */ #define zam_subfinish(a,t) \ { \ long _a = (a), _t = (t); \ _hi += 2; \ _lo = _a + _t - _lo; \ (t) = (((unsigned long)(_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = _lo & NTL_RADIXM; \ } #else /* clean int version */ /* value right-shifted is 0..2 */ #define zaddmulp(a, b, d, t) \ { \ long _a = (a), _b = (b), _d = (d), _t = (t); \ unsigned long _t1 = ((unsigned long) _b)*((unsigned long) _d); \ unsigned long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ _t2 = _t2 + ( (_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS ); \ _t1 = (_t1 & NTL_RADIXM) + ((unsigned long) _a) + ((unsigned long) _t); \ (t) = (long) (_t2 + (_t1 >> NTL_NBITS)); \ (a) = (long) (_t1 & NTL_RADIXM); \ } #define zxmulp(a, b, d, t) \ { \ long _b = (b), _d = (d), _t = (t); \ unsigned long _t1 = ((unsigned long) _b)*((unsigned long) _d) + ((unsigned long) _t); \ unsigned long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ (t) = (long) (_t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS)); \ (a) = (long) (_t1 & NTL_RADIXM); \ } /* value shifted is 0..2 */ #define zaddmulpsq(a, b, t) \ { \ long _a = (a), _b = (b); \ unsigned long _t1 = ((unsigned long) _b)*((unsigned long) _b); \ unsigned long _t2 = (long) ( ((double) _b)*(((double) _b)*NTL_FRADIX_INV) ) - 1; \ _t2 = _t2 + ( (_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS ); \ _t1 = (_t1 & NTL_RADIXM) + ((unsigned long) _a); \ (t) = (long) (_t2 + (_t1 >> NTL_NBITS)); \ (a) = (long) (_t1 & NTL_RADIXM); \ } #define zam_decl double _ds; long _s; unsigned long _hi, _lo; #define zam_init(b,s) \ { \ long _b = (b); \ _s = (s); \ _ds = ((_s << 1)+1)*(NTL_FRADIX_INV/2.0); \ _lo = ((unsigned long) _b)*((unsigned long) _s); \ _hi = (long) (((double) _b)*_ds); \ } /* value shifted is 0..3 */ #define zam_loop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ unsigned long _vv; \ double _yy; \ _vv = ((unsigned long) _nb)*((unsigned long)_s); \ _yy = ((double) _nb)*_ds; \ _lo = _lo + ((unsigned long) _a) + ((unsigned long) _t); \ _hi--; \ (t) = (long) (_hi + ((_lo - (_hi<> NTL_NBITS)); \ (a) = (long) (_lo & NTL_RADIXM); \ _lo = _vv; \ _hi = (long) _yy; \ } /* value shifted is 0..2 */ #define zsx_loop(a,t,nb) \ { \ long _t = (t), _nb = (nb); \ unsigned long _vv; \ double _yy; \ _vv = ((unsigned long) _nb)*((unsigned long) _s); \ _yy = ((double) _nb)*_ds; \ _lo = _lo + ((unsigned long) _t); \ _hi--; \ (t) = (long) (_hi + ((_lo - (_hi<> NTL_NBITS)); \ (a) = (long) (_lo & NTL_RADIXM); \ _lo = _vv; \ _hi = (long) _yy; \ } /* value shifted is 0..3 */ #define zam_subloop(a,t,nb) \ { \ long _a = (a); unsigned long _t = (t); long _nb = (nb); \ unsigned long _vv; \ double _yy; \ _vv = ((unsigned long) _nb)*((unsigned long) _s); \ _yy = ((double) _nb)*_ds; \ _hi += 2; \ _lo = ((unsigned long) _a) + _t - _lo; \ (t) = ((_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = (long) (_lo & NTL_RADIXM); \ _lo = _vv; \ _hi = (long) _yy; \ } /* value shifted is 0..3 */ #define zam_finish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _lo + ((unsigned long) _a) + ((unsigned long) _t); \ _hi--; \ (t) = (long) (_hi + ((_lo - (_hi<> NTL_NBITS)); \ (a) = (long) (_lo & NTL_RADIXM); \ } /* value shifted is 0..2 */ #define zsx_finish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _lo + ((unsigned long) _t); \ _hi--; \ (t) = (long) (_hi + ((_lo - (_hi<> NTL_NBITS)); \ (a) = (long) (_lo & NTL_RADIXM); \ } /* value shifted is 0..3 */ #define zam_subfinish(a,t) \ { \ long _a = (a); unsigned long _t = (t); \ _hi += 2; \ _lo = ((unsigned long) _a) + _t - _lo; \ (t) = ((_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = (long) (_lo & NTL_RADIXM); \ } #endif /* end of arithmemtic-right-shift if-then else */ #else /* NTL_BITS_PER_LONG > NTL_NBITS + 2, and certain optimizations can be made. Useful on 64-bit machines. */ #if (NTL_ARITH_RIGHT_SHIFT && !defined(NTL_CLEAN_INT)) /* shift is -1..+3 */ #define zaddmulp(a, b, d, t) \ { \ long _a = (a), _b = (b), _d = (d), _t = (t); \ long _t1 = _b*_d + _a + _t; \ long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ); \ (t) = _t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } #define zxmulp(a, b, d, t) \ { \ long _b = (b), _d = (d), _t = (t); \ long _t1 = _b*_d + _t; \ long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ); \ (t) = _t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } /* shift is -1..+2 */ #define zaddmulpsq(a, b, t) \ { \ long _a = (a), _b = (b), _t = (t); \ long _t1 = _b*_b + _a; \ long _t2 = (long) ( ((double) _b)*(((double) _b)*NTL_FRADIX_INV) ); \ (t) = _t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } #define zam_decl double _ds; long _hi, _lo, _s; #define zam_init(b,s) \ { \ long _b = (b); \ _s = (s); \ _ds = _s*NTL_FRADIX_INV; \ _lo = _b*_s; \ _hi = (long) (((double) _b)*_ds); \ } /* shift is -1..+3 */ #define zam_loop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _lo = _lo + _a + _t; \ (t) = _hi + ((_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is -1..+2 */ #define zsx_loop(a,t,nb) \ { \ long _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _lo = _lo + _t; \ (t) = _hi + ((_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is -3..+1 */ #define zam_subloop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _lo = _a + _t - _lo; \ (t) = ((_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is -1..+3 */ #define zam_finish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _lo + _a + _t; \ (t) = _hi + ((_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ } /* shift is -1..+2 */ #define zsx_finish(a,t) \ { \ long _t = (t); \ _lo = _lo + _t; \ (t) = _hi + ((_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ } /* shift is -3..+1 */ #define zam_subfinish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _a + _t - _lo; \ (t) = ((_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = _lo & NTL_RADIXM; \ } #elif (!defined(NTL_CLEAN_INT)) /* right shift is not arithmetic */ /* shift is 0..4 */ #define zaddmulp(a, b, d, t) \ { \ long _a = (a), _b = (b), _d = (d), _t = (t); \ long _t1 = _b*_d + _a + _t; \ long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ (t) = _t2 + (((unsigned long)(_t1 - (_t2 << NTL_NBITS))) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } #define zxmulp(a, b, d, t) \ { \ long _b = (b), _d = (d), _t = (t); \ long _t1 = _b*_d + _t; \ long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ (t) = _t2 + (((unsigned long)(_t1 - (_t2 << NTL_NBITS))) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } /* shift is 0..3 */ #define zaddmulpsq(a, b, t) \ { \ long _a = (a), _b = (b), _t = (t); \ long _t1 = _b*_b + _a; \ long _t2 = (long) ( ((double) _b)*(((double) _b)*NTL_FRADIX_INV) ) - 1; \ (t) = _t2 + (((unsigned long)(_t1 - (_t2 << NTL_NBITS))) >> NTL_NBITS); \ (a) = _t1 & NTL_RADIXM; \ } #define zam_decl double _ds; long _hi, _lo, _s; #define zam_init(b,s) \ { \ long _b = (b); \ _s = (s); \ _ds = _s*NTL_FRADIX_INV; \ _lo = _b*_s; \ _hi = (long) (((double) _b)*_ds); \ } /* shift is 0..4 */ #define zam_loop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _hi--; \ _lo = _lo + _a + _t; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is 0..3 */ #define zsx_loop(a,t,nb) \ { \ long _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _hi--; \ _lo = _lo + _t; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is 0..4 */ #define zam_subloop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ long _vv; \ double _yy; \ _vv = _nb*_s; \ _yy = ((double) _nb)*_ds; \ _hi += 3; \ _lo = _a + _t - _lo; \ (t) = (((unsigned long)(_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = _lo & NTL_RADIXM; \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is 0..4 */ #define zam_finish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _lo + _a + _t; \ _hi--; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ } /* shift is 0..3 */ #define zsx_finish(a,t) \ { \ long _t = (t); \ _lo = _lo + _t; \ _hi--; \ (t) = _hi + (((unsigned long)(_lo - (_hi<> NTL_NBITS); \ (a) = _lo & NTL_RADIXM; \ } /* shift is 0..4 */ #define zam_subfinish(a,t) \ { \ long _a = (a), _t = (t); \ _hi += 3; \ _lo = _a + _t - _lo; \ (t) = (((unsigned long)(_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = _lo & NTL_RADIXM; \ } #else /* clean int version */ /* shift is 0..4 */ #define zaddmulp(a, b, d, t) \ { \ long _a = (a), _b = (b), _d = (d), _t = (t); \ unsigned long _t1 = ((unsigned long) _b)*((unsigned long) _d) + ((unsigned long) _a) + ((unsigned long) _t); \ unsigned long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ (t) = (long) (_t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS)); \ (a) = (long) (_t1 & NTL_RADIXM); \ } #define zxmulp(a, b, d, t) \ { \ long _b = (b), _d = (d), _t = (t); \ unsigned long _t1 = ((unsigned long) _b)*((unsigned long) _d) + ((unsigned long) _t); \ unsigned long _t2 = (long) ( ((double) _b)*(((double) _d)*NTL_FRADIX_INV) ) - 1; \ (t) = (long) (_t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS)); \ (a) = (long) (_t1 & NTL_RADIXM); \ } /* shift is 0..3 */ #define zaddmulpsq(a, b, t) \ { \ long _a = (a), _b = (b), _t = (t); \ unsigned long _t1 = ((unsigned long) _b)*((unsigned long) _b) + ((unsigned long) _a); \ unsigned long _t2 = (long) ( ((double) _b)*(((double) _b)*NTL_FRADIX_INV) ) - 1; \ (t) = (long) (_t2 + ((_t1 - (_t2 << NTL_NBITS)) >> NTL_NBITS)); \ (a) = (long) (_t1 & NTL_RADIXM); \ } #define zam_decl double _ds; long _s; unsigned long _hi, _lo; #define zam_init(b,s) \ { \ long _b = (b); \ _s = (s); \ _ds = _s*NTL_FRADIX_INV; \ _lo = ((unsigned long) _b)*((unsigned long) _s); \ _hi = (long) (((double) _b)*_ds); \ } /* shift is 0..4 */ #define zam_loop(a,t,nb) \ { \ long _a = (a), _t = (t), _nb = (nb); \ unsigned long _vv; \ double _yy; \ _vv = ((unsigned long) _nb)*((unsigned long) _s); \ _yy = ((double) _nb)*_ds; \ _hi--; \ _lo = _lo + ((unsigned long) _a) + ((unsigned long) _t); \ (t) = (long) (_hi + ((_lo - (_hi<> NTL_NBITS)); \ (a) = (long) (_lo & NTL_RADIXM); \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is 0..3 */ #define zsx_loop(a,t,nb) \ { \ long _t = (t), _nb = (nb); \ unsigned long _vv; \ double _yy; \ _vv = ((unsigned long) _nb)*((unsigned long) _s); \ _yy = ((double) _nb)*_ds; \ _hi--; \ _lo = _lo + ((unsigned long) _t); \ (t) = (long) (_hi + ((_lo - (_hi<> NTL_NBITS)); \ (a) = (long) (_lo & NTL_RADIXM); \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is 0..4 */ #define zam_subloop(a,t,nb) \ { \ long _a = (a); unsigned long _t = (t); long _nb = (nb); \ unsigned long _vv; \ double _yy; \ _vv = ((unsigned long) _nb)*((unsigned long) _s); \ _yy = ((double) _nb)*_ds; \ _hi += 3; \ _lo = ((unsigned long) _a) + _t - _lo; \ (t) = ((_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = (long) (_lo & NTL_RADIXM); \ _lo = _vv; \ _hi = (long) _yy; \ } /* shift is 0..4 */ #define zam_finish(a,t) \ { \ long _a = (a), _t = (t); \ _lo = _lo + ((unsigned long) _a) + ((unsigned long) _t); \ _hi--; \ (t) = (long) (_hi + ((_lo - (_hi<> NTL_NBITS)); \ (a) = _lo & NTL_RADIXM; \ } /* shift is 0..3 */ #define zsx_finish(a,t) \ { \ long _t = (t); \ _lo = _lo + ((unsigned long) _t); \ _hi--; \ (t) = (long) (_hi + ((_lo - (_hi<> NTL_NBITS)); \ (a) = (long) (_lo & NTL_RADIXM); \ } /* shift is 0..4 */ #define zam_subfinish(a,t) \ { \ long _a = (a); unsigned long _t = (t); \ _hi += 3; \ _lo = ((unsigned long) _a) + _t - _lo; \ (t) = ((_lo + (_hi<> NTL_NBITS) - _hi; \ (a) = (long) (_lo & NTL_RADIXM); \ } #endif /* end of arithmetic-right-shift if-then-else */ #endif /* end of "NTL_BITS_PER_LONG <= NTL_NBITS + 2" if-then-else */ #endif /* end of long-integer-implementation if-then-else */ static void zaddmulone(long *lama, long *lamb) { long lami; long lams = 0; lams = 0; for (lami = (*lamb++); lami > 0; lami--) { lams += (*lama + *lamb++); *lama++ = lams & NTL_RADIXM; lams >>= NTL_NBITS; } *lama += lams; } #if (NTL_ARITH_RIGHT_SHIFT && !defined(NTL_CLEAN_INT)) static void zsubmulone(long *lama, long *lamb) { long lami; long lams = 0; lams = 0; for (lami = (*lamb++); lami > 0; lami--) { lams += (*lama - *lamb++); *lama++ = lams & NTL_RADIXM; lams >>= NTL_NBITS; } *lama += lams; } #else static void zsubmulone(long *lama, long *lamb) { long lami; long lams = 0; lams = 0; for (lami = (*lamb++); lami > 0; lami--) { lams = *lama - *lamb++ - lams; *lama++ = lams & NTL_RADIXM; lams = (lams < 0); } *lama -= lams; } #endif /* * definitions of zaddmul, zsxmul, zaddmulsq for the various * long integer implementation options. */ #if (defined(NTL_AVOID_FLOAT) || defined(NTL_LONG_LONG)) static void zaddmul(long lams, long *lama, long *lamb) { long lami; long lamcarry = 0; for (lami = (*lamb++); lami > 0; lami--) { zaddmulp(*lama, *lamb, lams, lamcarry); lama++; lamb++; } *lama += lamcarry; } static void zsxmul(long lams, long *lama, long *lamb) { long lami; long lamcarry = 0; for (lami = (*lamb++); lami > 0; lami--) { zxmulp(*lama, *lamb, lams, lamcarry); lama++; lamb++; } *lama = lamcarry; } static void zaddmulsq(long lsqi, long *lsqa, long *lsqb) { long lsqs = *(lsqb); long lsqcarry = 0; lsqb++; for (; lsqi > 0; lsqi--) { zaddmulp(*lsqa, *lsqb, lsqs, lsqcarry); lsqa++; lsqb++; } *lsqa += lsqcarry; } #else /* default long integer arithmetic */ static void zaddmul(long lams, long *lama, long *lamb) { long lami = (*lamb++)-1; long lamcarry = 0; zam_decl; zam_init(*lamb, lams); lamb++; for (; lami > 0; lami--) { zam_loop(*lama, lamcarry, *lamb); lama++; lamb++; } zam_finish(*lama, lamcarry); lama++; *lama += lamcarry; } static void zsxmul(long lams, long *lama, long *lamb) { long lami = (*lamb++)-1; long lamcarry = 0; zam_decl; zam_init(*lamb, lams); lamb++; for (; lami > 0; lami--) { zsx_loop(*lama, lamcarry, *lamb); lama++; lamb++; } zsx_finish(*lama, lamcarry); lama++; *lama = lamcarry; } static void zaddmulsq(long lsqi, long *lsqa, long *lsqb) { long lsqs; long lsqcarry; zam_decl if (lsqi <= 0) return; lsqs = *lsqb; lsqcarry = 0; lsqb++; zam_init(*lsqb, lsqs); lsqb++; lsqi--; for (; lsqi > 0; lsqi--) { zam_loop(*lsqa, lsqcarry, *lsqb); lsqa++; lsqb++; } zam_finish(*lsqa, lsqcarry); lsqa++; *lsqa += lsqcarry; } #endif /* * definition of zsubmul for the various long integer implementation options. * Note that zsubmul is only called with a positive first argument. */ #if (defined(NTL_AVOID_FLOAT) || (defined(NTL_LONG_LONG) && defined(NTL_CLEAN_INT))) static void zsubmul( long r, _ntl_verylong a, _ntl_verylong b ) { long rd = NTL_RADIX - r; long i; long carry = NTL_RADIX; for (i = (*b++); i > 0; i--) { zaddmulp(*a, *b, rd, carry); a++; carry += NTL_RADIXM - (*b++); } *a += carry - NTL_RADIX; /* unnormalized */ } #elif (defined(NTL_LONG_LONG)) /* * NOTE: the implementation of zaddmulp for the NTL_LONG_LONG option * will work on most machines even when the single-precision * multiplicand is negative; however, the C language standard does * not guarantee correct behaviour in this case, which is why the above * implementation is used when NTL_CLEAN_INT is set. */ static void zsubmul(long lams, long *lama, long *lamb) { long lami; long lamcarry = 0; lams = -lams; for (lami = (*lamb++); lami > 0; lami--) { zaddmulp(*lama, *lamb, lams, lamcarry); lama++; lamb++; } *lama += lamcarry; } #else /* default long integer arithmetic */ static void zsubmul(long lams, long *lama, long *lamb) { long lami = (*lamb++)-1; CARRY_TYPE lamcarry = 0; zam_decl; zam_init(*lamb, lams); lamb++; for (; lami > 0; lami--) { zam_subloop(*lama, lamcarry, *lamb); lama++; lamb++; } zam_subfinish(*lama, lamcarry); lama++; *lama += CARRY_CONV(lamcarry); } #endif /* * * zdiv21 returns quot, numhigh so * * quot = (numhigh*NTL_RADIX + numlow)/denom; * numhigh = (numhigh*NTL_RADIX + numlow)%denom; * Assumes 0 <= numhigh < denom < NTL_RADIX and 0 <= numlow < NTL_RADIX. */ #if (defined(NTL_CLEAN_INT)) /* * This "clean" version relies on the guaranteed semantics of * unsigned integer arithmetic. */ #define zdiv21(numhigh, numlow, denom, deninv, quot) \ { \ unsigned long udenom = denom; \ unsigned long lq21 = (long) (((NTL_FRADIX * (double) (numhigh)) + \ (double) (numlow)) * (deninv)); \ unsigned long lr21 = (((unsigned long) numhigh) << NTL_NBITS) + \ ((unsigned long) numlow) - udenom*lq21 ; \ \ if (lr21 >> (NTL_BITS_PER_LONG-1)) { \ lq21--; \ lr21 += udenom; \ } \ else if (lr21 >= udenom) { \ lr21 -= udenom; \ lq21++; \ } \ quot = (long) lq21; \ numhigh = (long) lr21; \ } #else /* * This "less clean" version relies on wrap-around semantics for * signed integer arithmetic. */ #define zdiv21(numhigh, numlow, denom, deninv, quot) \ { \ long lr21; \ long lq21 = (long) (((NTL_FRADIX * (double) (numhigh)) \ + (double) (numlow)) * (deninv)); \ long lp21; \ MulLo(lp21, lq21, denom); \ lr21 = (numhigh << NTL_NBITS) + numlow - lp21; \ if (lr21 < 0) { \ lq21--; \ lr21 += denom; \ } \ else if (lr21 >= denom) { \ lr21 -= denom; \ lq21++; \ } \ quot = lq21; \ numhigh = lr21; \ } #endif /* * zrem21 behaves just like zdiv21, except the only the remainder is computed. */ #if (defined(NTL_CLEAN_INT) || (defined(NTL_AVOID_BRANCHING) && !NTL_ARITH_RIGHT_SHIFT)) #define NTL_CLEAN_SPMM #endif #if (defined(NTL_CLEAN_SPMM) && !defined(NTL_AVOID_BRANCHING)) #define zrem21(numhigh, numlow, denom, deninv) \ { \ unsigned long udenom = denom; \ unsigned long lq21 = (long) (((NTL_FRADIX * (double) (numhigh)) + \ (double) (numlow)) * (deninv)); \ unsigned long lr21 = (((unsigned long) numhigh) << NTL_NBITS) + \ ((unsigned long) numlow) - udenom*lq21 ; \ \ if (lr21 >> (NTL_BITS_PER_LONG-1)) { \ lr21 += udenom; \ } \ else if (lr21 >= udenom) { \ lr21 -= udenom; \ } \ numhigh = (long) lr21; \ } #elif (defined(NTL_CLEAN_SPMM) && defined(NTL_AVOID_BRANCHING)) #define zrem21(numhigh, numlow, denom, deninv) \ { \ unsigned long udenom = denom; \ unsigned long lq21 = (long) (((NTL_FRADIX * (double) (numhigh)) + \ (double) (numlow)) * (deninv)); \ unsigned long lr21 = (((unsigned long) numhigh) << NTL_NBITS) + \ ((unsigned long) numlow) - udenom*lq21 ; \ lr21 += (-(lr21 >> (NTL_BITS_PER_LONG-1))) & udenom; \ lr21 -= udenom; \ lr21 += (-(lr21 >> (NTL_BITS_PER_LONG-1))) & udenom; \ numhigh = (long) lr21; \ } #elif (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING)) #define zrem21(numhigh, numlow, denom, deninv) \ { \ long lr21; \ long lq21 = (long) (((NTL_FRADIX * (double) (numhigh)) \ + (double) (numlow)) * (deninv)); \ long lp21; \ MulLo(lp21, lq21, denom); \ lr21 = (numhigh << NTL_NBITS) + numlow - lp21; \ lr21 += (lr21 >> (NTL_BITS_PER_LONG-1)) & denom; \ lr21 -= denom; \ lr21 += (lr21 >> (NTL_BITS_PER_LONG-1)) & denom; \ numhigh = lr21; \ } #else #define zrem21(numhigh, numlow, denom, deninv) \ { \ long lr21; \ long lq21 = (long) (((NTL_FRADIX * (double) (numhigh)) \ + (double) (numlow)) * (deninv)); \ long lp21; \ MulLo(lp21, lq21, denom); \ lr21 = (numhigh << NTL_NBITS) + numlow - lp21; \ if (lr21 < 0) lr21 += denom; \ else if (lr21 >= denom) lr21 -= denom; \ numhigh = lr21; \ } #endif long _ntl_zmaxalloc(_ntl_verylong x) { if (!x) return 0; else return (x[-1] >> 1); } void _ntl_zsetlength(_ntl_verylong *v, long len) { _ntl_verylong x = *v; if (len < 0) zhalt("negative size allocation in _ntl_zsetlength"); if (NTL_OVERFLOW(len, NTL_NBITS, 0)) zhalt("size too big in _ntl_zsetlength"); if (x) { long oldlen = x[-1]; long fixed = oldlen & 1; oldlen = oldlen >> 1; if (fixed) { if (len > oldlen) zhalt("internal error: can't grow this _ntl_verylong"); else return; } if (len <= oldlen) return; len++; /* always allocate at least one more than requested */ oldlen = (long) (oldlen * 1.2); /* always increase by at least 20% */ if (len < oldlen) len = oldlen; /* round up to multiple of MIN_SETL */ len = ((len+(MIN_SETL-1))/MIN_SETL)*MIN_SETL; /* test len again */ if (NTL_OVERFLOW(len, NTL_NBITS, 0)) zhalt("size too big in _ntl_zsetlength"); x[-1] = len << 1; if (!(x = (_ntl_verylong)NTL_REALLOC(&(x[-1]), len, sizeof(long), 2*sizeof(long)))) { zhalt("reallocation failed in _ntl_zsetlength"); } } else { len++; /* as above, always allocate one more than requested */ len = ((len+(MIN_SETL-1))/MIN_SETL)*MIN_SETL; /* test len again */ if (NTL_OVERFLOW(len, NTL_NBITS, 0)) zhalt("size too big in _ntl_zsetlength"); if (!(x = (_ntl_verylong)NTL_MALLOC(len, sizeof(long), 2*sizeof(long)))) { zhalt("allocation failed in _ntl_zsetlength"); } x[0] = len << 1; x[1] = 1; x[2] = 0; } *v = x+1; } void _ntl_zfree(_ntl_verylong *x) { _ntl_verylong y; if (!(*x)) return; if ((*x)[-1] & 1) zhalt("Internal error: can't free this _ntl_verylong"); y = (*x - 1); free((void*)y); *x = 0; } long _ntl_zround_correction(_ntl_verylong a, long k, long residual) { long direction; long p; long sgn; long bl; long wh; long i; if (a[0] > 0) sgn = 1; else sgn = -1; p = k - 1; bl = (p/NTL_NBITS); wh = 1L << (p - NTL_NBITS*bl); bl++; if (a[bl] & wh) { /* bit is 1...we have to see if lower bits are all 0 in order to implement "round to even" */ if (a[bl] & (wh - 1)) direction = 1; else { i = bl - 1; while (i > 0 && a[i] == 0) i--; if (i > 0) direction = 1; else direction = 0; } /* use residual to break ties */ if (direction == 0 && residual != 0) { if (residual == sgn) direction = 1; else direction = -1; } if (direction == 0) { /* round to even */ wh = wh << 1; if (wh == NTL_RADIX) { wh = 1; bl++; } if (a[bl] & wh) direction = 1; else direction = -1; } } else direction = -1; if (direction == 1) return sgn; return 0; } double _ntl_zdoub_aux(_ntl_verylong n) { double res; long i; if (!n) return ((double) 0); if ((i = n[0]) < 0) i = -i; res = (double) (n[i--]); for (; i; i--) res = res * NTL_FRADIX + (double) (n[i]); if (n[0] > 0) return (res); return (-res); } double _ntl_zdoub(_ntl_verylong n) { CRegister(tmp); long s; long shamt; long correction; double x; s = _ntl_z2log(n); shamt = s - NTL_DOUBLE_PRECISION; if (shamt <= 0) return _ntl_zdoub_aux(n); _ntl_zrshift(n, shamt, &tmp); correction = _ntl_zround_correction(n, shamt, 0); if (correction) _ntl_zsadd(tmp, correction, &tmp); x = _ntl_zdoub_aux(tmp); x = _ntl_ldexp(x, shamt); return x; } double _ntl_zlog(_ntl_verylong n) { CRegister(tmp); NTL_THREAD_LOCAL static double log_2; NTL_THREAD_LOCAL static long init = 0; long s; long shamt; long correction; double x; if (!init) { log_2 = log(2.0); init = 1; } if (_ntl_zsign(n) <= 0) zhalt("log argument <= 0"); s = _ntl_z2log(n); shamt = s - NTL_DOUBLE_PRECISION; if (shamt <= 0) return log(_ntl_zdoub_aux(n)); _ntl_zrshift(n, shamt, &tmp); correction = _ntl_zround_correction(n, shamt, 0); if (correction) _ntl_zsadd(tmp, correction, &tmp); x = _ntl_zdoub_aux(tmp); return log(x) + shamt*log_2; } void _ntl_zdoubtoz(double a, _ntl_verylong *xx) { _ntl_verylong x; long neg, i, t, sz; a = floor(a); if (!_ntl_IsFinite(&a)) zhalt("_ntl_zdoubtoz: attempt to convert non-finite value"); if (a < 0) { a = -a; neg = 1; } else neg = 0; if (a == 0) { _ntl_zzero(xx); return; } sz = 1; a = a*NTL_FRADIX_INV; while (a >= 1) { a = a*NTL_FRADIX_INV; sz++; } x = *xx; if (MustAlloc(x, sz)) { _ntl_zsetlength(&x, sz); *xx = x; } for (i = sz; i > 0; i--) { a = a*NTL_FRADIX; t = (long) a; x[i] = t; a = a - t; } x[0] = (neg ? -sz : sz); } void _ntl_zzero(_ntl_verylong *aa) { if (!(*aa)) _ntl_zsetlength(aa, 1); (*aa)[0] = 1; (*aa)[1] = 0; } /* same as _ntl_zzero, except does not unnecessarily allocate space */ void _ntl_zzero1(_ntl_verylong *aa) { if (!(*aa)) return; (*aa)[0] = 1; (*aa)[1] = 0; } void _ntl_zone(_ntl_verylong *aa) { if (!(*aa)) _ntl_zsetlength(aa, 1); (*aa)[0] = 1; (*aa)[1] = 1; } void _ntl_zcopy(_ntl_verylong a, _ntl_verylong *bb) { long i; _ntl_verylong b = *bb; if (!a) { _ntl_zzero(bb); return; } if (a != b) { if ((i = *a) < 0) i = (-i); if (MustAlloc(b, i)) { _ntl_zsetlength(&b, i); *bb = b; } for (; i >= 0; i--) *b++ = *a++; } } /* same as _ntl_zcopy, but does not unnecessarily allocate space */ void _ntl_zcopy1(_ntl_verylong a, _ntl_verylong *bb) { long i; _ntl_verylong b = *bb; if (!a) { _ntl_zzero1(bb); return; } if (a != b) { if ((i = *a) < 0) i = (-i); if (MustAlloc(b, i)) { _ntl_zsetlength(&b, i); *bb = b; } for (; i >= 0; i--) *b++ = *a++; } } void _ntl_zintoz(long d, _ntl_verylong *aa) { long i; long anegative; unsigned long d1, d2; _ntl_verylong a = *aa; anegative = 0; if (d < 0) { anegative = 1; d1 = - ((unsigned long) d); /* careful: avoid overflow */ } else d1 = d; i = 0; d2 = d1; do { d2 >>= NTL_NBITS; i++; } while (d2 > 0); if (MustAlloc(a, i)) { _ntl_zsetlength(&a, i); *aa = a; } i = 0; a[1] = 0; while (d1 > 0) { a[++i] = d1 & NTL_RADIXM; d1 >>= NTL_NBITS; } if (i > 0) a[0] = i; else a[0] = 1; if (anegative) a[0] = (-a[0]); } /* same as _ntl_zintoz, but does not unnecessarily allocate space */ void _ntl_zintoz1(long d, _ntl_verylong *aa) { long i; long anegative; unsigned long d1, d2; _ntl_verylong a = *aa; if (!d && !a) return; anegative = 0; if (d < 0) { anegative = 1; d1 = - ((unsigned long) d); /* careful: avoid overlow */ } else d1 = d; i = 0; d2 = d1; do { d2 >>= NTL_NBITS; i++; } while (d2 > 0); if (MustAlloc(a, i)) { _ntl_zsetlength(&a, i); *aa = a; } i = 0; a[1] = 0; while (d1 > 0) { a[++i] = d1 & NTL_RADIXM; d1 >>= NTL_NBITS; } if (i > 0) a[0] = i; else a[0] = 1; if (anegative) a[0] = (-a[0]); } void _ntl_zuintoz(unsigned long d, _ntl_verylong *aa) { long i; unsigned long d1, d2; _ntl_verylong a = *aa; d1 = d; i = 0; d2 = d1; do { d2 >>= NTL_NBITS; i++; } while (d2 > 0); if (MustAlloc(a, i)) { _ntl_zsetlength(&a, i); *aa = a; } i = 0; a[1] = 0; while (d1 > 0) { a[++i] = d1 & NTL_RADIXM; d1 >>= NTL_NBITS; } if (i > 0) a[0] = i; else a[0] = 1; } unsigned long _ntl_ztouint(_ntl_verylong a) { unsigned long d; long sa; if (!a) return (0); if ((sa = *a) < 0) sa = -sa; d = (unsigned long) (*(a += sa)); while (--sa) { d <<= NTL_NBITS; d += (unsigned long) (*(--a)); } if ((*(--a)) < 0) return (-d); return (d); } long _ntl_ztoint(_ntl_verylong a) { unsigned long res = _ntl_ztouint(a); return NTL_ULONG_TO_LONG(res); } long _ntl_zcompare(_ntl_verylong a, _ntl_verylong b) { long sa; long sb; if (!a) { if (!b) return (0); if (b[0] < 0) return (1); if (b[0] > 1) return (-1); if (b[1]) return (-1); return (0); } if (!b) { if (a[0] < 0) return (-1); if (a[0] > 1) return (1); if (a[1]) return (1); return (0); } if ((sa = *a) > (sb = *b)) return (1); if (sa < sb) return (-1); if (sa < 0) sa = (-sa); a += sa; b += sa; for (; sa; sa--) { long diff = *a - *b; if (diff > 0) { if (sb < 0) return (-1); return (1); } if (diff < 0) { if (sb < 0) return (1); return (-1); } a--; b--; } return (0); } void _ntl_znegate(_ntl_verylong *aa) { _ntl_verylong a = *aa; if (!a) return; if (a[1] || a[0] != 1) a[0] = (-a[0]); } void _ntl_zsadd(_ntl_verylong a, long d, _ntl_verylong *b) { CRegister(x); _ntl_zintoz(d, &x); _ntl_zadd(a, x, b); } void _ntl_zadd(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *cc) { long sa; long sb; long anegative; _ntl_verylong c; long a_alias, b_alias; if (!a) { if (b) _ntl_zcopy(b, cc); else _ntl_zzero(cc); return; } if (!b) { _ntl_zcopy(a, cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); if ((anegative = ((sa = a[0]) < 0)) == ((sb = b[0]) < 0)) { /* signs a and b are the same */ _ntl_verylong pc; long carry; long i; long maxab; if (anegative) { sa = -sa; sb = -sb; } if (sa < sb) { i = sa; maxab = sb; } else { i = sb; maxab = sa; } if (MustAlloc(c, maxab+1)) { _ntl_zsetlength(&c, maxab + 1); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } pc = c; carry = 0; do { long t = (*(++a)) + (*(++b)) + carry; carry = t >> NTL_NBITS; *(++pc) = t & NTL_RADIXM; i--; } while (i); i = sa-sb; if (!i) goto i_exit; if (i < 0) { i = -i; a = b; } if (!carry) goto carry_exit; for (;;) { long t = (*(++a)) + 1; carry = t >> NTL_NBITS; *(++pc) = t & NTL_RADIXM; i--; if (!i) goto i_exit; if (!carry) goto carry_exit; } i_exit: if (carry) { *(++pc) = 1; maxab++; } *c = anegative ? -maxab : maxab; return; carry_exit: if (pc != a) { do { *(++pc) = *(++a); i--; } while (i); } *c = anegative ? -maxab : maxab; } else { /* signs a and b are different...use _ntl_zsub */ if (anegative) { a[0] = -sa; _ntl_zsub(b, a, cc); if (!a_alias) a[0] = sa; } else { b[0] = -sb; _ntl_zsub(a, b, cc); if (!b_alias) b[0] = sb; } } } void _ntl_zsub(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *cc) { long sa; long sb; long anegative; long a_alias, b_alias; _ntl_verylong c; if (!b) { if (a) _ntl_zcopy(a, cc); else _ntl_zzero(cc); return; } if (!a) { _ntl_zcopy(b, cc); _ntl_znegate(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); if ((anegative = ((sa = a[0]) < 0)) == ((sb = b[0]) < 0)) { /* signs agree */ long i, carry, *pc; if (anegative) { sa = -sa; sb = -sb; } carry = sa - sb; if (!carry) { long *aa = a + sa; long *bb = b + sa; i = sa; while (i && !(carry = (*aa - *bb))) { aa--; bb--; i--; } } if (!carry) { _ntl_zzero(cc); return; } if (carry < 0) { { long t = sa; sa = sb; sb = t; } { long t = a_alias; a_alias = b_alias; b_alias = t; } { long *t = a; a = b; b = t; } anegative = !anegative; } if (MustAlloc(c, sa)) { _ntl_zsetlength(&c, sa); /* must have !a_alias */ if (b_alias) b = c; *cc = c; } i = sb; carry = 0; pc = c; do { #if (!NTL_ARITH_RIGHT_SHIFT || defined(NTL_CLEAN_INT)) long t = (*(++a)) - (*(++b)) - carry; carry = (t < 0); #else long t = (*(++a)) - (*(++b)) + carry; carry = t >> NTL_NBITS; #endif *(++pc) = t & NTL_RADIXM; i--; } while (i); i = sa-sb; while (carry) { long t = (*(++a)) - 1; #if (!NTL_ARITH_RIGHT_SHIFT || defined(NTL_CLEAN_INT)) carry = (t < 0); #else carry = t >> NTL_NBITS; #endif *(++pc) = t & NTL_RADIXM; i--; } if (i) { if (pc != a) { do { *(++pc) = *(++a); i--; } while (i); } } else { while (sa > 1 && *pc == 0) { sa--; pc--; } } if (anegative) sa = -sa; *c = sa; } else { /* signs of a and b are different...use _ntl_zadd */ if (anegative) { a[0] = -sa; _ntl_zadd(a, b, cc); if (!a_alias) a[0] = sa; c = *cc; c[0] = -c[0]; } else { b[0] = -sb; _ntl_zadd(a, b, cc); if (!b_alias) b[0] = sb; } } } void _ntl_zsmul(_ntl_verylong a, long d, _ntl_verylong *bb) { long sa; long anegative, bnegative; _ntl_verylong b; long a_alias; if (d == 2) { _ntl_z2mul(a, bb); return; } if ((d >= NTL_RADIX) || (d <= -NTL_RADIX)) { CRegister(x); _ntl_zintoz(d,&x); _ntl_zmul(a, x, bb); return; } if (!a || (a[0] == 1 && a[1] == 0)) { _ntl_zzero(bb); return; } if (!d) { _ntl_zzero(bb); return; } /* both inputs non-zero */ anegative = 0; bnegative = 0; if ((sa = a[0]) < 0) { anegative = 1; a[0] = sa = (-sa); if (d < 0) d = (-d); else bnegative = 1; } else if (bnegative = (d < 0)) d = (-d); b = *bb; a_alias = (a == b); if (MustAlloc(b, sa + 1)) { _ntl_zsetlength(&b, sa + 1); if (a_alias) a = b; *bb = b; } zsxmul(d, b+1, a); sa++; while ((sa > 1) && (!(b[sa]))) sa--; b[0] = sa; if (bnegative) b[0] = (-b[0]); if (anegative && !a_alias) a[0] = -a[0]; } void _ntl_zsubpos(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *cc) { long sa; long sb; long *c, *pc; long i, carry; long b_alias; if (!b) { if (a) _ntl_zcopy(a, cc); else _ntl_zzero(cc); return; } if (!a) { _ntl_zzero(cc); return; } sa = a[0]; sb = b[0]; c = *cc; b_alias = (b == c); if (MustAlloc(c, sa)) { _ntl_zsetlength(&c, sa); if (b_alias) b = c; *cc = c; } i = sb; carry = 0; pc = c; while (i) { #if (!NTL_ARITH_RIGHT_SHIFT || defined(NTL_CLEAN_INT)) long t = (*(++a)) - (*(++b)) - carry; carry = (t < 0); #else long t = (*(++a)) - (*(++b)) + carry; carry = t >> NTL_NBITS; #endif *(++pc) = t & NTL_RADIXM; i--; } i = sa-sb; while (carry) { long t = (*(++a)) - 1; #if (!NTL_ARITH_RIGHT_SHIFT || defined(NTL_CLEAN_INT)) carry = (t < 0); #else carry = t >> NTL_NBITS; #endif *(++pc) = t & NTL_RADIXM; i--; } if (i) { if (pc != a) { do { *(++pc) = *(++a); i--; } while (i); } } else { while (sa > 1 && *pc == 0) { sa--; pc--; } } *c = sa; } NTL_THREAD_LOCAL static long *kmem = 0; /* globals for Karatsuba */ NTL_THREAD_LOCAL static long max_kmem = 0; // FIXME: in a thread-safe impl, need to attach a static, thread-local // watcher that will free kmem when thread exits /* These cross-over points were estimated using a Sparc-10, a Sparc-20, and a Pentium-90. */ #define KARX (16) /* Auxilliary routines for Karatsuba */ static void kar_fold(long *T, long *b, long hsa) { long sb, *p2, *p3, i, carry; sb = *b; p2 = b + hsa; p3 = T; carry = 0; for (i = sb-hsa; i>0; i--) { long t = (*(++b)) + (*(++p2)) + carry; carry = t >> NTL_NBITS; *(++p3) = t & NTL_RADIXM; } for (i = (hsa << 1) - sb; i>0; i--) { long t = (*(++b)) + carry; carry = t >> NTL_NBITS; *(++p3) = t & NTL_RADIXM; } if (carry) { *(++p3) = carry; *T = hsa + 1; } else *T = hsa; } static void kar_sub(long *T, long *c) { long i, carry; i = *c; carry = 0; while (i>0) { #if (!NTL_ARITH_RIGHT_SHIFT || defined(NTL_CLEAN_INT)) long t = (*(++T)) - (*(++c)) - carry; carry = (t < 0); #else long t = (*(++T)) - (*(++c)) + carry; carry = t >> NTL_NBITS; #endif *T = t & NTL_RADIXM; i--; } while (carry) { long t = (*(++T)) - 1; #if (!NTL_ARITH_RIGHT_SHIFT || defined(NTL_CLEAN_INT)) carry = (t < 0); #else carry = t >> NTL_NBITS; #endif *T = t & NTL_RADIXM; } } static void kar_add(long *c, long *T, long hsa) { long i, carry; c += hsa; i = *T; while (T[i] == 0 && i > 0) i--; carry = 0; while (i>0) { long t = (*(++c)) + (*(++T)) + carry; carry = t >> NTL_NBITS; *c = t & NTL_RADIXM; i--; } while (carry) { long t = (*(++c)) + 1; carry = t >> NTL_NBITS; *c = t & NTL_RADIXM; } } static void kar_fix(long *c, long *T, long hsa) { long i, carry, s; s = *T; i = hsa; while (i>0) { *(++c) = *(++T); i--; } i = s - hsa; carry = 0; while (i > 0) { long t = (*(++c)) + (*(++T)) + carry; carry = t >> NTL_NBITS; *c = t & NTL_RADIXM; i--; } while (carry) { long t = (*(++c)) + 1; carry = t >> NTL_NBITS; *c = t & NTL_RADIXM; } } static void kar_mul(long *c, long *a, long *b, long *stk) { long sa, sb, sc; if (*a < *b) { long *t = a; a = b; b = t; } sa = *a; sb = *b; sc = sa + sb; if (sb < KARX) { /* classic algorithm */ long *pc, i, *pb; pc = c; for (i = sc; i; i--) { pc++; *pc = 0; } pc = c; pb = b; for (i = sb; i; i--) { pb++; pc++; zaddmul(*pb, pc, a); } } else { long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long *T1, *T2, *T3; /* allocate space */ T1 = stk; stk += hsa + 2; T2 = stk; stk += hsa + 2; T3 = stk; stk += (hsa << 1) + 3; if (stk-kmem > max_kmem) zhalt("internal error: kmem overflow"); /* compute T1 = a_lo + a_hi */ kar_fold(T1, a, hsa); /* compute T2 = b_lo + b_hi */ kar_fold(T2, b, hsa); /* recursively compute T3 = T1 * T2 */ kar_mul(T3, T1, T2, stk); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ { long olda, oldb; olda = a[hsa]; a[hsa] = sa-hsa; oldb = b[hsa]; b[hsa] = sb-hsa; kar_mul(c + (hsa << 1), a + hsa, b + hsa, stk); kar_sub(T3, c + (hsa << 1)); a[hsa] = olda; b[hsa] = oldb; } /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ *a = hsa; *b = hsa; kar_mul(c, a, b, stk); kar_sub(T3, c); *a = sa; *b = sb; /* finally, add T3 * NTL_RADIX^{hsa} to c */ kar_add(c, T3, hsa); } else { /* degenerate case */ long *T; T = stk; stk += sb + hsa + 1; if (stk-kmem > max_kmem) zhalt("internal error: kmem overflow"); /* recursively compute b*a_hi into high part of c */ { long olda; olda = a[hsa]; a[hsa] = sa-hsa; kar_mul(c + hsa, a + hsa, b, stk); a[hsa] = olda; } /* recursively compute b*a_lo into T */ *a = hsa; kar_mul(T, a, b, stk); *a = sa; /* fix-up result */ kar_fix(c, T, hsa); } } /* normalize result */ while (c[sc] == 0 && sc > 1) sc--; *c = sc; } #define KARSX (32) static void kar_sq(long *c, long *a, long *stk) { long sa, sc; sa = *a; sc = sa << 1; if (sa < KARSX) { /* classic algorithm */ long carry, i, j, *pc; pc = c; for (i = sc; i; i--) { pc++; *pc = 0; } carry = 0; i = 0; for (j = 1; j <= sa; j++) { unsigned long uncar; long t; i += 2; uncar = ((unsigned long) carry) + (((unsigned long) c[i-1]) << 1); t = uncar & NTL_RADIXM; zaddmulpsq(t, a[j], carry); c[i-1] = t; zaddmulsq(sa-j, c+i, a+j); uncar = (uncar >> NTL_NBITS) + (((unsigned long) c[i]) << 1); uncar += ((unsigned long) carry); carry = uncar >> NTL_NBITS; c[i] = uncar & NTL_RADIXM; } } else { long hsa = (sa + 1) >> 1; long *T1, *T2, olda; T1 = stk; stk += hsa + 2; T2 = stk; stk += (hsa << 1) + 3; if (stk-kmem > max_kmem) zhalt("internal error: kmem overflow"); kar_fold(T1, a, hsa); kar_sq(T2, T1, stk); olda = a[hsa]; a[hsa] = sa - hsa; kar_sq(c + (hsa << 1), a + hsa, stk); kar_sub(T2, c + (hsa << 1)); a[hsa] = olda; *a = hsa; kar_sq(c, a, stk); kar_sub(T2, c); *a = sa; kar_add(c, T2, hsa); } while (c[sc] == 0 && sc > 1) sc--; *c = sc; } void _ntl_zmul(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *cc) { CRegister(mem); _ntl_verylong c = *cc; if (!a || (a[0] == 1 && a[1] == 0) || !b || (b[0] == 1 && b[1] == 0)) { _ntl_zzero(cc); return; } if (a == b) { if (a == c) { _ntl_zcopy(a, &mem); a = mem; } _ntl_zsq(a, cc); } else { long aneg, bneg, sa, sb, sc; if (a == c) { _ntl_zcopy(a, &mem); a = mem; } else if (b == c) { _ntl_zcopy(b, &mem); b = mem; } sa = *a; if (sa < 0) { *a = sa = -sa; aneg = 1; } else aneg = 0; sb = *b; if (*b < 0) { *b = sb = -sb; bneg = 1; } else bneg = 0; sc = sa + sb; if (MustAlloc(c, sc)) { _ntl_zsetlength(&c, sc); *cc = c; } /* we optimize for *very* small numbers, * avoiding all function calls and loops */ if (sa <= 3 && sb <= 3) { long carry, d; switch (sa) { case 1: switch (sb) { case 1: carry = 0; zxmulp(c[1], a[1], b[1], carry); c[2] = carry; break; case 2: carry = 0; d = a[1]; zxmulp(c[1], b[1], d, carry); zxmulp(c[2], b[2], d, carry); c[3] = carry; break; case 3: carry = 0; d = a[1]; zxmulp(c[1], b[1], d, carry); zxmulp(c[2], b[2], d, carry); zxmulp(c[3], b[3], d, carry); c[4] = carry; break; } break; case 2: switch (sb) { case 1: carry = 0; d = b[1]; zxmulp(c[1], a[1], d, carry); zxmulp(c[2], a[2], d, carry); c[3] = carry; break; case 2: carry = 0; d = b[1]; zxmulp(c[1], a[1], d, carry); zxmulp(c[2], a[2], d, carry); c[3] = carry; carry = 0; d = b[2]; zaddmulp(c[2], a[1], d, carry); zaddmulp(c[3], a[2], d, carry); c[4] = carry; break; case 3: carry = 0; d = a[1]; zxmulp(c[1], b[1], d, carry); zxmulp(c[2], b[2], d, carry); zxmulp(c[3], b[3], d, carry); c[4] = carry; carry = 0; d = a[2]; zaddmulp(c[2], b[1], d, carry); zaddmulp(c[3], b[2], d, carry); zaddmulp(c[4], b[3], d, carry); c[5] = carry; break; } break; case 3: switch (sb) { case 1: carry = 0; d = b[1]; zxmulp(c[1], a[1], d, carry); zxmulp(c[2], a[2], d, carry); zxmulp(c[3], a[3], d, carry); c[4] = carry; break; case 2: carry = 0; d = b[1]; zxmulp(c[1], a[1], d, carry); zxmulp(c[2], a[2], d, carry); zxmulp(c[3], a[3], d, carry); c[4] = carry; carry = 0; d = b[2]; zaddmulp(c[2], a[1], d, carry); zaddmulp(c[3], a[2], d, carry); zaddmulp(c[4], a[3], d, carry); c[5] = carry; break; case 3: carry = 0; d = b[1]; zxmulp(c[1], a[1], d, carry); zxmulp(c[2], a[2], d, carry); zxmulp(c[3], a[3], d, carry); c[4] = carry; carry = 0; d = b[2]; zaddmulp(c[2], a[1], d, carry); zaddmulp(c[3], a[2], d, carry); zaddmulp(c[4], a[3], d, carry); c[5] = carry; carry = 0; d = b[3]; zaddmulp(c[3], a[1], d, carry); zaddmulp(c[4], a[2], d, carry); zaddmulp(c[5], a[3], d, carry); c[6] = carry; break; } } if (c[sc] == 0) sc--; if (aneg != bneg) sc = -sc; *c = sc; if (aneg) *a = -sa; if (bneg) *b = -sb; return; } if (*a < KARX || *b < KARX) { /* classic algorithm */ long i, *pc; pc = c; for (i = sc; i; i--) { pc++; *pc = 0; } pc = c; if (*a >= *b) { long *pb = b; for (i = *pb; i; i--) { pb++; pc++; zaddmul(*pb, pc, a); } } else { long *pa = a; for (i = *pa; i; i--) { pa++; pc++; zaddmul(*pa, pc, b); } } while (c[sc] == 0 && sc > 1) sc--; if (aneg != bneg) sc = -sc; c[0] = sc; if (aneg) *a = - *a; if (bneg) *b = - *b; } else { /* karatsuba */ long n, hn, sp; if (*a < *b) n = *b; else n = *a; sp = 0; do { hn = (n + 1) >> 1; sp += (hn << 2) + 7; n = hn+1; } while (n >= KARX); if (sp > max_kmem) { if (max_kmem == 0) kmem = (long *) NTL_MALLOC(sp, sizeof(long), 0); else kmem = (long *) NTL_REALLOC(kmem, sp, sizeof(long), 0); max_kmem = sp; if (!kmem) zhalt("out of memory in karatsuba"); } kar_mul(c, a, b, kmem); if (aneg != bneg) *c = - *c; if (aneg) *a = - *a; if (bneg) *b = - *b; } } } void _ntl_zsq(_ntl_verylong a, _ntl_verylong *cc) { CRegister(mem); _ntl_verylong c = *cc; long sa, aneg, sc; if (!a || (a[0] == 1 && a[1] == 0)) { _ntl_zzero(cc); return; } if (a == c) { _ntl_zcopy(a, &mem); a = mem; } sa = *a; if (*a < 0) { *a = sa = -sa; aneg = 1; } else aneg = 0; sc = (sa) << 1; if (MustAlloc(c, sc)) { _ntl_zsetlength(&c, sc); *cc = c; } if (sa <= 3) { long carry, d; switch (sa) { case 1: carry = 0; zxmulp(c[1], a[1], a[1], carry); c[2] = carry; break; case 2: carry = 0; d = a[1]; zxmulp(c[1], a[1], d, carry); zxmulp(c[2], a[2], d, carry); c[3] = carry; carry = 0; d = a[2]; zaddmulp(c[2], a[1], d, carry); zaddmulp(c[3], a[2], d, carry); c[4] = carry; break; case 3: carry = 0; d = a[1]; zxmulp(c[1], a[1], d, carry); zxmulp(c[2], a[2], d, carry); zxmulp(c[3], a[3], d, carry); c[4] = carry; carry = 0; d = a[2]; zaddmulp(c[2], a[1], d, carry); zaddmulp(c[3], a[2], d, carry); zaddmulp(c[4], a[3], d, carry); c[5] = carry; carry = 0; d = a[3]; zaddmulp(c[3], a[1], d, carry); zaddmulp(c[4], a[2], d, carry); zaddmulp(c[5], a[3], d, carry); c[6] = carry; break; } if (c[sc] == 0) sc--; *c = sc; if (aneg) *a = -sa; return; } if (sa < KARSX) { /* classic algorithm */ long carry, i, j, *pc; pc = c; for (i = sc; i; i--) { pc++; *pc = 0; } carry = 0; i = 0; for (j = 1; j <= sa; j++) { unsigned long uncar; long t; i += 2; uncar = ((unsigned long) carry) + (((unsigned long) c[i-1]) << 1); t = uncar & NTL_RADIXM; zaddmulpsq(t, a[j], carry); c[i-1] = t; zaddmulsq(sa-j, c+i, a+j); uncar = (uncar >> NTL_NBITS) + (((unsigned long) c[i]) << 1); uncar += ((unsigned long) carry); carry = uncar >> NTL_NBITS; c[i] = uncar & NTL_RADIXM; } while (c[sc] == 0 && sc > 1) sc--; c[0] = sc; if (aneg) *a = - *a; } else { /* karatsuba */ long n, hn, sp; n = *a; sp = 0; do { hn = (n + 1) >> 1; sp += hn + hn + hn + 5; n = hn+1; } while (n >= KARSX); if (sp > max_kmem) { if (max_kmem == 0) kmem = (long *) NTL_MALLOC(sp, sizeof(long), 0); else kmem = (long *) NTL_REALLOC(kmem, sp, sizeof(long), 0); max_kmem = sp; if (!kmem) zhalt("out of memory in karatsuba"); } kar_sq(c, a, kmem); if (aneg) *a = - *a; } } long _ntl_zsdiv(_ntl_verylong a, long d, _ntl_verylong *bb) { long sa; _ntl_verylong b = *bb; if (!d) { zhalt("division by zero in _ntl_zsdiv"); } if (!a) { _ntl_zzero(bb); return (0); } if (d == 2) { long is_odd = a[1] & 1; long fix = (a[0] < 0) & is_odd; _ntl_zrshift(a, 1, bb); if (fix) _ntl_zsadd(*bb, -1, bb); return is_odd; } if ((sa = a[0]) < 0) sa = (-sa); /* if b aliases a, then b won't move */ _ntl_zsetlength(&b, sa); *bb = b; if ((d >= NTL_RADIX) || (d <= -NTL_RADIX)) { CRegister(zd); CRegister(zb); _ntl_zintoz(d, &zb); _ntl_zdiv(a, zb, &b, &zd); *bb = b; return (_ntl_ztoint(zd)); } else { long den = d; double deninv; long carry = 0; long i; long flag = (*a < 0 ? 2 : 0) | (den < 0 ? 1 : 0); if (den < 0) den = -den; deninv = 1.0 / ((double) den); if (a[sa] < den && sa > 1) carry = a[sa--]; for (i = sa; i; i--) { zdiv21(carry, a[i], den, deninv, b[i]); } while ((sa > 1) && (!(b[sa]))) sa--; b[0] = sa; if (flag) { if (flag <= 2) { if (!carry) _ntl_znegate(&b); else { _ntl_zsadd(b, 1, &b); b[0] = -b[0]; if (flag == 1) carry = carry - den; else carry = den - carry; *bb = b; } } else carry = -carry; } return (carry); } } long _ntl_zsmod(_ntl_verylong a, long d) { long sa; if (!a) { return (0); } if (d == 2) return (a[1] & 1); if (!d) { zhalt("division by zero in _ntl_zsdiv"); } if ((sa = a[0]) < 0) sa = (-sa); if ((d >= NTL_RADIX) || (d <= -NTL_RADIX)) { CRegister(zd); CRegister(zb); _ntl_zintoz(d, &zb); _ntl_zmod(a, zb, &zd); return (_ntl_ztoint(zd)); } else { long den = d; double deninv; long carry = 0; long i; long flag = (*a < 0 ? 2 : 0) | (den < 0 ? 1 : 0); if (den < 0) den = -den; deninv = 1.0 / ((double) den); if (a[sa] < den && sa > 1) carry = a[sa--]; for (i = sa; i; i--) { zrem21(carry, a[i], den, deninv); } if (flag) { if (flag <= 2) { if (carry) { if (flag == 1) carry = carry - den; else carry = den - carry; } } else carry = -carry; } return (carry); } } void _ntl_zmultirem(_ntl_verylong a, long n, long* dd, long *rr) { long j; long sa; if (!a || (a[0] == 1 && a[1] == 0)) { for (j = 0; j < n; j++) rr[j] = 0; return; } sa = a[0]; for (j = 0; j < n; j++) { long den = dd[j]; double deninv; long carry = 0; long i; long lsa = sa; deninv = 1.0 / ((double) den); if (a[lsa] < den && lsa > 1) carry = a[lsa--]; for (i = lsa; i; i--) { zrem21(carry, a[i], den, deninv); } rr[j] = carry; } } #if (defined(NTL_TBL_REM)) #if (defined(NTL_LONG_LONG)) /* This version uses the double-word long type directly. * It's a little faster that the other one. * It accumlates 8 double-word products before stepping * a higher-level accumulator. */ void _ntl_zmultirem3(_ntl_verylong a, long n, long* dd, long **ttbl, long *rr) { long sa, i, j, d, *tbl, ac0, ac1, ac2, *ap, *tp, k, carry; double dinv; NTL_LL_TYPE acc; if (!a || a[0] < 8 || a[0] >= NTL_RADIX) { _ntl_zmultirem(a, n, dd, rr); return; } sa = a[0]; for (i = 0; i < n; i++) { d = dd[i]; tbl = ttbl[i]; acc = a[1]; ac2 = 0; ap = &a[2]; tp = &tbl[1]; k = sa - 7; for (j = 0; j < k; j += 7) { acc += ((NTL_LL_TYPE) ap[j+0]) * ((NTL_LL_TYPE) tp[j+0]); acc += ((NTL_LL_TYPE) ap[j+1]) * ((NTL_LL_TYPE) tp[j+1]); acc += ((NTL_LL_TYPE) ap[j+2]) * ((NTL_LL_TYPE) tp[j+2]); acc += ((NTL_LL_TYPE) ap[j+3]) * ((NTL_LL_TYPE) tp[j+3]); acc += ((NTL_LL_TYPE) ap[j+4]) * ((NTL_LL_TYPE) tp[j+4]); acc += ((NTL_LL_TYPE) ap[j+5]) * ((NTL_LL_TYPE) tp[j+5]); acc += ((NTL_LL_TYPE) ap[j+6]) * ((NTL_LL_TYPE) tp[j+6]); ac2 += (long) (acc >> (2*NTL_NBITS)); acc &= (((NTL_LL_TYPE) 1) << (2*NTL_NBITS)) - ((NTL_LL_TYPE) 1); } k = sa - 1; for (; j < k; j++) acc += ((NTL_LL_TYPE) ap[j+0]) * ((NTL_LL_TYPE) tp[j+0]); ac2 += (long) (acc >> (2*NTL_NBITS)); acc &= (((NTL_LL_TYPE) 1) << (2*NTL_NBITS)) - ((NTL_LL_TYPE) 1); ac0 = (long) (acc & ( (((NTL_LL_TYPE) 1) << (NTL_NBITS)) - ((NTL_LL_TYPE) 1) )); ac1 = (long) (acc >> NTL_NBITS); carry = 0; dinv = ((double) 1)/((double) d); if (ac2 >= d) { zrem21(carry, ac2, d, dinv); } else carry = ac2; zrem21(carry, ac1, d, dinv); zrem21(carry, ac0, d, dinv); rr[i] = carry; } } #else void _ntl_zmultirem3(_ntl_verylong a, long n, long* dd, long **ttbl, long *rr) { long sa, i, d, *tbl, ac0, ac1, ac2, *ap, *tp, k, t, carry; double dinv; if (!a || a[0] < 8 || a[0] >= NTL_RADIX) { _ntl_zmultirem(a, n, dd, rr); return; } sa = a[0]; for (i = 0; i < n; i++) { d = dd[i]; tbl = ttbl[i]; ac0 = a[1]; ac1 = 0; ac2 = 0; ap = &a[2]; tp = &tbl[1]; k = sa-1; while (k) { zxmulp(t, *ap, *tp, ac0); ac1 += ac0; ac2 += ac1 >> NTL_NBITS; ac1 &= NTL_RADIXM; ac0 = t; k--; ap++; tp++; } carry = 0; dinv = ((double) 1)/((double) d); if (ac2 >= d) { zrem21(carry, ac2, d, dinv); } else carry = ac2; zrem21(carry, ac1, d, dinv); zrem21(carry, ac0, d, dinv); rr[i] = carry; } } #endif #endif long _ntl_zsfastrem(_ntl_verylong a, long d) /* assumes a >= 0, and 0 < d < NTL_RADIX */ /* computes a % d */ { long sa; if (!a || (a[0] == 1 && a[1] == 0)) { return 0; } sa = a[0]; { long den = d; double deninv = ((double)1)/((double)den); long carry = 0; long i; long lsa = sa; if (a[lsa] < den && lsa > 1) carry = a[lsa--]; for (i = lsa; i; i--) { zrem21(carry, a[i], den, deninv); } return carry; } } void _ntl_zdiv(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *qq, _ntl_verylong *rr) { long sa, sb, sq, i; long sign; long q1; long *rp; double btopinv, aux; CRegister(q); CRegister(r); if (!b || (((sb=b[0]) == 1) && (!b[1]))) { zhalt("division by zero in _ntl_zdiv"); } if (!a || (((sa=a[0]) == 1) && (!a[1]))) { _ntl_zzero(qq); if (rr) _ntl_zzero(rr); return; } if (sb == 1) { long t1 = _ntl_zsdiv(a, b[1], qq); if (rr) _ntl_zintoz(t1, rr); return; } if (sb == -1) { long t1 = _ntl_zsdiv(a, -b[1], qq); if (rr) _ntl_zintoz(t1, rr); return; } sign = 0; if (sa < 0) { a[0] = sa = -sa; sign = 2; } if (sb < 0) { b[0] = sb = -sb; sign |= 1; } sq = sa-sb+1; if (sq <= 0) { _ntl_zcopy(a, &r); _ntl_zzero(&q); goto done; } _ntl_zsetlength(&q, sq); _ntl_zsetlength(&r, sa+1); _ntl_zcopy(a, &r); rp = &r[sa+1]; *rp = 0; r[0] = 0; /* this streamlines the last evaluation of aux */ btopinv = b[sb]*NTL_FRADIX + b[sb-1]; if (sb > 2) btopinv = NTL_FRADIX / (btopinv*NTL_FRADIX + b[sb-2]); else btopinv = 1.0 / btopinv; aux = btopinv*(rp[-1]*NTL_FRADIX + rp[-2]); if (aux >= NTL_FRADIX) aux = NTL_FRADIX-1; for (i = sq; i >= 1; i--, rp--) { q1 = (long) aux; if (q1) { zsubmul(q1, &r[i], b); } while (rp[0] < 0) { zaddmulone(&r[i], b); q1--; } while (rp[0] > 0) { zsubmulone(&r[i], b); q1++; } aux = btopinv*((rp[-1]*NTL_FRADIX + rp[-2])*NTL_FRADIX + rp[-3]); while (aux > NTL_FRADIX - 16) { /* q1 might be too small */ if (aux >= NTL_FRADIX) aux = NTL_FRADIX-1; zsubmulone(&r[i], b); if (rp[0] < 0) { /* oops...false alarm! */ zaddmulone(&r[i], b); break; } else { q1++; aux = btopinv*((rp[-1]*NTL_FRADIX + rp[-2])*NTL_FRADIX + rp[-3]); } } q[i] = q1; } while (sq > 1 && q[sq] == 0) sq--; q[0] = sq; i = sb; while (i > 1 && r[i] == 0) i--; r[0] = i; done: if (sign) { if (sign <= 2) { if (!(r[1]) && (r[0] == 1)) _ntl_znegate(&q); else { _ntl_zsadd(q, 1, &q); _ntl_znegate(&q); if (sign == 1) _ntl_zsub(r, b, &r); else _ntl_zsub(b, r, &r); } } else _ntl_znegate(&r); if (sign & 2) a[0] = -sa; if (sign & 1) b[0] = -sb; } _ntl_zcopy(q, qq); if (rr) _ntl_zcopy(r, rr); } void _ntl_zmod(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *rr) { long sa, sb, sq, i; long sign; long q1; long *rp; double btopinv, aux; CRegister(r); if (!b || (((sb=b[0]) == 1) && (!b[1]))) { zhalt("division by zero in _ntl_zdiv"); } if (!a || (((sa=a[0]) == 1) && (!a[1]))) { _ntl_zzero(rr); return; } if (sb == 1) { _ntl_zintoz(_ntl_zsmod(a, b[1]), rr); return; } if (sb == -1) { _ntl_zintoz(_ntl_zsmod(a, -b[1]), rr); return; } sign = 0; if (sa < 0) { a[0] = sa = -sa; sign = 2; } if (sb < 0) { b[0] = sb = -sb; sign |= 1; } sq = sa-sb+1; if (sq <= 0) { _ntl_zcopy(a, &r); goto done; } _ntl_zsetlength(&r, sa+1); _ntl_zcopy(a, &r); rp = &r[sa+1]; *rp = 0; r[0] = 0; /* this streamlines the last evaluation of aux */ btopinv = b[sb]*NTL_FRADIX + b[sb-1]; if (sb > 2) btopinv = NTL_FRADIX / (btopinv*NTL_FRADIX + b[sb-2]); else btopinv = 1.0 / btopinv; aux = btopinv*(rp[-1]*NTL_FRADIX + rp[-2]); if (aux >= NTL_FRADIX) aux = NTL_FRADIX-1; for (i = sq; i >= 1; i--, rp--) { q1 = (long) aux; if (q1) { zsubmul(q1, &r[i], b); } while (rp[0] < 0) { zaddmulone(&r[i], b); } while (rp[0] > 0) { zsubmulone(&r[i], b); } aux = btopinv*((rp[-1]*NTL_FRADIX + rp[-2])*NTL_FRADIX + rp[-3]); while (aux > NTL_FRADIX - 16) { /* q1 might be too small */ if (aux >= NTL_FRADIX) aux = NTL_FRADIX-1; zsubmulone(&r[i], b); if (rp[0] < 0) { /* oops...false alarm! */ zaddmulone(&r[i], b); break; } else { aux = btopinv*((rp[-1]*NTL_FRADIX + rp[-2])*NTL_FRADIX + rp[-3]); } } } i = sb; while (i > 1 && r[i] == 0) i--; r[0] = i; done: if (sign) { if (sign <= 2) { if (!(r[1]) && (r[0] == 1)) /* no op */; else { if (sign == 1) _ntl_zsub(r, b, &r); else _ntl_zsub(b, r, &r); } } else _ntl_znegate(&r); if (sign & 2) a[0] = -sa; if (sign & 1) b[0] = -sb; } _ntl_zcopy(r, rr); } void _ntl_zquickmod(_ntl_verylong *rr, _ntl_verylong b) { long sa, sb, sq, i; long q1; long *rp; double btopinv, aux; _ntl_verylong r; sb = b[0]; r = *rr; if (!r || (((sa=r[0]) == 1) && (!r[1]))) { _ntl_zzero(rr); return; } if (sb == 1) { _ntl_zintoz(_ntl_zsmod(r, b[1]), rr); return; } sq = sa-sb+1; if (sq <= 0) { return; } _ntl_zsetlength(rr, sa+1); r = *rr; rp = &r[sa+1]; *rp = 0; r[0] = 0; /* this streamlines the last evaluation of aux */ btopinv = b[sb]*NTL_FRADIX + b[sb-1]; if (sb > 2) btopinv = NTL_FRADIX / (btopinv*NTL_FRADIX + b[sb-2]); else btopinv = 1.0 / btopinv; aux = btopinv*(rp[-1]*NTL_FRADIX + rp[-2]); if (aux >= NTL_FRADIX) aux = NTL_FRADIX-1; for (i = sq; i >= 1; i--, rp--) { q1 = (long) aux; if (q1) { zsubmul(q1, &r[i], b); } while (rp[0] < 0) { zaddmulone(&r[i], b); } while (rp[0] > 0) { zsubmulone(&r[i], b); } aux = btopinv*((rp[-1]*NTL_FRADIX + rp[-2])*NTL_FRADIX + rp[-3]); while (aux > NTL_FRADIX - 16) { /* q1 might be too small */ if (aux >= NTL_FRADIX) aux = NTL_FRADIX-1; zsubmulone(&r[i], b); if (rp[0] < 0) { /* oops...false alarm! */ zaddmulone(&r[i], b); break; } else { aux = btopinv*((rp[-1]*NTL_FRADIX + rp[-2])*NTL_FRADIX + rp[-3]); } } } i = sb; while (i > 1 && r[i] == 0) i--; r[0] = i; } void _ntl_zaddmod( _ntl_verylong a, _ntl_verylong b, _ntl_verylong n, _ntl_verylong *c ) { if (*c != n) { _ntl_zadd(a, b, c); if (_ntl_zcompare(*c, n) >= 0) _ntl_zsubpos(*c, n, c); } else { CRegister(mem); _ntl_zadd(a, b, &mem); if (_ntl_zcompare(mem, n) >= 0) _ntl_zsubpos(mem, n, c); else _ntl_zcopy(mem, c); } } void _ntl_zsubmod( _ntl_verylong a, _ntl_verylong b, _ntl_verylong n, _ntl_verylong *c ) { CRegister(mem); long cmp; if ((cmp=_ntl_zcompare(a, b)) < 0) { _ntl_zadd(n, a, &mem); _ntl_zsubpos(mem, b, c); } else if (!cmp) _ntl_zzero(c); else _ntl_zsubpos(a, b, c); } void _ntl_zsmulmod( _ntl_verylong a, long d, _ntl_verylong n, _ntl_verylong *c ) { CRegister(mem); _ntl_zsmul(a, d, &mem); _ntl_zquickmod(&mem, n); _ntl_zcopy(mem, c); } void _ntl_zmulmod( _ntl_verylong a, _ntl_verylong b, _ntl_verylong n, _ntl_verylong *c ) { CRegister(mem); _ntl_zmul(a, b, &mem); _ntl_zquickmod(&mem, n); _ntl_zcopy(mem, c); } void _ntl_zsqmod( _ntl_verylong a, _ntl_verylong n, _ntl_verylong *c ) { CRegister(mem); _ntl_zsq(a, &mem); _ntl_zquickmod(&mem, n); _ntl_zcopy(mem, c); } void _ntl_zinvmod( _ntl_verylong a, _ntl_verylong n, _ntl_verylong *c ) { if (_ntl_zinv(a, n, c)) zhalt("undefined inverse in _ntl_zinvmod"); } static long zxxeucl( _ntl_verylong ain, _ntl_verylong nin, _ntl_verylong *invv, _ntl_verylong *uu ) { CRegister(a); CRegister(n); CRegister(q); CRegister(w); CRegister(x); CRegister(y); CRegister(z); _ntl_verylong inv = *invv; _ntl_verylong u = *uu; long diff; long ilo; long sa; long sn; long temp; long e; long fast; long parity; long gotthem; _ntl_verylong pin; _ntl_verylong p; long i; long try11; long try12; long try21; long try22; long got11; long got12; long got21; long got22; double hi; double lo; double dt; double fhi, fhi1; double flo, flo1; double num; double den; double dirt; _ntl_zsetlength(&a, (e = (ain[0] > nin[0] ? ain[0] : nin[0]))); _ntl_zsetlength(&n, e); _ntl_zsetlength(&q, e); _ntl_zsetlength(&w, e); _ntl_zsetlength(&x, e); _ntl_zsetlength(&y, e); _ntl_zsetlength(&z, e); _ntl_zsetlength(&inv, e); *invv = inv; _ntl_zsetlength(&u, e); *uu = u; fhi1 = 1.0 + ((double) 32.0)/NTL_FDOUBLE_PRECISION; flo1 = 1.0 - ((double) 32.0)/NTL_FDOUBLE_PRECISION; fhi = 1.0 + ((double) 8.0)/NTL_FDOUBLE_PRECISION; flo = 1.0 - ((double) 8.0)/NTL_FDOUBLE_PRECISION; pin = &ain[0]; p = &a[0]; for (i = (*pin); i >= 0; i--) *p++ = *pin++; pin = &nin[0]; p = &n[0]; for (i = (*pin); i >= 0; i--) *p++ = *pin++; inv[0] = 1; inv[1] = 1; w[0] = 1; w[1] = 0; while (n[0] > 1 || n[1] > 0) { gotthem = 0; sa = a[0]; sn = n[0]; diff = sa - sn; if (!diff || diff == 1) { sa = a[0]; p = &a[sa]; num = ((double) (*p)) * NTL_FRADIX; if (sa > 1) num += (*(--p)); num *= NTL_FRADIX; if (sa > 2) num += (*(p - 1)); sn = n[0]; p = &n[sn]; den = (double) (*p) * NTL_FRADIX; if (sn > 1) den += (*(--p)); den *= NTL_FRADIX; if (sn > 2) den += (*(p - 1)); hi = fhi1 * (num + 1.0) / den; lo = flo1 * num / (den + 1.0); if (diff > 0) { hi *= NTL_FRADIX; lo *= NTL_FRADIX; } try11 = 1; try12 = 0; try21 = 0; try22 = 1; parity = 1; fast = 1; while (fast > 0) { parity = 1 - parity; if (hi >= NTL_FRADIX) fast = 0; else { ilo = (long)lo; dirt = hi - ilo; if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi) fast = 0; else { dt = lo-ilo; lo = flo / dirt; if (dt > 1.0/NTL_FDOUBLE_PRECISION) hi = fhi / dt; else hi = NTL_FRADIX; temp = try11; try11 = try21; if ((NTL_RADIX - temp) / ilo < try21) fast = 0; else try21 = temp + ilo * try21; temp = try12; try12 = try22; if ((NTL_RADIX - temp) / ilo < try22) fast = 0; else try22 = temp + ilo * try22; if ((fast > 0) && (parity > 0)) { gotthem = 1; got11 = try11; got12 = try12; got21 = try21; got22 = try22; } } } } } if (gotthem) { _ntl_zsmul(inv, got11, &x); _ntl_zsmul(w, got12, &y); _ntl_zsmul(inv, got21, &z); _ntl_zsmul(w, got22, &w); _ntl_zadd(x, y, &inv); _ntl_zadd(z, w, &w); _ntl_zsmul(a, got11, &x); _ntl_zsmul(n, got12, &y); _ntl_zsmul(a, got21, &z); _ntl_zsmul(n, got22, &n); _ntl_zsub(x, y, &a); _ntl_zsub(n, z, &n); } else { _ntl_zdiv(a, n, &q, &a); _ntl_zmul(q, w, &x); _ntl_zadd(inv, x, &inv); if (a[0] > 1 || a[1] > 0) { _ntl_zdiv(n, a, &q, &n); _ntl_zmul(q, inv, &x); _ntl_zadd(w, x, &w); } else { p = &a[0]; pin = &n[0]; for (i = (*pin); i >= 0; i--) *p++ = *pin++; n[0] = 1; n[1] = 0; _ntl_zcopy(w, &inv); _ntl_znegate(&inv); } } } if ((a[0] == 1) && (a[1] == 1)) e = 0; else e = 1; p = &u[0]; pin = &a[0]; for (i = (*pin); i >= 0; i--) *p++ = *pin++; *invv = inv; *uu = u; return (e); } long _ntl_zinv( _ntl_verylong ain, _ntl_verylong nin, _ntl_verylong *invv ) { CRegister(u); CRegister(v); long sgn; if (_ntl_zscompare(nin, 1) <= 0) { zhalt("InvMod: second input <= 1"); } sgn = _ntl_zsign(ain); if (sgn < 0) { zhalt("InvMod: first input negative"); } if (_ntl_zcompare(ain, nin) >= 0) { zhalt("InvMod: first input too big"); } if (sgn == 0) { _ntl_zcopy(nin, invv); return 1; } if (!(zxxeucl(ain, nin, &v, &u))) { if (_ntl_zsign(v) < 0) _ntl_zadd(v, nin, &v); _ntl_zcopy(v, invv); return 0; } _ntl_zcopy(u, invv); return 1; } void _ntl_zexteucl( _ntl_verylong aa, _ntl_verylong *xa, _ntl_verylong bb, _ntl_verylong *xb, _ntl_verylong *d ) { CRegister(modcon); CRegister(a); CRegister(b); long anegative = 0; long bnegative = 0; _ntl_zcopy(aa, &a); _ntl_zcopy(bb, &b); if (anegative = (a[0] < 0)) a[0] = -a[0]; if (bnegative = (b[0] < 0)) b[0] = -b[0]; if (!b[1] && (b[0] == 1)) { _ntl_zone(xa); _ntl_zzero(xb); _ntl_zcopy(a, d); goto done; } if (!a[1] && (a[0] == 1)) { _ntl_zzero(xa); _ntl_zone(xb); _ntl_zcopy(b, d); goto done; } zxxeucl(a, b, xa, d); _ntl_zmul(a, *xa, xb); _ntl_zsub(*d, *xb, xb); _ntl_zdiv(*xb, b, xb, &modcon); if ((modcon[1]) || (modcon[0] != 1)) { zhalt("non-zero remainder in _ntl_zexteucl BUG"); } done: if (anegative) { _ntl_znegate(xa); } if (bnegative) { _ntl_znegate(xb); } } /* I've adapted LIP's extended euclidean algorithm to * do rational reconstruction. -- VJS. */ long _ntl_zxxratrecon( _ntl_verylong ain, _ntl_verylong nin, _ntl_verylong num_bound, _ntl_verylong den_bound, _ntl_verylong *num_out, _ntl_verylong *den_out ) { CRegister(a); CRegister(n); CRegister(q); CRegister(w); CRegister(x); CRegister(y); CRegister(z); CRegister(inv); CRegister(u); CRegister(a_bak); CRegister(n_bak); CRegister(inv_bak); CRegister(w_bak); _ntl_verylong p; long diff; long ilo; long sa; long sn; long snum; long sden; long e; long fast; long temp; long parity; long gotthem; long try11; long try12; long try21; long try22; long got11; long got12; long got21; long got22; double hi; double lo; double dt; double fhi, fhi1; double flo, flo1; double num; double den; double dirt; if (_ntl_zsign(num_bound) < 0) zhalt("rational reconstruction: bad numerator bound"); if (!num_bound) snum = 1; else snum = num_bound[0]; if (_ntl_zsign(den_bound) <= 0) zhalt("rational reconstruction: bad denominator bound"); sden = den_bound[0]; if (_ntl_zsign(nin) <= 0) zhalt("rational reconstruction: bad modulus"); if (_ntl_zsign(ain) < 0 || _ntl_zcompare(ain, nin) >= 0) zhalt("rational reconstruction: bad residue"); e = nin[0]; _ntl_zsetlength(&a, e); _ntl_zsetlength(&n, e); _ntl_zsetlength(&q, e); _ntl_zsetlength(&w, e); _ntl_zsetlength(&x, e); _ntl_zsetlength(&y, e); _ntl_zsetlength(&z, e); _ntl_zsetlength(&inv, e); _ntl_zsetlength(&u, e); _ntl_zsetlength(&a_bak, e); _ntl_zsetlength(&n_bak, e); _ntl_zsetlength(&inv_bak, e); _ntl_zsetlength(&w_bak, e); fhi1 = 1.0 + ((double) 32.0)/NTL_FDOUBLE_PRECISION; flo1 = 1.0 - ((double) 32.0)/NTL_FDOUBLE_PRECISION; fhi = 1.0 + ((double) 8.0)/NTL_FDOUBLE_PRECISION; flo = 1.0 - ((double) 8.0)/NTL_FDOUBLE_PRECISION; _ntl_zcopy(ain, &a); _ntl_zcopy(nin, &n); _ntl_zone(&inv); _ntl_zzero(&w); while (1) { if (w[0] >= sden && _ntl_zcompare(w, den_bound) > 0) break; if (n[0] <= snum && _ntl_zcompare(n, num_bound) <= 0) break; _ntl_zcopy(a, &a_bak); _ntl_zcopy(n, &n_bak); _ntl_zcopy(w, &w_bak); _ntl_zcopy(inv, &inv_bak); gotthem = 0; sa = a[0]; sn = n[0]; diff = sa - sn; if (!diff || diff == 1) { sa = a[0]; p = &a[sa]; num = (double) (*p) * NTL_FRADIX; if (sa > 1) num += (*(--p)); num *= NTL_FRADIX; if (sa > 2) num += (*(p - 1)); sn = n[0]; p = &n[sn]; den = (double) (*p) * NTL_FRADIX; if (sn > 1) den += (*(--p)); den *= NTL_FRADIX; if (sn > 2) den += (*(p - 1)); hi = fhi1 * (num + 1.0) / den; lo = flo1 * num / (den + 1.0); if (diff > 0) { hi *= NTL_FRADIX; lo *= NTL_FRADIX; } try11 = 1; try12 = 0; try21 = 0; try22 = 1; parity = 1; fast = 1; while (fast > 0) { parity = 1 - parity; if (hi >= NTL_FRADIX) fast = 0; else { ilo = (long)lo; dirt = hi - ilo; if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi) fast = 0; else { dt = lo-ilo; lo = flo / dirt; if (dt > 1.0/NTL_FDOUBLE_PRECISION) hi = fhi / dt; else hi = NTL_FRADIX; temp = try11; try11 = try21; if ((NTL_RADIX - temp) / ilo < try21) fast = 0; else try21 = temp + ilo * try21; temp = try12; try12 = try22; if ((NTL_RADIX - temp) / ilo < try22) fast = 0; else try22 = temp + ilo * try22; if ((fast > 0) && (parity > 0)) { gotthem = 1; got11 = try11; got12 = try12; got21 = try21; got22 = try22; } } } } } if (gotthem) { _ntl_zsmul(inv, got11, &x); _ntl_zsmul(w, got12, &y); _ntl_zsmul(inv, got21, &z); _ntl_zsmul(w, got22, &w); _ntl_zadd(x, y, &inv); _ntl_zadd(z, w, &w); _ntl_zsmul(a, got11, &x); _ntl_zsmul(n, got12, &y); _ntl_zsmul(a, got21, &z); _ntl_zsmul(n, got22, &n); _ntl_zsub(x, y, &a); _ntl_zsub(n, z, &n); } else { _ntl_zdiv(a, n, &q, &a); _ntl_zmul(q, w, &x); _ntl_zadd(inv, x, &inv); if (a[0] > 1 || a[1] > 0) { _ntl_zdiv(n, a, &q, &n); _ntl_zmul(q, inv, &x); _ntl_zadd(w, x, &w); } else { break; } } } _ntl_zcopy(a_bak, &a); _ntl_zcopy(n_bak, &n); _ntl_zcopy(w_bak, &w); _ntl_zcopy(inv_bak, &inv); _ntl_znegate(&w); while (1) { sa = w[0]; if (sa < 0) w[0] = -sa; if (w[0] >= sden && _ntl_zcompare(w, den_bound) > 0) return 0; w[0] = sa; if (n[0] <= snum && _ntl_zcompare(n, num_bound) <= 0) break; fast = 0; sa = a[0]; sn = n[0]; diff = sa - sn; if (!diff || diff == 1) { sa = a[0]; p = &a[sa]; num = (double) (*p) * NTL_FRADIX; if (sa > 1) num += (*(--p)); num *= NTL_FRADIX; if (sa > 2) num += (*(p - 1)); sn = n[0]; p = &n[sn]; den = (double) (*p) * NTL_FRADIX; if (sn > 1) den += (*(--p)); den *= NTL_FRADIX; if (sn > 2) den += (*(p - 1)); hi = fhi1 * (num + 1.0) / den; lo = flo1 * num / (den + 1.0); if (diff > 0) { hi *= NTL_FRADIX; lo *= NTL_FRADIX; } if (hi < NTL_FRADIX) { ilo = (long)lo; if (ilo == (long)hi) fast = 1; } } if (fast) { if (ilo != 0) { if (ilo == 1) { _ntl_zsub(inv, w, &inv); _ntl_zsubpos(a, n, &a); } else if (ilo == 2) { _ntl_z2mul(w, &x); _ntl_zsub(inv, x, &inv); _ntl_z2mul(n, &x); _ntl_zsubpos(a, x, &a); } else if (ilo ==3) { _ntl_z2mul(w, &x); _ntl_zadd(w, x, &x); _ntl_zsub(inv, x, &inv); _ntl_z2mul(n, &x); _ntl_zadd(n, x, &x); _ntl_zsubpos(a, x, &a); } else if (ilo == 4) { _ntl_zlshift(w, 2, &x); _ntl_zsub(inv, x, &inv); _ntl_zlshift(n, 2, &x); _ntl_zsubpos(a, x, &a); } else { _ntl_zsmul(w, ilo, &x); _ntl_zsub(inv, x, &inv); _ntl_zsmul(n, ilo, &x); _ntl_zsubpos(a, x, &a); } } } else { _ntl_zdiv(a, n, &q, &a); _ntl_zmul(q, w, &x); _ntl_zsub(inv, x, &inv); } _ntl_zswap(&a, &n); _ntl_zswap(&inv, &w); } if (_ntl_zsign(w) < 0) { _ntl_znegate(&w); _ntl_znegate(&n); } _ntl_zcopy(n, num_out); _ntl_zcopy(w, den_out); return 1; } static long OptWinSize(long n) /* finds k that minimizes n/(k+1) + 2^{k-1} */ { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/((double)(k+2)) + ((double)(1L << k)); if (v_new >= v) break; v = v_new; k++; } return k; } static void _ntl_zsppowermod(long a, _ntl_verylong e, _ntl_verylong n, _ntl_verylong *x) { _ntl_verylong res; long i, k; if (_ntl_ziszero(e)) { _ntl_zone(x); return; } res = 0; _ntl_zsetlength(&res, n[0]); _ntl_zone(&res); k = _ntl_z2log(e); for (i = k - 1; i >= 0; i--) { _ntl_zsqmod(res, n, &res); if (_ntl_zbit(e, i)) _ntl_zsmulmod(res, a, n, &res); } if (_ntl_zsign(e) < 0) _ntl_zinvmod(res, n, &res); _ntl_zcopy(res, x); _ntl_zfree(&res); } static void _ntl_ztwopowermod( _ntl_verylong e, _ntl_verylong n, _ntl_verylong *x) { _ntl_verylong res; long i, k; if (_ntl_ziszero(e)) { _ntl_zone(x); return; } res = 0; _ntl_zsetlength(&res, n[0]); _ntl_zone(&res); k = _ntl_z2log(e); for (i = k - 1; i >= 0; i--) { _ntl_zsqmod(res, n, &res); if (_ntl_zbit(e, i)) _ntl_zaddmod(res, res, n, &res); } if (_ntl_zsign(e) < 0) _ntl_zinvmod(res, n, &res); _ntl_zcopy(res, x); _ntl_zfree(&res); } void _ntl_zpowermod(_ntl_verylong g, _ntl_verylong e, _ntl_verylong F, _ntl_verylong *h) /* h = g^e mod f using "sliding window" algorithm remark: the notation (h, g, e, F) is strange, because I copied the code from BB.c. */ { _ntl_verylong res, *v, t; long n, i, k, val, cnt, m; if (_ntl_zsign(g) < 0 || _ntl_zcompare(g, F) >= 0 || _ntl_zscompare(F, 1) <= 0) zhalt("PowerMod: bad args"); if (!g || g[0] == 1 || g[0] == -1) { long gg = _ntl_ztoint(g); if (gg == 2) _ntl_ztwopowermod(e, F, h); else _ntl_zsppowermod(gg, e, F, h); return; } if (_ntl_zscompare(e, 0) == 0) { _ntl_zone(h); return; } if (_ntl_zscompare(e, 1) == 0) { _ntl_zcopy(g, h); return; } if (_ntl_zscompare(e, -1) == 0) { _ntl_zinvmod(g, F, h); return; } if (_ntl_zscompare(e, 2) == 0) { _ntl_zsqmod(g, F, h); return; } if (_ntl_zscompare(e, -2) == 0) { res = 0; _ntl_zsqmod(g, F, &res); _ntl_zinvmod(res, F, h); _ntl_zfree(&res); return; } n = _ntl_z2log(e); res = 0; _ntl_zone(&res); if (n < 16) { /* plain square-and-multiply algorithm */ for (i = n - 1; i >= 0; i--) { _ntl_zsqmod(res, F, &res); if (_ntl_zbit(e, i)) _ntl_zmulmod(res, g, F, &res); } if (_ntl_zsign(e) < 0) _ntl_zinvmod(res, F, &res); _ntl_zcopy(res, h); _ntl_zfree(&res); return; } k = OptWinSize(n); if (k > 5) k = 5; v = (_ntl_verylong *) NTL_MALLOC(1L << (k-1), sizeof(_ntl_verylong), 0); if (!v) zhalt("out of memory"); for (i = 0; i < (1L << (k-1)); i++) v[i] = 0; _ntl_zcopy(g, &v[0]); if (k > 1) { t = 0; _ntl_zsqmod(g, F, &t); for (i = 1; i < (1L << (k-1)); i++) _ntl_zmulmod(v[i-1], t, F, &v[i]); _ntl_zfree(&t); } val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | _ntl_zbit(e, i); if (val == 0) _ntl_zsqmod(res, F, &res); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { _ntl_zsqmod(res, F, &res); m = m >> 1; } _ntl_zmulmod(res, v[val >> 1], F, &res); while (cnt > 0) { _ntl_zsqmod(res, F, &res); cnt--; } val = 0; } } if (_ntl_zsign(e) < 0) _ntl_zinvmod(res, F, &res); _ntl_zcopy(res, h); _ntl_zfree(&res); for (i = 0; i < (1L << (k-1)); i++) _ntl_zfree(&v[i]); free(v); } void _ntl_zexp( _ntl_verylong a, long e, _ntl_verylong *bb ) { long k; long len_a; long sa; CRegister(res); if (!a) sa = 0; else { sa = a[0]; if (sa < 0) sa = -sa; } if (sa <= 1) { _ntl_zexps(_ntl_ztoint(a), e, bb); return; } if (!e) { _ntl_zone(bb); return; } if (e < 0) zhalt("negative exponent in _ntl_zexp"); if (_ntl_ziszero(a)) { _ntl_zzero(bb); return; } len_a = _ntl_z2log(a); if (len_a > (NTL_MAX_LONG-(NTL_NBITS-1))/e) zhalt("overflow in _ntl_zexp"); _ntl_zsetlength(&res, (len_a*e+NTL_NBITS-1)/NTL_NBITS); _ntl_zcopy(a, &res); k = 1; while ((k << 1) <= e) k <<= 1; while (k >>= 1) { _ntl_zsq(res, &res); if (e & k) _ntl_zmul(a, res, &res); } _ntl_zcopy(res, bb); } void _ntl_zexps( long a, long e, _ntl_verylong *bb ) { long k; long len_a; CRegister(res); if (!e) { _ntl_zone(bb); return; } if (e < 0) zhalt("negative exponent in _ntl_zexps"); if (!a) { _ntl_zzero(bb); return; } if (a >= NTL_RADIX || a <= -NTL_RADIX) { _ntl_zintoz(a, &res); _ntl_zexp(res, e, &res); return; } len_a = _ntl_z2logs(a); if (len_a > (NTL_MAX_LONG-(NTL_NBITS-1))/e) zhalt("overflow in _ntl_zexps"); _ntl_zsetlength(&res, (len_a*e+NTL_NBITS-1)/NTL_NBITS); _ntl_zintoz(a, &res); k = 1; while ((k << 1) <= e) k <<= 1; while (k >>= 1) { _ntl_zsq(res, &res); if (e & k) _ntl_zsmul(res, a, &res); } _ntl_zcopy(res, bb); } void _ntl_z2mul( _ntl_verylong n, _ntl_verylong *rres ) { long sn; long i; long n_alias; long carry; _ntl_verylong res; if (!n) { _ntl_zzero(rres); return; } if ((!n[1]) && (n[0] == 1)) { _ntl_zzero(rres); return; } if ((sn = n[0]) < 0) sn = -sn; res = *rres; n_alias = (n == res); _ntl_zsetlength(&res, sn + 1); if (n_alias) n = res; *rres = res; carry = 0; for (i = 1; i <= sn; i++) { if ((res[i] = (n[i] << 1) + carry) >= NTL_RADIX) { res[i] -= NTL_RADIX; carry = 1; } else carry = 0; } if (carry) res[++sn] = 1; if (n[0] < 0) res[0] = -sn; else res[0] = sn; } long _ntl_z2div( _ntl_verylong n, _ntl_verylong *rres ) { long sn; long i; long result; _ntl_verylong res = *rres; if ((!n) || ((!n[1]) && (n[0] == 1))) { _ntl_zzero(rres); return (0); } if ((sn = n[0]) < 0) sn = -sn; /* n won't move if res aliases n */ _ntl_zsetlength(&res, sn); *rres = res; result = n[1] & 1; for (i = 1; i < sn; i++) { res[i] = (n[i] >> 1); if (n[i + 1] & 1) res[i] += (NTL_RADIX >> 1); } if (res[sn] = (n[sn] >> 1)) res[0] = n[0]; else if (sn == 1) { res[0] = 1; } else if (n[0] < 0) res[0] = -sn + 1; else res[0] = sn - 1; return (result); } void _ntl_zlshift( _ntl_verylong n, long k, _ntl_verylong *rres ) { long big; long small; long sn; long i; long cosmall; long n_alias; _ntl_verylong res; if (!n) { _ntl_zzero(rres); return; } if ((!n[1]) && (n[0] == 1)) { _ntl_zzero(rres); return; } res = *rres; n_alias = (n == res); if (!k) { if (!n_alias) _ntl_zcopy(n, rres); return; } if (k < 0) { if (k < -NTL_MAX_LONG) _ntl_zzero(rres); else _ntl_zrshift(n, -k, rres); return; } if (k == 1) { _ntl_z2mul(n, rres); return; } if ((sn = n[0]) < 0) sn = -sn; i = sn + (big = k / NTL_NBITS); if (small = k - big * NTL_NBITS) { _ntl_zsetlength(&res, i + 1); if (n_alias) n = res; *rres = res; res[i + 1] = n[sn] >> (cosmall = NTL_NBITS - small); for (i = sn; i > 1; i--) res[i + big] = ((((unsigned long) n[i]) << small) & NTL_RADIXM) + (n[i - 1] >> cosmall); res[big + 1] = (((unsigned long) n[1]) << small) & NTL_RADIXM; for (i = big; i; i--) res[i] = 0; if (res[sn + big + 1]) big++; } else { _ntl_zsetlength(&res, i); if (n_alias) n = res; *rres = res; for (i = sn; i; i--) res[i + big] = n[i]; for (i = big; i; i--) res[i] = 0; } if (n[0] > 0) res[0] = n[0] + big; else res[0] = n[0] - big; } void _ntl_zrshift( _ntl_verylong n, long k, _ntl_verylong *rres ) { long big; long small; long sn; long i; long cosmall; _ntl_verylong res; if (!n) { _ntl_zzero(rres); return; } if ((!n[1]) && (n[0] == 1)) { _ntl_zzero(rres); return; } res = *rres; if (!k) { if (n != res) _ntl_zcopy(n, rres); return; } if (k < 0) { if (k < -NTL_MAX_LONG) zhalt("overflow in _ntl_zrshift"); _ntl_zlshift(n, -k, rres); return; } if (k == 1) { _ntl_z2div(n, rres); return; } big = k / NTL_NBITS; small = k - big * NTL_NBITS; if ((sn = n[0]) < 0) sn = -sn; if ((big >= sn) || ((big == sn - 1) && small && (!(n[sn] >> small)))) /* The microsoft optimizer generates bad code without the above test for small != 0 */ { _ntl_zzero(rres); return; } sn -= big; /* n won't move if res aliases n */ _ntl_zsetlength(&res, sn); *rres = res; if (small) { cosmall = NTL_NBITS - small; for (i = 1; i < sn; i++) res[i] = (n[i + big] >> small) + ((((unsigned long) n[i + big + 1]) << cosmall) & NTL_RADIXM); if (!(res[sn] = (n[sn + big] >> small))) sn--; } else for (i = 1; i <= sn; i++) res[i] = n[i + big]; if (n[0] > 0) res[0] = sn; else res[0] = -sn; } long _ntl_zmakeodd( _ntl_verylong *nn ) { _ntl_verylong n = *nn; long i; long shift = 1; if (!n || (!n[1] && (n[0] == 1))) return (0); while (!(n[shift])) shift++; i = n[shift]; shift = NTL_NBITS * (shift - 1); while (!(i & 1)) { shift++; i >>= 1; } _ntl_zrshift(n, shift, &n); return (shift); } long _ntl_znumtwos( _ntl_verylong n ) { long i; long shift = 1; if (!n || (!n[1] && (n[0] == 1))) return (0); while (!(n[shift])) shift++; i = n[shift]; shift = NTL_NBITS * (shift - 1); while (!(i & 1)) { shift++; i >>= 1; } return (shift); } long _ntl_zsqrts( long n ) { long a; long ndiva; long newa; CRegister(ln); CRegister(rr); if (n < 0) zhalt("_ntl_zsqrts: negative argument"); if (n <= 0) return (0); if (n <= 3) return (1); if (n <= 8) return (2); if (n >= NTL_RADIX) { _ntl_zintoz(n,&ln); _ntl_zsqrt(ln,&rr); return(_ntl_ztoint(rr)); } newa = 3L << (2 * (NTL_NBITSH - 1)); a = 1L << NTL_NBITSH; while (!(n & newa)) { newa >>= 2; a >>= 1; } while (1) { newa = ((ndiva = n / a) + a) / 2; if (newa - ndiva <= 1) { if (newa * newa <= n) return (newa); else return (ndiva); } a = newa; } } void _ntl_zsqrt(_ntl_verylong n, _ntl_verylong *rr) { CRegister(a); CRegister(ndiva); CRegister(diff); CRegister(r); long i; if (!n) { _ntl_zzero(rr); return; } if ((i = n[0]) < 0) zhalt("negative argument in _ntl_zsqrt"); if (i == 1) { _ntl_zintoz(_ntl_zsqrts(n[1]), rr); return; } _ntl_zsetlength(&a, i); _ntl_zsetlength(&ndiva, i); _ntl_zsetlength(&diff, i); a[(a[0] = (i + 1) / 2)] = _ntl_zsqrts(n[i]) + 1; if (!(i & 1)) a[a[0]] <<= NTL_NBITSH; if (a[a[0]] & NTL_RADIX) { a[a[0]] = 0; a[0]++; a[a[0]] = 1; } for (i = a[0] - 1; i; i--) a[i] = 0; while (1) { _ntl_zdiv(n, a, &ndiva, &r); _ntl_zadd(a, ndiva, &r); _ntl_zrshift(r, 1, &r); if (_ntl_zcompare(r, ndiva) <= 0) goto done; _ntl_zsubpos(r, ndiva, &diff); if ((diff[0] == 1) && (diff[1] <= 1)) { _ntl_zsq(r, &diff); if (_ntl_zcompare(diff, n) > 0) _ntl_zcopy(ndiva, &r); goto done; } _ntl_zcopy(r, &a); } done: _ntl_zcopy(r, rr); } void _ntl_zgcd( _ntl_verylong mm1, _ntl_verylong mm2, _ntl_verylong *rres ) { long agrb; long shibl; CRegister(aa); CRegister(bb); CRegister(cc); _ntl_verylong a; _ntl_verylong b; _ntl_verylong c; _ntl_verylong d; long m1negative; long m2negative; /* _ntl_ziszero is necessary here and below to fix an an aliasing bug in LIP */ if (_ntl_ziszero(mm1)) { if (mm2 != *rres) _ntl_zcopy(mm2,rres); _ntl_zabs(rres); return; } if (_ntl_ziszero(mm2)) { if (mm1 != *rres) _ntl_zcopy(mm1,rres); _ntl_zabs(rres); return; } if (mm1 == mm2) { if (mm1 != *rres) _ntl_zcopy(mm1, rres); _ntl_zabs(rres); return; } if (m1negative = (mm1[0] < 0)) mm1[0] = -mm1[0]; if (m2negative = (mm2[0] < 0)) mm2[0] = -mm2[0]; if ((agrb = mm1[0]) < mm2[0]) agrb = mm2[0]; _ntl_zsetlength(&aa, agrb+1); _ntl_zsetlength(&bb, agrb+1); _ntl_zsetlength(&cc, agrb+1); if (mm1[0] != mm2[0]) { if (mm1[0] > mm2[0]) { _ntl_zcopy(mm2, &aa); _ntl_zmod(mm1, aa, &bb); } else { _ntl_zcopy(mm1, &aa); _ntl_zmod(mm2, aa, &bb); } if (!(bb[1]) && (bb[0] == 1)) { a = aa; goto done; } } else { _ntl_zcopy(mm1, &aa); _ntl_zcopy(mm2, &bb); } if ((agrb = _ntl_zmakeodd(&aa)) < (shibl = _ntl_zmakeodd(&bb))) shibl = agrb; if (!(agrb = _ntl_zcompare(aa, bb))) { a = aa; goto endshift; } else if (agrb < 0) { a = bb; b = aa; } else { a = aa; b = bb; } c = cc; _ntl_zsubpos(a, b, &c); do { _ntl_zmakeodd(&c); if (!(agrb = _ntl_zcompare(b, c))) { a = b; goto endshift; } else if (agrb > 0) { a = b; b = c; c = a; } else { d = a; a = c; c = d; } _ntl_zsubpos(a, b, &c); } while (c[1] || c[0] != 1); endshift: _ntl_zlshift(a, shibl, &a); done: if (m1negative) mm1[0] = -mm1[0]; if (m2negative) mm2[0] = -mm2[0]; _ntl_zcopy(a, rres); } long _ntl_zsign(_ntl_verylong a) { if (!a) { return (0); } if (a[0] < 0) return (-1); if (a[0] > 1) return (1); if (a[1]) return (1); return (0); } void _ntl_zabs(_ntl_verylong *pa) { _ntl_verylong a = *pa; if (!a) return; if (a[0] < 0) a[0] = (-a[0]); } long _ntl_z2logs( long aa ) { long i = 0; unsigned long a; if (aa < 0) a = - ((unsigned long) aa); else a = aa; while (a>=256) i += 8, a >>= 8; if (a >=16) i += 4, a >>= 4; if (a >= 4) i += 2, a >>= 2; if (a >= 2) i += 2; else if (a >= 1) i++; return (i); } long _ntl_z2log( _ntl_verylong a ) { long la; if (!a) return (0); la = (a[0] > 0 ? a[0] : -a[0]); return ( NTL_NBITS * (la - 1) + _ntl_z2logs(a[la]) ); } long _ntl_zscompare( _ntl_verylong a, long b ) { if (!b) return _ntl_zsign(a); else { CRegister(c); _ntl_zintoz(b, &c); return (_ntl_zcompare(a, c)); } } void _ntl_zswap( _ntl_verylong *a, _ntl_verylong *b ) { _ntl_verylong c; if ((*a && ((*a)[-1] & 1)) || (*b && ((*b)[-1] & 1))) { CRegister(t); _ntl_zcopy(*a, &t); _ntl_zcopy(*b, a); _ntl_zcopy(t, b); return; } c = *a; *a = *b; *b = c; } long _ntl_ziszero( _ntl_verylong a ) { if (!a) return (1); if (a[1]) return (0); if (a[0]==1) return (1); return (0); } long _ntl_zodd( _ntl_verylong a ) { if (!a) return (0); return (a[1]&1); } long _ntl_zbit( _ntl_verylong a, long p ) { long bl; long wh; long sa; if (p < 0 || !a) return 0; bl = (p/NTL_NBITS); wh = 1L << (p - NTL_NBITS*bl); bl ++; sa = a[0]; if (sa < 0) sa = -sa; if (sa < bl) return (0); if (a[bl] & wh) return (1); return (0); } void _ntl_zlowbits( _ntl_verylong a, long b, _ntl_verylong *cc ) { _ntl_verylong c; long bl; long wh; long sa; if (_ntl_ziszero(a) || (b<=0)) { _ntl_zzero(cc); return; } bl = b/NTL_NBITS; wh = b - NTL_NBITS*bl; if (wh != 0) bl++; else wh = NTL_NBITS; sa = a[0]; if (sa < 0) sa = -sa; if (sa < bl) { _ntl_zcopy(a,cc); _ntl_zabs(cc); return; } c = *cc; /* a won't move if c aliases a */ _ntl_zsetlength(&c, bl); *cc = c; for (sa=1; sa1) && (!c[bl])) bl --; c[0] = bl; } long _ntl_zslowbits(_ntl_verylong a, long p) { CRegister(x); if (p > NTL_BITS_PER_LONG) p = NTL_BITS_PER_LONG; _ntl_zlowbits(a, p, &x); return _ntl_ztoint(x); } long _ntl_zweights( long aa ) { unsigned long a; long res = 0; if (aa < 0) a = - ((unsigned long) aa); else a = aa; while (a) { if (a & 1) res ++; a >>= 1; } return (res); } long _ntl_zweight( _ntl_verylong a ) { long i; long res = 0; if (!a) return (0); i = a[0]; if (i<0) i = -i; for (;i;i--) res += _ntl_zweights(a[i]); return (res); } void _ntl_zand( _ntl_verylong a, _ntl_verylong b, _ntl_verylong *cc ) { _ntl_verylong c; long sa; long sb; long sm; long a_alias; long b_alias; if (_ntl_ziszero(a) || _ntl_ziszero(b)) { _ntl_zzero(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = a[0]; if (sa < 0) sa = -sa; sb = b[0]; if (sb < 0) sb = -sb; sm = (sa > sb ? sb : sa ); _ntl_zsetlength(&c, sm); if (a_alias) a = c; if (b_alias) b = c; *cc = c; for (sa = 1; sa <= sm; sa ++) c[sa] = a[sa] & b[sa]; while ((sm > 1) && (!(c[sm]))) sm --; c[0] = sm; } void _ntl_zxor( _ntl_verylong a, _ntl_verylong b, _ntl_verylong *cc ) { _ntl_verylong c; long sa; long sb; long sm; long la; long i; long a_alias; long b_alias; if (_ntl_ziszero(a)) { _ntl_zcopy(b,cc); _ntl_zabs(cc); return; } if (_ntl_ziszero(b)) { _ntl_zcopy(a,cc); _ntl_zabs(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = a[0]; if (sa < 0) sa = -sa; sb = b[0]; if (sb < 0) sb = -sb; if (sa > sb) { la = sa; sm = sb; } else { la = sb; sm = sa; } _ntl_zsetlength(&c, la); if (a_alias) a = c; if (b_alias) b = c; *cc = c; for (i = 1; i <= sm; i ++) c[i] = a[i] ^ b[i]; if (sa > sb) for (;i <= la; i++) c[i] = a[i]; else for (;i <= la; i++) c[i] = b[i]; while ((la > 1) && (!(c[la]))) la --; c[0] = la; } void _ntl_zor( _ntl_verylong a, _ntl_verylong b, _ntl_verylong *cc ) { _ntl_verylong c; long sa; long sb; long sm; long la; long i; long a_alias; long b_alias; if (_ntl_ziszero(a)) { _ntl_zcopy(b,cc); _ntl_zabs(cc); return; } if (_ntl_ziszero(b)) { _ntl_zcopy(a,cc); _ntl_zabs(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = a[0]; if (sa < 0) sa = -sa; sb = b[0]; if (sb < 0) sb = -sb; if (sa > sb) { la = sa; sm = sb; } else { la = sb; sm = sa; } _ntl_zsetlength(&c, la); if (a_alias) a = c; if (b_alias) b = c; *cc = c; for (i = 1; i <= sm; i ++) c[i] = a[i] | b[i]; if (sa > sb) for (;i <= la; i++) c[i] = a[i]; else for (;i <= la; i++) c[i] = b[i]; c[0] = la; } long _ntl_zsetbit( _ntl_verylong *a, long b ) { long bl; long wh; long sa; if (b<0) zhalt("_ntl_zsetbit: negative index"); if (_ntl_ziszero(*a)) { _ntl_zintoz(1,a); _ntl_zlshift(*a,b,a); return (0); } bl = (b/NTL_NBITS); wh = 1L << (b - NTL_NBITS*bl); bl ++; sa = (*a)[0]; if (sa<0) sa = -sa; if (sa >= bl) { sa = (*a)[bl] & wh; (*a)[bl] |= wh; if (sa) return (1); return (0); } else { _ntl_zsetlength(a,bl); sa ++; for (;sa<=bl;sa++) (*a)[sa]=0; if ((*a)[0] < 0) (*a)[0] = -bl; else (*a)[0] = bl; (*a)[bl] |= wh; return (0); } } long _ntl_zswitchbit( _ntl_verylong *a, long p ) { long bl; long wh; long sa; if (p < 0) zhalt("_ntl_zswitchbit: negative index"); if (_ntl_ziszero(*a)) { _ntl_zintoz(1,a); _ntl_zlshift(*a,p,a); return (0); } bl = (p/NTL_NBITS); wh = 1L << (p - NTL_NBITS*bl); bl ++; sa = (*a)[0]; if (sa < 0) sa = -sa; if ((sa < bl) || (!((*a)[bl] & wh))) { _ntl_zsetbit(a,p); return (0); } (*a)[bl] ^= wh; while ((sa>1) && (!(*a)[sa])) sa --; if ((*a)[0] > 0) (*a)[0] = sa; else (*a)[0] = -sa; return (1); } long _ntl_zsize(_ntl_verylong rep) { if (!rep || (rep[0] == 1 && rep[1] == 0)) return 0; else if (rep[0] < 0) return -rep[0]; else return rep[0]; } long _ntl_zdigit(_ntl_verylong rep, long i) { long sa; if (i < 0 || !rep) return 0; sa = rep[0]; if (sa < 0) sa = -sa; if (i >= sa) return 0; return rep[i+1]; } long _ntl_zisone(_ntl_verylong rep) { return rep != 0 && rep[0] == 1 && rep[1] == 1; } long _ntl_zsptest(_ntl_verylong rep) { return !rep || rep[0] == 1 || rep[0] == -1; } long _ntl_zwsptest(_ntl_verylong rep) { return !rep || rep[0] == 1 || rep[0] == -1; } long _ntl_zcrtinrange(_ntl_verylong g, _ntl_verylong a) { long sa, sg, carry, i, diff; if (!a || a[0] < 0 || (a[0] == 1 && a[1] == 0)) return 0; sa = a[0]; if (!g) return 1; sg = g[0]; if (sg == 1 && g[1] == 0) return 1; if (sg < 0) sg = -sg; if (sa-sg > 1) return 1; if (sa-sg < 0) return 0; carry=0; if (sa-sg == 1) { if (a[sa] > 1) return 1; carry = 1; } i = sg; diff = 0; while (i > 0 && diff == 0) { diff = (carry << (NTL_NBITS-1)) + (a[i] >> 1) - g[i]; carry = (a[i] & 1); i--; } if (diff == 0) { if (carry) return 1; return (g[0] > 0); } else return (diff > 0); } void _ntl_zfrombytes(_ntl_verylong *x, const unsigned char *p, long n) { long sz; long i; _ntl_verylong a; long bitpos, wordpos, bitoffset, diff; if (n <= 0) { _ntl_zzero(x); return; } if (n > (NTL_MAX_LONG-(NTL_NBITS-1))/8) zhalt("ZZFromBytes: excessive length"); sz = (n*8 + NTL_NBITS-1)/NTL_NBITS; _ntl_zsetlength(x, sz); a = *x; for (i = 1; i <= sz; i++) a[i] = 0; for (i = 0; i < n; i++) { bitpos = i*8; wordpos = bitpos/NTL_NBITS; bitoffset = bitpos - wordpos*NTL_NBITS; diff = NTL_NBITS-bitoffset; if (diff < 8) { a[wordpos+1] |= ((( ((unsigned long)(p[i])) & 255UL ) << bitoffset) & NTL_RADIXM); a[wordpos+2] = ( ((long)(p[i])) & 255 ) >> diff; } else { a[wordpos+1] |= (( ((long)(p[i])) & 255 ) << bitoffset); } } while (sz > 1 && a[sz] == 0) sz--; a[0] = sz; } void _ntl_zbytesfromz(unsigned char *p, _ntl_verylong a, long nn) { long k = _ntl_z2log(a); long n = (k+7)/8; long sz = _ntl_zsize(a); long min_n = ((n < nn) ? n : nn); long i; for (i = 0; i < min_n; i++) { long bitpos = i*8; long wordpos = bitpos/NTL_NBITS; long bitoffset = bitpos - wordpos*NTL_NBITS; long diff; p[i] = (a[wordpos+1] >> bitoffset) & 255; diff = NTL_NBITS - bitoffset; if (diff < 8 && wordpos < sz-1) { long msk = (1L << (8-diff))-1; p[i] |= ((a[wordpos+2] & msk) << diff); } } for (i = min_n; i < nn; i++) p[i] = 0; } long _ntl_zblock_construct_alloc(_ntl_verylong *x, long d, long n) { long nwords, nbytes, AllocAmt, m, *p, *q, j; /* check n value */ if (n <= 0) zhalt("block construct: n must be positive"); /* check d value */ if (d <= 0) zhalt("block construct: d must be positive"); if (NTL_OVERFLOW(d, NTL_NBITS, NTL_NBITS) || NTL_OVERFLOW(d, sizeof(long), 3*sizeof(long))) zhalt("block construct: d too large"); nwords = d + 3; nbytes = nwords*sizeof(long); AllocAmt = (NTL_MAX_ALLOC_BLOCK - sizeof(long)) / nbytes; if (AllocAmt == 0) AllocAmt = 1; if (AllocAmt < n) m = AllocAmt; else m = n; p = (long *) NTL_MALLOC(m, nbytes, sizeof(long)); if (!p) zhalt("out of memory in block construct"); *p = m; q = p+2; *x = q; for (j = 0; j < m; j++) { q[-1] = ((d+1) << 1) | 1; q[0] = 1; q[1] = 0; q += nwords; } return m; } void _ntl_zblock_construct_set(_ntl_verylong x, _ntl_verylong *y, long i) { long d, size; d = (x[-1] >> 1) - 1; size = d + 3; *y = x + i*size; } long _ntl_zblock_destroy(_ntl_verylong x) { long m, *p; p = x - 2; m = *p; free(p); return m; } long _ntl_zblock_storage(long d) { long size = d+3; return size * (sizeof (long)) + sizeof(_ntl_verylong); } /* The following routines provide special support for ZZ_pX * arithmetic. */ /* this is a generic single-precision mul mod that will work * on any platform */ #define SP_MUL_MOD(r, a, b, n) \ { \ long l__a = (a); \ long l__b = (b); \ long l__n = (n); \ long l__q; \ unsigned long l__res; \ \ l__q = (long) ((((double) l__a) * ((double) l__b)) / ((double) l__n)); \ l__res = ((unsigned long) l__a)*((unsigned long) l__b) - \ ((unsigned long) l__q)*((unsigned long) l__n); \ if (l__res >> (NTL_BITS_PER_LONG-1)) \ l__res += l__n; \ else if (((long) l__res) >= l__n) \ l__res -= l__n; \ \ r = (long) l__res; \ } static void sp_ext_eucl(long *dd, long *ss, long *tt, long a, long b) { long u, v, u0, v0, u1, v1, u2, v2, q, r; long aneg = 0, bneg = 0; if (a < 0) { if (a < -NTL_MAX_LONG) zhalt("integer overflow"); a = -a; aneg = 1; } if (b < 0) { if (b < -NTL_MAX_LONG) zhalt("integer overflow"); b = -b; bneg = 1; } u1=1; v1=0; u2=0; v2=1; u = a; v = b; while (v != 0) { q = u / v; r = u % v; u = v; v = r; u0 = u2; v0 = v2; u2 = u1 - q*u2; v2 = v1- q*v2; u1 = u0; v1 = v0; } if (aneg) u1 = -u1; if (bneg) v1 = -v1; *dd = u; *ss = u1; *tt = v1; } static long sp_inv_mod(long a, long n) { long d, s, t; sp_ext_eucl(&d, &s, &t, a, n); if (d != 1) zhalt("inverse undefined"); if (s < 0) return s + n; else return s; } /* Data structures and algorithms for fast Chinese Remaindering */ struct crt_body_lip { _ntl_verylong *v; long sbuf; long n; }; struct crt_body { long strategy; union { struct crt_body_lip L; } U; // FIXME: don't need union any more }; long _ntl_crt_struct_special(void *crt_struct) { struct crt_body *c = (struct crt_body *) crt_struct; return (c->strategy == 2); } void _ntl_crt_struct_init(void **crt_struct, long n, _ntl_verylong p, const long *primes) { struct crt_body *c; c = (struct crt_body *) NTL_MALLOC(1, sizeof(struct crt_body), 0); if (!c) zhalt("out of memory"); { struct crt_body_lip *C = &c->U.L; long i; c->strategy = 0; C->n = n; C->v = (_ntl_verylong *) NTL_MALLOC(n, sizeof(_ntl_verylong), 0); if (!C->v) zhalt("out of memory"); for (i = 0; i < n; i++) C->v[i] = 0; C->sbuf = p[0]+3; *crt_struct = (void *) c; } } void _ntl_crt_struct_insert(void *crt_struct, long i, _ntl_verylong m) { struct crt_body *c = (struct crt_body *) crt_struct; switch (c->strategy) { case 0: { _ntl_zcopy(m, &c->U.L.v[i]); break; } default: zhalt("_ntl_crt_struct_insert: inconsistent strategy"); } /* end switch */ } void _ntl_crt_struct_free(void *crt_struct) { struct crt_body *c = (struct crt_body *) crt_struct; switch (c->strategy) { case 0: { struct crt_body_lip *C = &c->U.L; long i, n; n = C->n; for (i = 0; i < n; i++) _ntl_zfree(&C->v[i]); free(C->v); free(c); break; } default: zhalt("_ntl_crt_struct_free: inconsistent strategy"); } /* end case */ } void _ntl_crt_struct_eval(void *crt_struct, _ntl_verylong *x, const long *b) { struct crt_body *c = (struct crt_body *) crt_struct; switch (c->strategy) { case 0: { struct crt_body_lip *C = &c->U.L; _ntl_verylong xx, yy, *a; long i, sx, n; n = C->n; sx = C->sbuf; _ntl_zsetlength(x, sx); xx = *x; a = C->v; for (i = 1; i <= sx; i++) xx[i] = 0; xx++; for (i = 0; i < n; i++) { yy = a[i]; if (!yy || !b[i]) continue; zaddmul(b[i], xx, yy); yy = xx + yy[0]; if ((*yy) >= NTL_RADIX) { (*yy) -= NTL_RADIX; yy++; while ((*yy) == NTL_RADIX-1) { *yy = 0; yy++; } (*yy)++; } } xx--; while (sx > 1 && xx[sx] == 0) sx--; xx[0] = sx; break; } default: zhalt("_crt_struct_eval: inconsistent strategy"); } /* end case */ } /* Data structures and algorithms for multi-modulus remaindering */ struct rem_body_lip { long n; long *primes; }; #if (defined(NTL_TBL_REM)) struct rem_body_tbl { long n; long *primes; long **tbl; }; #endif struct rem_body { long strategy; union { struct rem_body_lip L; #if (defined(NTL_TBL_REM)) struct rem_body_tbl T; #endif } U; }; void _ntl_rem_struct_init(void **rem_struct, long n, _ntl_verylong modulus, const long *p) { struct rem_body *r; r = (struct rem_body *) NTL_MALLOC(1, sizeof(struct rem_body), 0); if (!r) zhalt("out of memory"); #if (defined(NTL_TBL_REM)) { struct rem_body_tbl *R = &r->U.T; long *qq; long i; long **tbl; long t, t1, j, q; long sz = modulus[0]; r->strategy = 3; R->n = n; qq = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!qq) zhalt("out of memory"); R->primes = qq; for (i = 0; i < n; i++) qq[i] = p[i]; tbl = (long **) NTL_MALLOC(n, sizeof(long *), 0); if (!tbl) zhalt("out of space"); for (i = 0; i < n; i++) { tbl[i] = (long *) NTL_MALLOC(sz, sizeof(long), 0); if (!tbl[i]) zhalt("out of space"); } R->tbl = tbl; for (i = 0; i < n; i++) { q = qq[i]; t = (((long)1) << NTL_NBITS) % q; t1 = 1; tbl[i][0] = 1; for (j = 1; j < sz; j++) { SP_MUL_MOD(t1, t1, t, q); tbl[i][j] = t1; } } *rem_struct = (void *) r; return; } #endif { struct rem_body_lip *R = &r->U.L; long *q; long i; r->strategy = 0; R->n = n; q = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!q) zhalt("out of memory"); R->primes = q; for (i = 0; i < n; i++) q[i] = p[i]; *rem_struct = (void *) r; } } void _ntl_rem_struct_free(void *rem_struct) { struct rem_body *r = (struct rem_body *) rem_struct; switch (r->strategy) { case 0: { free(r->U.L.primes); free(r); break; } #if (defined(NTL_TBL_REM)) case 3: { struct rem_body_tbl *R = &r->U.T; long n = R->n; long **tbl = R->tbl; long i; for (i = 0; i < n; i++) free(tbl[i]); free(tbl); free(R->primes); free(r); break; } #endif default: zhalt("_ntl_rem_struct_free: inconsistent strategy"); } /* end switch */ } void _ntl_rem_struct_eval(void *rem_struct, long *x, _ntl_verylong a) { struct rem_body *r = (struct rem_body *) rem_struct; switch (r->strategy) { case 0: { struct rem_body_lip *R = &r->U.L; _ntl_zmultirem(a, R->n, R->primes, x); return; } #if (defined(NTL_TBL_REM)) case 3: { struct rem_body_tbl *R = &r->U.T; _ntl_zmultirem3(a, R->n, R->primes, R->tbl, x); break; } #endif default: zhalt("_ntl_rem_struct_eval: inconsistent strategy"); } /* end switch */ } void _ntl_zaorsmul_1(_ntl_verylong x, long y, long sub, _ntl_verylong *ww) { CRegister(tmp); if (y == 0) return; if (y == 1) { if (sub) _ntl_zsub(*ww, x, ww); else _ntl_zadd(*ww, x, ww); return; } if (y == -1) { if (!sub) _ntl_zsub(*ww, x, ww); else _ntl_zadd(*ww, x, ww); return; } _ntl_zsmul(x, y, &tmp); if (sub) _ntl_zsub(*ww, tmp, ww); else _ntl_zadd(*ww, tmp, ww); } void _ntl_zsaddmul(_ntl_verylong x, long y, _ntl_verylong *ww) { _ntl_zaorsmul_1(x, y, 0, ww); } void _ntl_zssubmul(_ntl_verylong x, long y, _ntl_verylong *ww) { _ntl_zaorsmul_1(x, y, 1, ww); } void _ntl_zaorsmul(_ntl_verylong x, _ntl_verylong y, long sub, _ntl_verylong *ww) { CRegister(tmp); _ntl_zmul(x, y, &tmp); if (sub) _ntl_zsub(*ww, tmp, ww); else _ntl_zadd(*ww, tmp, ww); } void _ntl_zaddmul(_ntl_verylong x, _ntl_verylong y, _ntl_verylong *ww) { _ntl_zaorsmul(x, y, 0, ww); } void _ntl_zsubmul(_ntl_verylong x, _ntl_verylong y, _ntl_verylong *ww) { _ntl_zaorsmul(x, y, 1, ww); } ntl-6.2.1/src/cfile000644 000765 000024 00000035140 12377144456 014432 0ustar00shoupstaff000000 000000 #ifndef NTL_config__H #define NTL_config__H /************************************************************************* NTL Configuration File ---------------------- This file may be modified prior to building NTL so as to specify some basic configuration options, and to customize how code is generated so as to improve performance. The Basic Configuration Options must be set by hand. If you use the configuration wizard, then these flags should be set before the installation process begins; there values will be retained by the wizard. The Performance Options can be set either by hand, by editing this file, or (on most Unix platforms) can be set automatically using the configuration wizard which runs when NTL is installed. All NTL header files include this file. By setting these flags here, instead of on the compiler command line, it is easier to guarantee that NTL library and client code use consistent settings. How to do it ------------ To set a flag, just replace the pre-processor directive 'if 0' by 'if 1' for that flag, which causes the appropriate macro to be defined. Of course, to unset a flag, just replace the 'if 1' by an 'if 0'. You can also do this more conveniently via the command line using the configure script. *************************************************************************/ /************************************************************************* * * Basic Configuration Options * *************************************************************************/ /* None of these flags are set by the configuration wizard; * they must be set by hand, before installation begins. */ #if @{NTL_STD_CXX} #define NTL_STD_CXX /* * Use this flag if you want to use the "Standard C++" version of NTL. * In this version, all of NTL is "wrapped" inside the namespace NTL, * and are no longer directly accessible---you must either use * explicit qualification, or using directives, or using declarations. * However, note that all names that begin with "NTL_" are macros, * and as such do not belong to any namespace. * Additionally, instead of including the standard headers * , , and , the standard headers * , , and are included. * These "wrap" some (but not all) names in namespace std. * Also, the 'nothrow' version on the 'new' operator is used. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* The following three flags may be used if you want to use some * of the features of Standard C++, but your compiler is deficient. * Instead of setting the NTL_STD_CXX, you can set any subset * of the these three. Setting all three of these flags is equivalent * to setting NTL_STD_CXX. No harm is done if NTL_STD_CXX is set * and some of the following three flags are set. * * To re-build after changing any of these flags: rm *.o; make ntl.a */ #if @{NTL_PSTD_NNS} #define NTL_PSTD_NNS /* Set if NTL library components are to be wrapped in namespace 'NTL'. */ #endif #if @{NTL_PSTD_NHF} #define NTL_PSTD_NHF /* Set if you want to use the new header files , , and * , instead of the traditional header files , * , and . * If new header files are used, then it is assumed that all standard * library components are wrapped in namespace std; otherwise, * it is assumed that all standard library components are in the * global namespace. * * Also, when set, some internal NTL files use the header * in place of . */ #endif #if @{NTL_PSTD_NTN} #define NTL_PSTD_NTN /* Set if you want to use the 'nothrow' version of new. */ #endif #if @{NTL_GMP_LIP} #define NTL_GMP_LIP /* * Use this flag if you want to use GMP as the long integer package. * This can result in significantly faster code on some platforms. * It requires that the GMP package (version >= 3.1) has already been * installed. You will also have to set the variables GMP_OPT_INCDIR, * GMP_OPT_LIBDIR, GMP_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GMP_LIP=on * to that script. * * Beware that setting this flag can break some very old NTL codes. * * To re-build after changing this flag: * rm *.o; make setup3; make ntl.a * You may also have to edit the makefile to modify the variables * GMP_OPT_INCDIR, GMP_OPT_LIBDIR, and GMP_OPT_LIB. */ #endif #if @{NTL_GF2X_LIB} #define NTL_GF2X_LIB /* * Use this flag if you want to use the gf2x library for * faster GF2X arithmetic. * This can result in significantly faster code, especially * when working with polynomials of huge degree. * You will also have to set the variables GF2X_OPT_INCDIR, * GF2X_OPT_LIBDIR, GF2X_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GF2X_LIB=on * to that script. * * To re-build after changing this flag: * rm GF2X.o; GF2X1.o; make ntl.a * You may also have to edit the makefile to modify the variables * GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, and GF2X_OPT_LIB. */ #endif #if @{FLAG_LONG_LONG_TYPE} #define NTL_LONG_LONG_TYPE @{NTL_LONG_LONG_TYPE} /* * If you set the flag NTL_LONG_LONG, then the value of * NTL_LONG_LONG_TYPE will be used * to declare 'double word' signed integer types. * Irrelevant when NTL_GMP_LIP is set. * If left undefined, some "ifdef magic" will attempt * to find the best choice for your platform, depending * on the compiler and wordsize. On 32-bit machines, * this is usually 'long long'. * * To re-build after changing this flag: rm lip.o; make ntl.a */ #endif #if @{FLAG_UNSIGNED_LONG_LONG_TYPE} #define NTL_UNSIGNED_LONG_LONG_TYPE @{NTL_UNSIGNED_LONG_LONG_TYPE} /* * If you set the flag NTL_SPMM_ULL, then the value of * NTL_UNSIGNED_LONG_LONG_TYPE will be used * to declare 'double word' unsigned integer types. * If left undefined, some "ifdef magic" will attempt * to find the best choice for your platform, depending * on the compiler and wordsize. On 32-bit machines, * this is usually 'unsigned long long'. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if @{NTL_CLEAN_INT} #define NTL_CLEAN_INT /* * This will disallow the use of some non-standard integer arithmetic * that may improve performance somewhat. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if @{NTL_CLEAN_PTR} #define NTL_CLEAN_PTR /* * This will disallow the use of some non-standard pointer arithmetic * that may improve performance somewhat. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if @{NTL_RANGE_CHECK} #define NTL_RANGE_CHECK /* * This will generate vector subscript range-check code. * Useful for debugging, but it slows things down of course. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if @{NTL_NO_INIT_TRANS} #define NTL_NO_INIT_TRANS /* * Without this flag, NTL uses a special code sequence to avoid * copying large objects in return statements. However, if your * compiler optimizes away the return of a *named* local object, * this is not necessary, and setting this flag will result * in *slightly* more compact and efficient code. Although * the emeriging C++ standard allows compilers to perform * this optimization, I know of none that currently do. * Most will avoid copying *temporary* objects in return statements, * and NTL's default code sequence exploits this fact. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if @{NTL_X86_FIX} #define NTL_X86_FIX /* * Forces the "x86 floating point fix", overriding the default behavior. * By default, NTL will apply the "fix" if it looks like it is * necessary, and if knows how to fix it. * The problem addressed here is that x86 processors sometimes * run in a mode where FP registers have more precision than doubles. * This will cause code in quad_float.c some trouble. * NTL can normally correctly detect the problem, and fix it, * so you shouldn't need to worry about this or the next flag. * To re-build after changing this flag: rm quad_float.o; make ntl.a * */ #elif @{NTL_NO_X86_FIX} #define NTL_NO_X86_FIX /* * Forces no "x86 floating point fix", overriding the default behavior. * To re-build after changing this flag: rm quad_float.o; make ntl.a */ #endif /************************************************************************* * * Performance Options * *************************************************************************/ /* One can choose one of three different stragtegies for long integer * arithmetic: the default, NTL_LONG_LONG, or NTL_AVOID_FLOAT. * The configuration wizard will choose among them. * */ #if @{NTL_LONG_LONG} #define NTL_LONG_LONG /* * * For platforms that support it, this flag can be set to cause * the low-level multiplication code to use the type "long long", * which may yield a significant performance gain, * but on others, it can yield no improvement and can even * slow things down. * * * See below (NTL_LONG_LONG_TYPE) for how to use a type name * other than "long long". * * If you set NTL_LONG_LONG, you might also want to set * the flag NTL_TBL_REM (see below). * * To re-build after changing this flag: rm lip.o; make ntl.a */ #elif @{NTL_AVOID_FLOAT} #define NTL_AVOID_FLOAT /* * * On machines with slow floating point or---more comminly---slow int/float * conversions, this flag can lead to faster code. * * If you set NTL_AVOID_FLOAT, you should probably also * set NTL_TBL_REM (see below). * * To re-build after changing this flag: rm lip.o; make ntl.a */ #endif /* There are four strategies to implmement single-precision * modular multiplication with precondinition (see the MulModPrecon * function in the ZZ module): the default, NTL_SPMM_UL, and NTL_SPMM_ULL, * and NTL_SPMM_ASM. * This plays a crucial role in the "small prime FFT" used to * implement polynomial arithmetic, and in other CRT-based methods * (such as linear algebra over ZZ), as well as polynomial and matrix * arithmetic over zz_p. */ #if @{NTL_SPMM_UL} #define NTL_SPMM_UL /* The default MulModPrecon implementation uses a mix of * int and float arithmetic, which may be slow on certain machines. * This flag causes an "all integer" implementation to be used. * It is entirely portable. * To re-build after changing this flag: rm *.o; make ntl.a */ #elif @{NTL_SPMM_ULL} #define NTL_SPMM_ULL /* Like this previous flag, this also causes an "all integer" * implementation of MulModPrecon to be used. * It us usually a faster implementation, * but it is not enturely portable. * It relies on double-word unsigned multiplication * (see NTL_UNSIGNED_LONG_LONG_TYPE above). * * To re-build after changing this flag: rm *.o; make ntl.a */ #elif @{NTL_SPMM_ASM} #define NTL_SPMM_ASM /* Like this previous two flag, this also causes an "all integer" * implementation of MulModPrecon to be used. * It relies assembler code to do double-word unsigned multiplication. * This is only supported on a select mechines under GCC. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* * The following two flags provide additional control for how the * FFT modulo single-precision primes is implemented. */ #if @{NTL_FFT_BIGTAB} #define NTL_FFT_BIGTAB /* * Precomputed tables are used to store all the roots of unity * used in an FFT computation for the first NTL_FFT_BIGTAB_LIMIT * FFT primes (the latter is defined in FFT.h). This can * lead to significant time savings but at the const of some space: * in the worst case, the precomputed tables will take of space * log_2(NTL_FFT_BUGTAB_LIMIT) * M, where M is roughly the maxmimum * space occupied by any one polynomial that was involved in an * FFT computation (this could be a polynomial over zz_p, ZZ_p, or ZZ). * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if @{NTL_FFT_LAZYMUL} #define NTL_FFT_LAZYMUL /* * This flag only has an effect when combined with the NTL_FFT_BIGTAB * flag, and either the NTL_SPMM_ULL or NTL_SPMM_ASM flags. * When set, a "lazy multiplication" strategy due to David Harvey: * see his paper "FASTER ARITHMETIC FOR NUMBER-THEORETIC TRANSFORMS". * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* The next five flags NTL_AVOID_BRANCHING, NTL_TBL_REM, * NTL_GF2X_ALTCODE, NTL_GF2X_ALTCODE1, and NTL_GF2X_NOINLINE * are also set by the configuration wizard. */ #if @{NTL_AVOID_BRANCHING} #define NTL_AVOID_BRANCHING /* * With this option, branches are replaced at several * key points with equivalent code using shifts and masks. * It may speed things up on machines with * deep pipelines and high branch penalities. * This flag mainly affects the implementation of the * single-precision modular arithmetic routines. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if @{NTL_TBL_REM} #define NTL_TBL_REM /* * * With this flag, some divisions are avoided in the * ZZ_pX multiplication routines. If you use the NTL_AVOID_FLOAT * or NTL_LONG_LONG flags, then you should probably use this one too. * * Irrelevent when NTL_GMP_LIP is set. * * To re-build after changing this flag: * rm lip.o; make ntl.a */ #endif #if @{NTL_GF2X_ALTCODE} #define NTL_GF2X_ALTCODE /* * With this option, the default strategy for implmenting low-level * GF2X multiplication is replaced with an alternative strategy. * This alternative strategy seems to work better on RISC machines * with deep pipelines and high branch penalties (like a powerpc), * but does no better (or even worse) on x86s. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #elif @{NTL_GF2X_ALTCODE1} #define NTL_GF2X_ALTCODE1 /* * Yest another alternative strategy for implementing GF2X * multiplication. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #endif #if @{NTL_GF2X_NOINLINE} #define NTL_GF2X_NOINLINE /* * By default, the low-level GF2X multiplication routine in inlined. * This can potentially lead to some trouble on some platforms, * and you can override the default by setting this flag. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #endif /* The following flag is not set by the configuration wizard; its use * is not generally recommended. */ @{WIZARD_HACK} #endif ntl-6.2.1/src/configure000755 000765 000024 00000000545 12377144456 015335 0ustar00shoupstaff000000 000000 #!/bin/sh # This is just a shell script that calls perl. # Since perl may be located in a wierd place, this # should be more portable than using a direct "shebang". # Also, some shells do not handle "$@" correctly when # no options are supplied, so this is handled as a special case. if test $# -ne 0 then perl DoConfig "$@" else perl DoConfig fi ntl-6.2.1/src/ctools.c000644 000765 000024 00000005026 12377144456 015074 0ustar00shoupstaff000000 000000 #include #include #include /* * An IEEE double x is finite if and only if x - x == 0. * The function _ntl_IsFinite implements this logic; however, * it does not completely trust that an optimizing compiler * really implements this correctly, and so it goes out of its way to * confuse the compiler. For a good compiler that respects IEEE floating * point arithmetic, this may not be necessary, but it is better * to be a bit paranoid. * * Like the routine _ntl_ForceToMem below, this routine has the * side effect of forcing its argument into memory. */ NTL_THREAD_LOCAL volatile double _ntl_IsFinite__local; NTL_THREAD_LOCAL volatile double *_ntl_IsFinite__ptr1 = &_ntl_IsFinite__local; NTL_THREAD_LOCAL volatile double *_ntl_IsFinite__ptr2 = &_ntl_IsFinite__local; NTL_THREAD_LOCAL volatile double *_ntl_IsFinite__ptr3 = &_ntl_IsFinite__local; NTL_THREAD_LOCAL volatile double *_ntl_IsFinite__ptr4 = &_ntl_IsFinite__local; long _ntl_IsFinite(double *p) { *_ntl_IsFinite__ptr1 = *p; *_ntl_IsFinite__ptr3 = (*_ntl_IsFinite__ptr2 - *p); if (*_ntl_IsFinite__ptr4 != 0.0) return 0; return 1; } /* * On machines with wide floating point registers, the routine _ntl_ForceToMem * is used to force a floating point double to a memory location. * This relies on "separate compilation" model, so that optimizing * compilers cannot "optimize away" the whole thing. */ #if (NTL_EXT_DOUBLE) void _ntl_ForceToMem(double *p) { *_ntl_IsFinite__ptr1 = *p; *p = *_ntl_IsFinite__ptr2; } #else void _ntl_ForceToMem(double *p) { } #endif /* * The routine _ntl_ldexp(x, e) is like the standard ldexp(x, e) routine, * except that it takes a long exponent e, rather than an int exponenet. * Some care is taken to ensure reasonable overflow/undeflow behavior. * If the value of e does not fit into an int, then the result * is x*infinity or x*0, as appropriate. * Of course, this can only happen on platforms where long is wider * than int (e.g., most 64-bit platforms). * * We go out of our way to hide the fact that we are multiplying/dividing * by zero, so as to avoid unnecessary warnings, and to prevent * overly-agressive optimizing compilers from screwing things up. */ NTL_THREAD_LOCAL volatile double _ntl_ldexp_zero = 0.0; double _ntl_ldexp(double x, long e) { if (e > NTL_MAX_INT) return x/_ntl_ldexp_zero; else if (e < NTL_MIN_INT) return x*_ntl_ldexp_zero; else return ldexp(x, ((int) e)); } void _ntl_abort() { _ntl_abort_cxx_callback(); abort(); } ntl-6.2.1/src/def_makefile000644 000765 000024 00000041752 12377144457 015752 0ustar00shoupstaff000000 000000 ############################################################### # # First, choose a C++ compiler, and set compiler flags. # This is done by setting the variables CXX and CXXFLAGS. # ############################################################### CXX=g++ # A C++ compiler, e.g., g++, CC, xlC CXXFLAGS=-O2 # Flags for the C++ compiler # Some useful flags: # -O2 -- recommended level of optimization # -m64 -- needed to get 64-bit longs on some platforms # -g -- debugging AR=ar # command to make a library ARFLAGS=ruv # arguments for AR RANLIB=ranlib # set to echo if you want to disable it completely LDFLAGS= # libraries for linking C++ programs LDLIBS=-lm # libraries for linking C++ programs CPPFLAGS= # arguments for the C preprocessor LIBTOOL=libtool # libtool command DEF_PREFIX=/usr/local PREFIX=$(DEF_PREFIX) LIBDIR=$(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include DOCDIR=$(PREFIX)/share/doc # where to install NTL ############################################################### # # Second, if you want to use GMP (the GNU Multi-Precision library), # define the variables GMP_OPT_INCDIR, GMP_OPT_LIBDIR, GMP_OPT_LIB below. # You also will have to set either NTL_GMP_LIP or NTL_GMP_HACK # in the config.h file. # # Using GMP can lead to significant performance gains on some # platforms. You can obtain GMP from http://www.swox.com/gmp. # Once you unpack it into a directory, just execute # ./configure; make # in that directory. # ############################################################### GMP_PREFIX=$(DEF_PREFIX) GMP_INCDIR=$(GMP_PREFIX)/include # directory containing gmp.h if using GMP GMP_LIBDIR=$(GMP_PREFIX)/lib # directory containing libgmp.a if using GMP GMP_OPT_INCDIR=# -I$(GMP_INCDIR) # GMPI GMP_OPT_LIBDIR=# -L$(GMP_LIBDIR) # GMPL GMP_OPT_LIB=# -lgmp # GMP # uncomment these if using GMP ############################################################### # # Third, if you want to use gf2x (a library for fast # multiplication over GF(2)[X]), you need to # define the variables GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, GF2X_OPT_LIB below. # You also will have to set NTL_GF2X_LIB # in the config.h file. # ############################################################### GF2X_PREFIX=$(DEF_PREFIX) GF2X_INCDIR=$(GF2X_PREFIX)/include # directory containing gf2x.h if using gf2x GF2X_LIBDIR=$(GF2X_PREFIX)/lib # directory containing libgf2x.a GF2X_OPT_INCDIR=# -I$(GF2X_INCDIR) # GF2X GF2X_OPT_LIBDIR=# -L$(GF2X_LIBDIR) # GF2X GF2X_OPT_LIB=# -lgf2x # GF2X # uncomment these if using gf2x ############################################################### # # Fourth, if you do not want to run the wizard that automagically # sets some performace related flags in config.h, set the flag below. # ############################################################### WIZARD=on # Set to off if you want to bypass the wizard; otherwise, set to on. ################################################################# # # That's it! You can ignore everything else in this file! # ################################################################# # object files O01=FFT.o FacVec.o GF2.o GF2E.o GF2EX.o GF2EXFactoring.o GF2X.o GF2X1.o O02=$(O01) GF2XFactoring.o GF2XVec.o GetTime.o HNF.o ctools.o LLL.o LLL_FP.o O03=$(O02) LLL_QP.o LLL_RR.o LLL_XD.o RR.o WordVector.o ZZ.o ZZVec.o O04=$(O03) ZZX.o ZZX1.o ZZXCharPoly.o ZZXFactoring.o ZZ_p.o ZZ_pE.o ZZ_pEX.o O05=$(O04) ZZ_pEXFactoring.o ZZ_pX.o ZZ_pX1.o ZZ_pXCharPoly.o ZZ_pXFactoring.o O06=$(O05) fileio.o lip.o lzz_p.o lzz_pE.o lzz_pEX.o lzz_pEXFactoring.o O07=$(O06) lzz_pX.o lzz_pX1.o lzz_pXCharPoly.o lzz_pXFactoring.o O08=$(O07) mat_GF2.o mat_GF2E.o mat_RR.o mat_ZZ.o mat_ZZ_p.o O09=$(O08) mat_ZZ_pE.o mat_lzz_p.o mat_lzz_pE.o mat_poly_ZZ.o O10=$(O09) mat_poly_ZZ_p.o mat_poly_lzz_p.o O11=$(O10) O12=$(O11) O13=$(O12) quad_float.o tools.o vec_GF2.o vec_GF2E.o O14=$(O13) vec_RR.o vec_ZZ.o vec_ZZ_p.o vec_ZZ_pE.o O15=$(O14) vec_lzz_p.o vec_lzz_pE.o O16=$(O15) O17=$(O16) O18=$(O17) xdouble.o O19=$(O18) G_LLL_FP.o G_LLL_QP.o G_LLL_XD.o G_LLL_RR.o OBJ=$(O19) # library source files S01=FFT.c FacVec.c GF2.c GF2E.c GF2EX.c GF2EXFactoring.c GF2X.c GF2X1.c S02=$(S01) GF2XFactoring.c GF2XVec.c HNF.c ctools.c LLL.c LLL_FP.c LLL_QP.c S03=$(S02) LLL_RR.c LLL_XD.c RR.c WordVector.c ZZ.c ZZVec.c ZZX.c ZZX1.c S04=$(S03) ZZXCharPoly.c ZZXFactoring.c ZZ_p.c ZZ_pE.c ZZ_pEX.c S05=$(S04) ZZ_pEXFactoring.c ZZ_pX.c ZZ_pX1.c ZZ_pXCharPoly.c S06=$(S05) ZZ_pXFactoring.c fileio.c lip.c lzz_p.c lzz_pE.c lzz_pEX.c S07=$(S06) lzz_pEXFactoring.c lzz_pX.c lzz_pX1.c S08=$(S07) lzz_pXCharPoly.c lzz_pXFactoring.c mat_GF2.c mat_GF2E.c S09=$(S08) mat_RR.c mat_ZZ.c mat_ZZ_p.c mat_ZZ_pE.c mat_lzz_p.c mat_lzz_pE.c S10=$(S09) mat_poly_ZZ.c mat_poly_ZZ_p.c mat_poly_lzz_p.c S11=$(S10) S12=$(S11) S13=$(S12) quad_float.c tools.c vec_GF2.c vec_GF2E.c vec_RR.c S14=$(S13) vec_ZZ.c vec_ZZ_p.c vec_ZZ_pE.c S15=$(S14) vec_lzz_p.c vec_lzz_pE.c S16=$(S15) S17=$(S16) S18=$(S17) xdouble.c S19=$(S18) G_LLL_FP.c G_LLL_QP.c G_LLL_XD.c G_LLL_RR.c SRC = $(S19) # library source files that are header files SINC = c_lip_impl.h g_lip_impl.h # library header files IN01= FFT.h FacVec.h GF2.h GF2E.h GF2EX.h GF2EXFactoring.h GF2X.h IN02=$(IN01) GF2XFactoring.h GF2XVec.h HNF.h ctools.h LLL.h IN03=$(IN02) RR.h SPMM_ASM.h WordVector.h ZZ.h ZZVec.h ZZX.h ZZXFactoring.h IN04=$(IN03) ZZ_p.h ZZ_pE.h ZZ_pEX.h ZZ_pEXFactoring.h ZZ_pX.h ZZ_pXFactoring.h IN05=$(IN04) fileio.h lip.h lzz_p.h lzz_pE.h lzz_pEX.h lzz_pEXFactoring.h IN06=$(IN05) lzz_pX.h lzz_pXFactoring.h mat_GF2.h mat_GF2E.h mat_RR.h IN07=$(IN06) mat_ZZ.h mat_ZZ_p.h mat_ZZ_pE.h mat_lzz_p.h mat_lzz_pE.h IN08=$(IN07) mat_poly_ZZ.h mat_poly_ZZ_p.h mat_poly_lzz_p.h matrix.h IN09=$(IN08) pair.h vector.h pair_GF2EX_long.h pair_GF2X_long.h IN10=$(IN09) pair_ZZX_long.h pair_ZZ_pEX_long.h pair_ZZ_pX_long.h IN11=$(IN10) pair_lzz_pEX_long.h pair_lzz_pX_long.h quad_float.h IN12=$(IN11) tools.h vec_GF2.h vec_GF2E.h vec_GF2XVec.h vec_RR.h IN13=$(IN12) vec_ZZ.h vec_ZZVec.h vec_ZZ_p.h vec_ZZ_pE.h vec_double.h IN14=$(IN13) vec_long.h vec_lzz_p.h vec_lzz_pE.h vec_quad_float.h IN15=$(IN14) vec_vec_GF2.h vec_vec_GF2E.h vec_vec_RR.h vec_vec_ZZ.h IN16=$(IN15) vec_vec_ZZ_p.h vec_vec_ZZ_pE.h vec_vec_long.h vec_vec_lzz_p.h IN17=$(IN16) vec_vec_lzz_pE.h vec_xdouble.h xdouble.h config.h version.h IN18=$(IN17) def_config.h new.h vec_ulong.h vec_vec_ulong.h c_lip.h g_lip.h INCL=$(IN18) # test data TD1=BerlekampTestIn BerlekampTestOut CanZassTestIn CanZassTestOut TD2=$(TD1) ZZXFacTestIn ZZXFacTestOut MoreFacTestIn LLLTestIn LLLTestOut RRTestIn RRTestOut TD3=$(TD2) MatrixTestIn MatrixTestOut CharPolyTestIn TD4=$(TD3) CharPolyTestOut QuadTestIn QuadTestOut TD = $(TD4) # test source files TS1=QuickTest.c BerlekampTest.c CanZassTest.c ZZXFacTest.c MoreFacTest.c LLLTest.c TS2=$(TS1) subset.c MatrixTest.c CharPolyTest.c RRTest.c QuadTest.c TS3=$(TS2) GF2XTest.c GF2EXTest.c BitMatTest.c ZZ_pEXTest.c lzz_pEXTest.c Timing.c TS = $(TS3) # scripts SCRIPTS1=MakeGetTime TestScript dosify unixify RemoveProg SCRIPTS2=$(SCRIPTS1) configure DoConfig mfile cfile ppscript SCRIPTS=$(SCRIPTS2) # auxilliary source MD=MakeDesc.c MakeDescAux.c newnames.c gen_gmp_aux.c GT=GetTime1.c GetTime2.c GetTime3.c GetTime4.c GetTime5.c TestGetTime.c # documentation D01=copying.txt GF2.txt GF2E.txt GF2EX.txt GF2EXFactoring.txt GF2X.txt D02=$(D01) GF2XFactoring.txt GF2XVec.txt HNF.txt LLL.txt RR.txt D03=$(D02) ZZ.txt ZZVec.txt ZZX.txt ZZXFactoring.txt ZZ_p.txt ZZ_pE.txt D04=$(D03) ZZ_pEX.txt ZZ_pEXFactoring.txt ZZ_pX.txt ZZ_pXFactoring.txt D05=$(D04) conversions.txt flags.txt lzz_p.txt lzz_pE.txt lzz_pEX.txt D06=$(D05) lzz_pEXFactoring.txt lzz_pX.txt lzz_pXFactoring.txt mat_GF2.txt D07=$(D06) mat_GF2E.txt mat_RR.txt mat_ZZ.txt mat_ZZ_p.txt mat_ZZ_pE.txt D08=$(D07) mat_lzz_p.txt mat_lzz_pE.txt mat_poly_ZZ.txt mat_poly_ZZ_p.txt D09=$(D08) mat_poly_lzz_p.txt matrix.txt pair.txt vector.txt D10=$(D09) quad_float.txt sedscript.txt tools.txt vec_GF2.txt D11=$(D10) vec_GF2E.txt vec_RR.txt vec_ZZ.txt vec_ZZ_p.txt vec_ZZ_pE.txt D12=$(D11) vec_lzz_p.txt vec_lzz_pE.txt xdouble.txt names.txt D13=$(D12) tour-ack.html tour-intro.html tour-time.html tour-changes.html D14=$(D13) tour-modules.html tour-stdcxx.html tour-unix.html tour-examples.html D15=$(D14) tour-roadmap.html tour-win.html tour-impl.html tour-struct.html D16=$(D15) tour.html tour-ex1.html tour-ex2.html tour-ex3.html tour-ex4.html D17=$(D16) tour-ex5.html tour-ex6.html arrow1.gif arrow2.gif arrow3.gif D18=$(D17) tour-gmp.html tour-gf2x.html tour-tips.html config.txt version.txt TX01=GF2.txt GF2E.txt GF2EX.txt GF2EXFactoring.txt GF2X.txt GF2XFactoring.txt TX02=GF2XVec.txt HNF.txt LLL.txt RR.txt ZZ.txt ZZVec.txt ZZX.txt ZZXFactoring.txt TX03=ZZ_p.txt ZZ_pE.txt ZZ_pEX.txt ZZ_pEXFactoring.txt ZZ_pX.txt ZZ_pXFactoring.txt TX04=lzz_p.txt lzz_pE.txt lzz_pEX.txt lzz_pEXFactoring.txt lzz_pX.txt TX05=lzz_pXFactoring.txt mat_GF2.txt mat_GF2E.txt mat_RR.txt mat_ZZ.txt mat_ZZ_p.txt TX06=mat_ZZ_pE.txt mat_lzz_p.txt mat_lzz_pE.txt mat_poly_ZZ.txt mat_poly_ZZ_p.txt TX07=mat_poly_lzz_p.txt matrix.txt pair.txt quad_float.txt tools.txt vec_GF2.txt TX08=vec_GF2E.txt vec_RR.txt vec_ZZ.txt vec_ZZ_p.txt vec_ZZ_pE.txt vec_lzz_p.txt TX09=vec_lzz_pE.txt vector.txt version.txt xdouble.txt TXFILES=$(TX01) $(TX02) $(TX03) $(TX04) $(TX05) $(TX06) $(TX07) $(TX08) $(TX09) HT01=GF2.cpp.html GF2E.cpp.html GF2EX.cpp.html GF2EXFactoring.cpp.html GF2X.cpp.html GF2XFactoring.cpp.html HT02=GF2XVec.cpp.html HNF.cpp.html LLL.cpp.html RR.cpp.html ZZ.cpp.html ZZVec.cpp.html ZZX.cpp.html ZZXFactoring.cpp.html HT03=ZZ_p.cpp.html ZZ_pE.cpp.html ZZ_pEX.cpp.html ZZ_pEXFactoring.cpp.html ZZ_pX.cpp.html ZZ_pXFactoring.cpp.html HT04=lzz_p.cpp.html lzz_pE.cpp.html lzz_pEX.cpp.html lzz_pEXFactoring.cpp.html lzz_pX.cpp.html HT05=lzz_pXFactoring.cpp.html mat_GF2.cpp.html mat_GF2E.cpp.html mat_RR.cpp.html mat_ZZ.cpp.html mat_ZZ_p.cpp.html HT06=mat_ZZ_pE.cpp.html mat_lzz_p.cpp.html mat_lzz_pE.cpp.html mat_poly_ZZ.cpp.html mat_poly_ZZ_p.cpp.html HT07=mat_poly_lzz_p.cpp.html matrix.cpp.html pair.cpp.html quad_float.cpp.html tools.cpp.html vec_GF2.cpp.html HT08=vec_GF2E.cpp.html vec_RR.cpp.html vec_ZZ.cpp.html vec_ZZ_p.cpp.html vec_ZZ_pE.cpp.html vec_lzz_p.cpp.html HT09=vec_lzz_pE.cpp.html vector.cpp.html version.cpp.html xdouble.cpp.html HTFILES=$(HT01) $(HT02) $(HT03) $(HT04) $(HT05) $(HT06) $(HT07) $(HT08) $(HT09) DOC = $(D18) $(HTFILES) # test program executables PROG1=QuickTest BerlekampTest CanZassTest ZZXFacTest MoreFacTest LLLTest BitMatTest PROG2=$(PROG1) MatrixTest CharPolyTest RRTest QuadTest PROG3=$(PROG2) GF2XTest GF2EXTest subset ZZ_pEXTest lzz_pEXTest Timing PROGS = $(PROG3) # things to save to a tar file SFI1=makefile $(SRC) $(SINC) $(SCRIPTS) $(MD) $(GT) $(TS) $(TD) mach_desc.win SFI2=$(SFI1) MulTimeTest.c PolyTimeTest.c Poly1TimeTest.c GF2XTimeTest.c SFI3=$(SFI2) InitSettings.c DispSettings.c WizardAux Wizard def_makefile SFILES=$(SFI3) ################################################################# # # Rules for compiling the library # ################################################################# NTL_INCLUDE = -I../include -I. # NTL needs this to find its include files COMPILE = $(CXX) $(NTL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) -c LINK = $(CXX) $(NTL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) # 'make all' does a complete make, including all setup. # It also creates the file 'all', which means you should # run 'make clobber' before running 'make' or 'make all' # again. all: make setup1 make setup2 make setup3 make setup4 make ntl.a touch all # setup1 generates the file ../incluse/NTL/mach_desc.h setup1: $(COMPILE) MakeDescAux.c $(LINK) -o MakeDesc MakeDesc.c MakeDescAux.o $(LDLIBS) ./MakeDesc mv mach_desc.h ../include/NTL/mach_desc.h # setup2 generates the file GetTime.c setup2: sh MakeGetTime "$(LINK)" "$(LDLIBS)" # setup3 generates the file ../include/NTL/gmp_aux.h # The file ../include/NTL/gmp_aux.h is included in ../include/NTL/lip.h # when NTL_GMP_LIP is set. # When this flag is not set, an empty files produced. setup3: $(LINK) $(GMP_OPT_INCDIR) -o gen_gmp_aux gen_gmp_aux.c $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) ./gen_gmp_aux > ../include/NTL/gmp_aux.h # setup4 runs the wizard setup4: sh Wizard $(WIZARD) ntl.a: $(OBJ) $(AR) $(ARFLAGS) ntl.a $(OBJ) #LSTAT - $(RANLIB) ntl.a #LSTAT # $(LIBTOOL) --mode=link $(LINK) -o libntl.la $(OBJ:.o=.lo) $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) -rpath $(LIBDIR) -version-info `cat VERSION_INFO` #LSHAR LCOMP= #LSTAT # LCOMP=$(LIBTOOL) --mode=compile #LSHAR lip.o: lip.c g_lip_impl.h c_lip_impl.h $(LCOMP) $(COMPILE) $(GMP_OPT_INCDIR) lip.c ctools.o: ctools.c $(LCOMP) $(COMPILE) ctools.c GetTime.o: GetTime.c $(LCOMP) $(COMPILE) GetTime.c .c.o: $(LCOMP) $(COMPILE) $(GF2X_OPT_INCDIR) $< .c: $(LINK) -o $@ $< ntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) #LSTAT # $(LIBTOOL) --mode=link $(LINK) -o $@ $< libntl.la #LSHAR ################################################################# # # Rule for running tests # make check runs a series of tests # ################################################################# check: sh RemoveProg $(PROGS) make QuickTest ./QuickTest sh RemoveProg QuickTest sh TestScript ################################################################# # # Rule for installing # make install just does a simple copy of the include file # and library. The -p option is used to preserve file attributes. # This helps avoid some problems (especially when copying ntl.a). # Also, an attempt is made to make everything that is # installed readable by everyone. # # make uninstall removes these files # ################################################################# install: mkdir -p -m 755 $(INCLUDEDIR) rm -rf $(INCLUDEDIR)/NTL mkdir -m 755 $(INCLUDEDIR)/NTL cp -p ../include/NTL/*.h $(INCLUDEDIR)/NTL - chmod -R a+r $(INCLUDEDIR)/NTL mkdir -p -m 755 $(DOCDIR) rm -rf $(DOCDIR)/NTL mkdir -m 755 $(DOCDIR)/NTL cp -p ../doc/*.txt $(DOCDIR)/NTL cp -p ../doc/*.html $(DOCDIR)/NTL cp -p ../doc/*.gif $(DOCDIR)/NTL - chmod -R a+r $(DOCDIR)/NTL mkdir -p -m 755 $(LIBDIR) cp -p ntl.a $(LIBDIR)/libntl.a #LSTAT - chmod a+r $(LIBDIR)/libntl.a #LSTAT # $(LIBTOOL) --mode=install cp -p libntl.la $(LIBDIR) #LSHAR uninstall: rm -f $(LIBDIR)/libntl.a #LSTAT # $(LIBTOOL) --mode=uninstall rm -f $(LIBDIR)/libntl.la #LSHAR rm -rf $(INCLUDEDIR)/NTL rm -rf $(DOCDIR)/NTL ################################################################# # # Rules for cleaning up # # make clobber removes *everything* created by make, # but it does not restore config.h to its default. # # make clean tidies up a bit # ################################################################# clobber: rm -f ntl.a mach_desc.h ../include/NTL/mach_desc.h GetTime.c rm -f ../include/NTL/gmp_aux.h sh RemoveProg $(PROGS) MakeDesc TestGetTime gen_gmp_aux rm -f *.o rm -rf small rm -f cfileout mfileout rm -rf .libs *.lo libntl.la rm -f all clean: sh RemoveProg MakeDesc TestGetTime gen_gmp_aux rm -f *.o rm -rf small # - $(LIBTOOL) --mode=clean rm -f libntl.la *.lo #LSHAR ################################################################# # # Rules for making tar and zip files # # make ppdoc creates pretty-printed versions of some documentation # - run before make package or make winpack # # make package creates a tar.gz file suitable for Unix # # make winpack creates a zip file suitable for Windows # ################################################################# ppdoc: sh ppscript "$(TXFILES)" package: sh unixify "$(SFILES) DIRNAME WINDIR VERSION_INFO NOTES" "$(INCL)" "$(DOC)" rm -rf `cat DIRNAME` rm -f `cat DIRNAME`.tar rm -f `cat DIRNAME`.tar.gz mv unix `cat DIRNAME` chmod -R a+rX `cat DIRNAME` tar -cvf `cat DIRNAME`.tar `cat DIRNAME` gzip `cat DIRNAME`.tar rm -rf `cat DIRNAME` winpack: sh dosify "$(SRC)" "$(INCL)" "$(DOC)" "$(TS)" "$(TD)" "$(SINC)" rm -rf `cat WINDIR` rm -f `cat WINDIR`.zip mv dos `cat WINDIR` chmod -R a+rX `cat WINDIR` find ./`cat WINDIR` '!' -name '*.gif' -print | zip -l `cat WINDIR` -@ find ./`cat WINDIR` -name '*.gif' -print | zip -u `cat WINDIR` -@ rm -rf `cat WINDIR` ###################################################################### # # config wizard related stuff # ###################################################################### WO1 = FFT.o GetTime.o ctools.o ZZ.o ZZVec.o ZZ_p.o ZZ_pX.o WO2 = $(WO1) ZZ_pX1.o lip.o tools.o vec_ZZ.o vec_ZZ_p.o WO3 = $(WO2) GF2.o WordVector.o vec_GF2.o GF2X.o GF2X1.o WOBJ = $(WO3) # wntl.a: LCOMP= #LSHAR wntl.a: $(WOBJ) $(AR) $(ARFLAGS) wntl.a $(WOBJ) - $(RANLIB) wntl.a MulTimeTest: $(LINK) -o MulTimeTest MulTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) PolyTimeTest: $(LINK) -o PolyTimeTest PolyTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) Poly1TimeTest: $(LINK) -o Poly1TimeTest Poly1TimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) GF2XTimeTest: $(LINK) -o GF2XTimeTest GF2XTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) InitSettings: $(LINK) -o InitSettings InitSettings.c $(LDLIBS) DispSettings: $(LINK) -o DispSettings DispSettings.c $(LDLIBS) ntl-6.2.1/src/dosify000644 000765 000024 00000001671 12377144456 014647 0ustar00shoupstaff000000 000000 rm -r dos mkdir dos mkdir dos/src mkdir dos/include mkdir dos/include/NTL mkdir dos/doc mkdir dos/GetTime mkdir dos/MakeDesc mkdir dos/misc mkdir dos/tests cp ../README dos/README.txt cp GetTime4.c dos/src/GetTime.cpp cp mach_desc.win dos/include/NTL/mach_desc.h cp GetTime1.c dos/GetTime/GetTime1.cpp cp GetTime2.c dos/GetTime/GetTime2.cpp cp GetTime3.c dos/GetTime/GetTime3.cpp cp GetTime4.c dos/GetTime/GetTime4.cpp cp GetTime5.c dos/GetTime/GetTime5.cpp cp MakeDesc.c dos/MakeDesc/MakeDesc.cpp cp MakeDescAux.c dos/MakeDesc/MakeDescAux.cpp cp newnames.c dos/misc/newnames.cpp cp gen_gmp_aux.c dos/misc/gen_gmp_aux.cpp for i in $1 do cp $i dos/src/`basename $i .c`.cpp done for i in $2 do cp ../include/NTL/$i dos/include/NTL/$i done for i in $3 do cp ../doc/$i dos/doc/$i done for i in $4 do cp $i dos/tests/`basename $i .c`.cpp done cp $5 dos/tests cp $6 dos/src cp ../include/NTL/def_config.h dos/include/NTL/config.h ntl-6.2.1/src/fileio.c000644 000765 000024 00000002150 12377144456 015033 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL void OpenWrite(ofstream& s, const char *name) { s.open(name, ios::out); if (!s) { cerr << "open write error: " << name; Error(""); } } void OpenRead(ifstream& s, const char *name) { s.open(name, ios::in); if (!s) { cerr << "open read error: " << name; Error(""); } } #define SBUF_SZ (1024) NTL_THREAD_LOCAL static char sbuf[SBUF_SZ]; char *FileName(const char* stem, const char *ext) { if (strlen(stem) + 1 + strlen(ext) >= SBUF_SZ) Error("bad file name"); strcpy(sbuf, stem); strcat(sbuf, "-"); strcat(sbuf, ext); return sbuf; } char *FileName(const char* stem, const char *ext, long d) { if (strlen(stem) + 1 + strlen(ext) + 1 + 5 >= SBUF_SZ) Error("bad file name"); strcpy(sbuf, stem); strcat(sbuf, "-"); strcat(sbuf, ext); strcat(sbuf, "-"); char dbuf[6]; dbuf[5] = '\0'; long i, dd; dd = d; for (i = 4; i >= 0; i--) { dbuf[i] = IntValToChar(dd % 10); dd = dd / 10; } strcat(sbuf, dbuf); return sbuf; } NTL_END_IMPL ntl-6.2.1/src/g_lip_impl.h000644 000765 000024 00000322007 12377144456 015712 0ustar00shoupstaff000000 000000 /* * This is a "wrapper" layer that builds on top of the "mpn" layer of gmp. * This layer provides much of the same functionality of the "mpz" * layer of gmp, but the interface it provides is much more like * the interface provided by lip. * * This layer was written under the following assumptions about gmp: * 1) mp_limb_t is an unsigned integral type * 2) sizeof(mp_limb_t) == sizeof(long) or sizeof(mp_limb_t) == 2*sizeof(long) * 3) the number of bits of an mp_limb_t is equal to that of a long, * or twice that of a long * 4) the number of bits of a gmp radix is equal to the number of bits * of an mp_limb_t * * Except for assumption (1), these assumptions are verified in the * installation script, and they should be universally satisfied in practice, * except when gmp is built using the proposed, new "nail" fetaure * (in which some bits of an mp_limb_t are unused). * The code here will not work properly with the "nail" feature; * however, I have (attempted to) identify all such problem spots, * and any other places where assumptions (2-4) are made, * with a comment labeled "DIRT". */ #include #include #include #include #include #include typedef mp_limb_t *_ntl_limb_t_ptr; #if (__GNU_MP_VERSION < 3) #error "You have to use GNP version >= 3.1" #endif #if ((__GNU_MP_VERSION == 3) && (__GNU_MP_VERSION_MINOR < 1)) #error "You have to use GNP version >= 3.1" #endif /* v 3.1 is supposed mpn_tdiv_qr defined, but it doesn't. Here's a workaround */ #if ((__GNU_MP_VERSION == 3) && (__GNU_MP_VERSION_MINOR == 1) && (__GNU_MP_VERSION_PATCHLEVEL == 0)) #define mpn_tdiv_qr __MPN(tdiv_qr) extern "C" void mpn_tdiv_qr(mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t); #endif union gbigint_header { long info[2]; mp_limb_t alignment; }; /* A bigint is represented as two long's, ALLOC and SIZE, followed by a * vector DATA of mp_limb_t's. * * ALLOC is of the form * (alloc << 2) | continue_flag | frozen_flag * where * - alloc is the number of allocated mp_limb_t's, * - continue flag is either 2 or 0, * - frozen_flag is either 1 or 0. * If frozen_flag is set, then the space for this bigint is *not* * managed by the _ntl_gsetlength and _ntl_gfree routines, * but are instead managed by the vec_ZZ_p and ZZVec routines. * The continue_flag is only set when the frozen_flag is set. * * SIZE is the number of mp_limb_t's actually * used by the bigint, with the sign of SIZE having * the sign of the bigint. * Note that the zero bigint is represented as SIZE=0. * * Bigint's are accessed through a handle, which is pointer to void. * A null handle logically represents the bigint zero. * This is done so that the interface presented to higher level * routines is essentially the same as that of NTL's traditional * long integer package. * * The components ALLOC, SIZE, and DATA are all accessed through * macros using pointer casts. While all of may seem a bit dirty, * it should be quite portable: objects are never referenced * through pointers of different types, and no alignmement * problems should arise. * * DIRT: This rule is broken in the file g_lip.h: the inline definition * of _ntl_gmaxalloc in that file has the definition of ALLOC pasted in. * * Actually, mp_limb_t is usually the type unsigned long. * However, on some 64-bit platforms, the type long is only 32 bits, * and gmp makes mp_limb_t unsigned long long in this case. * This is fairly rare, as the industry standard for Unix is to * have 64-bit longs on 64-bit machines. */ #if 0 #define ALLOC(p) (((long *) (p))[0]) #define SIZE(p) (((long *) (p))[1]) #define DATA(p) ((mp_limb_t *) (((long *) (p)) + 2)) #define STORAGE(len) ((long)(2*sizeof(long) + (len)*sizeof(mp_limb_t))) /* DIRT: STORAGE computes the number of bytes to allocate for a bigint * of maximal SIZE len. This should be computed so that one * can store several such bigints in a contiguous array * of memory without breaking any alignment requirements. * Currently, it is assumed (and explicitly checked in the NTL installation * script) that sizeof(mp_limb_t) is either sizeof(long) or * 2*sizeof(long), and therfore, nothing special needs to * be done to enfoce alignment requirements. If this assumption * should change, then the storage layout for bigints must be * re-designed. */ #define MustAlloc(c, len) (!(c) || (ALLOC(c) >> 2) < (len)) #define GET_SIZE_NEG(sz, neg, p) \ do \ { \ long _s; \ _s = SIZE(p); \ if (_s < 0) { \ sz = -_s; \ neg = 1; \ } \ else { \ sz = _s; \ neg = 0; \ } \ } \ while (0) #define STRIP(sz, p) \ do \ { \ long _i; \ _i = sz - 1; \ while (_i >= 0 && p[_i] == 0) _i--; \ sz = _i + 1; \ } \ while (0) #define ZEROP(p) (!p || !SIZE(p)) #define ONEP(p) (p && SIZE(p) == 1 && DATA(p)[0] == 1) #define SWAP_BIGINT(a, b) \ do \ { \ _ntl_gbigint _t; \ _t = a; \ a = b; \ b = _t; \ } \ while (0) #define SWAP_LONG(a, b) \ do \ { \ long _t; \ _t = a; \ a = b; \ b = _t; \ } \ while (0) #define SWAP_LIMB_PTR(a, b) \ do \ { \ _ntl_limb_t_ptr _t; \ _t = a; \ a = b; \ b = _t; \ } \ while (0) #define COUNT_BITS(cnt, a) \ do \ { \ long _i = 0; \ mp_limb_t _a = (a); \ \ while (_a>=256) \ _i += 8, _a >>= 8; \ if (_a >=16) \ _i += 4, _a >>= 4; \ if (_a >= 4) \ _i += 2, _a >>= 2; \ if (_a >= 2) \ _i += 2; \ else if (_a >= 1) \ _i++; \ \ cnt = _i; \ } \ while (0) #else /* These are C++ inline functions that are equivalent to the above * macros. They are mainly intended as a debugging aid. */ static inline long& ALLOC(_ntl_gbigint p) { return (((long *) p)[0]); } static inline long& SIZE(_ntl_gbigint p) { return (((long *) p)[1]); } static inline mp_limb_t * DATA(_ntl_gbigint p) { return ((mp_limb_t *) (((long *) (p)) + 2)); } static inline long STORAGE(long len) { return ((long)(2*sizeof(long) + (len)*sizeof(mp_limb_t))); } static inline long MustAlloc(_ntl_gbigint c, long len) { return (!(c) || (ALLOC(c) >> 2) < (len)); } static inline void GET_SIZE_NEG(long& sz, long& neg, _ntl_gbigint p) { long s; s = SIZE(p); if (s < 0) { sz = -s; neg = 1; } else { sz = s; neg = 0; } } static inline void STRIP(long& sz, mp_limb_t *p) { long i; i = sz - 1; while (i >= 0 && p[i] == 0) i--; sz = i + 1; } static inline long ZEROP(_ntl_gbigint p) { return !p || !SIZE(p); } static inline long ONEP(_ntl_gbigint p) { return p && SIZE(p) == 1 && DATA(p)[0] == 1; } static inline void SWAP_BIGINT(_ntl_gbigint& a, _ntl_gbigint& b) { _ntl_gbigint t; t = a; a = b; b = t; } static inline void SWAP_LONG(long& a, long& b) { long t; t = a; a = b; b = t; } static inline void SWAP_LIMB_PTR(_ntl_limb_t_ptr& a, _ntl_limb_t_ptr& b) { _ntl_limb_t_ptr t; t = a; a = b; b = t; } static inline void COUNT_BITS(long& cnt, mp_limb_t a) { long i = 0; while (a>=256) i += 8, a >>= 8; if (a >=16) i += 4, a >>= 4; if (a >= 4) i += 2, a >>= 2; if (a >= 2) i += 2; else if (a >= 1) i++; cnt = i; } #endif #if 0 #define GRegister(x) static _ntl_gbigint x = 0 #else class _ntl_gbigint_watcher { public: _ntl_gbigint *watched; explicit _ntl_gbigint_watcher(_ntl_gbigint *_watched) : watched(_watched) {} ~_ntl_gbigint_watcher() { if (*watched && (ALLOC(*watched) >> 2) > NTL_RELEASE_THRESH) _ntl_gfree(watched); } }; #define GRegister(x) NTL_THREAD_LOCAL static _ntl_gbigint x = 0; _ntl_gbigint_watcher _WATCHER__ ## x(&x) // FIXME: when we implement thread safe code, we may want to define // this so that we also attach a thread-local watcher that unconditionally // releases memory when the thread terminates #endif #define STORAGE_OVF(len) NTL_OVERFLOW(len, sizeof(mp_limb_t), 2*sizeof(long)) /* ForceNormal ensures a normalized bigint */ static void ForceNormal(_ntl_gbigint x) { long sx, xneg; mp_limb_t *xdata; if (!x) return; GET_SIZE_NEG(sx, xneg, x); xdata = DATA(x); STRIP(sx, xdata); if (xneg) sx = -sx; SIZE(x) = sx; } static void ghalt(const char *c) { fprintf(stderr,"fatal error:\n %s\nexit...\n",c); fflush(stderr); _ntl_abort(); } #define MIN_SETL (4) /* _ntl_gsetlength allocates a multiple of MIN_SETL digits */ void _ntl_gsetlength(_ntl_gbigint *v, long len) { _ntl_gbigint x = *v; if (len < 0) ghalt("negative size allocation in _ntl_zgetlength"); if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0)) ghalt("size too big in _ntl_gsetlength"); #ifdef NTL_SMALL_MP_SIZE_T /* this makes sure that numbers don't get too big for GMP */ if (len >= (1L << (NTL_BITS_PER_INT-4))) ghalt("size too big for GMP"); #endif if (x) { long oldlen = ALLOC(x); long fixed = oldlen & 1; oldlen = oldlen >> 2; if (fixed) { if (len > oldlen) ghalt("internal error: can't grow this _ntl_gbigint"); else return; } if (len <= oldlen) return; len++; /* always allocate at least one more than requested */ oldlen = (long) (oldlen * 1.2); /* always increase by at least 20% */ if (len < oldlen) len = oldlen; /* round up to multiple of MIN_SETL */ len = ((len+(MIN_SETL-1))/MIN_SETL)*MIN_SETL; /* test len again */ if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0)) ghalt("size too big in _ntl_gsetlength"); if (STORAGE_OVF(len)) ghalt("reallocation failed in _ntl_gsetlength"); ALLOC(x) = len << 2; if (!(x = (_ntl_gbigint)NTL_REALLOC((void *) x, 1, STORAGE(len), 0))) { ghalt("reallocation failed in _ntl_gsetlength"); } } else { len++; /* as above, always allocate one more than explicitly reqested */ len = ((len+(MIN_SETL-1))/MIN_SETL)*MIN_SETL; /* test len again */ if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0)) ghalt("size too big in _ntl_gsetlength"); if (STORAGE_OVF(len)) ghalt("reallocation failed in _ntl_gsetlength"); if (!(x = (_ntl_gbigint)NTL_MALLOC(1, STORAGE(len), 0))) { ghalt("allocation failed in _ntl_gsetlength"); } ALLOC(x) = len << 2; SIZE(x) = 0; } *v = x; } void _ntl_gfree(_ntl_gbigint *xx) { _ntl_gbigint x = *xx; if (!x) return; if (ALLOC(x) & 1) ghalt("Internal error: can't free this _ntl_gbigint"); free((void*) x); *xx = 0; return; } void _ntl_gswap(_ntl_gbigint *a, _ntl_gbigint *b) { _ntl_gbigint c; if ((*a && (ALLOC(*a) & 1)) || (*b && (ALLOC(*b) & 1))) { GRegister(t); _ntl_gcopy(*a, &t); _ntl_gcopy(*b, a); _ntl_gcopy(t, b); return; } c = *a; *a = *b; *b = c; } void _ntl_gcopy(_ntl_gbigint a, _ntl_gbigint *bb) { _ntl_gbigint b; long sa, abs_sa, i; mp_limb_t *adata, *bdata; b = *bb; if (!a || (sa = SIZE(a)) == 0) { if (b) SIZE(b) = 0; } else { if (a != b) { if (sa >= 0) abs_sa = sa; else abs_sa = -sa; if (MustAlloc(b, abs_sa)) { _ntl_gsetlength(&b, abs_sa); *bb = b; } adata = DATA(a); bdata = DATA(b); for (i = 0; i < abs_sa; i++) bdata[i] = adata[i]; SIZE(b) = sa; } } } void _ntl_gzero(_ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (a) SIZE(a) = 0; } void _ntl_gone(_ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (!a) { _ntl_gsetlength(&a, 1); *aa = a; } SIZE(a) = 1; DATA(a)[0] = 1; } long _ntl_giszero(_ntl_gbigint a) { return ZEROP(a); } long _ntl_godd(_ntl_gbigint a) { if (ZEROP(a)) return 0; else return DATA(a)[0]&1; } long _ntl_gbit(_ntl_gbigint a, long p) { long bl; long sa; mp_limb_t wh; if (p < 0 || !a) return 0; bl = p/NTL_ZZ_NBITS; wh = ((mp_limb_t) 1) << (p - NTL_ZZ_NBITS*bl); sa = SIZE(a); if (sa < 0) sa = -sa; if (sa <= bl) return 0; if (DATA(a)[bl] & wh) return 1; return 0; } void _ntl_glowbits(_ntl_gbigint a, long b, _ntl_gbigint *cc) { _ntl_gbigint c; long bl; long wh; long sa; long i; mp_limb_t *adata, *cdata; if (ZEROP(a) || (b<=0)) { _ntl_gzero(cc); return; } bl = b/NTL_ZZ_NBITS; wh = b - NTL_ZZ_NBITS*bl; if (wh != 0) bl++; else wh = NTL_ZZ_NBITS; sa = SIZE(a); if (sa < 0) sa = -sa; if (sa < bl) { _ntl_gcopy(a,cc); _ntl_gabs(cc); return; } c = *cc; /* a won't move if c aliases a */ _ntl_gsetlength(&c, bl); *cc = c; adata = DATA(a); cdata = DATA(c); for (i = 0; i < bl-1; i++) cdata[i] = adata[i]; if (wh == NTL_ZZ_NBITS) cdata[bl-1] = adata[bl-1]; else cdata[bl-1] = adata[bl-1] & ((((mp_limb_t) 1) << wh) - ((mp_limb_t) 1)); STRIP(bl, cdata); SIZE(c) = bl; } long _ntl_gslowbits(_ntl_gbigint a, long p) { GRegister(x); if (p > NTL_BITS_PER_LONG) p = NTL_BITS_PER_LONG; _ntl_glowbits(a, p, &x); return _ntl_gtoint(x); } long _ntl_gsetbit(_ntl_gbigint *a, long b) { long bl; long sa, aneg; long i; mp_limb_t wh, *adata, tmp; if (b<0) ghalt("_ntl_gsetbit: negative index"); if (ZEROP(*a)) { _ntl_gintoz(1, a); _ntl_glshift(*a, b, a); return 0; } bl = (b/NTL_ZZ_NBITS); wh = ((mp_limb_t) 1) << (b - NTL_ZZ_NBITS*bl); GET_SIZE_NEG(sa, aneg, *a); if (sa > bl) { adata = DATA(*a); tmp = adata[bl] & wh; adata[bl] |= wh; if (tmp) return 1; return 0; } else { _ntl_gsetlength(a, bl+1); adata = DATA(*a); for (i = sa; i < bl; i++) adata[i] = 0; adata[bl] = wh; sa = bl+1; if (aneg) sa = -sa; SIZE(*a) = sa; return 0; } } long _ntl_gswitchbit(_ntl_gbigint *a, long b) { long bl; long sa, aneg; long i; mp_limb_t wh, *adata, tmp; if (b<0) ghalt("_ntl_gswitchbit: negative index"); if (ZEROP(*a)) { _ntl_gintoz(1, a); _ntl_glshift(*a, b, a); return 0; } bl = (b/NTL_ZZ_NBITS); wh = ((mp_limb_t) 1) << (b - NTL_ZZ_NBITS*bl); GET_SIZE_NEG(sa, aneg, *a); if (sa > bl) { adata = DATA(*a); tmp = adata[bl] & wh; adata[bl] ^= wh; if (bl == sa-1) { STRIP(sa, adata); if (aneg) sa = -sa; SIZE(*a) = sa; } if (tmp) return 1; return 0; } else { _ntl_gsetlength(a, bl+1); adata = DATA(*a); for (i = sa; i < bl; i++) adata[i] = 0; adata[bl] = wh; sa = bl+1; if (aneg) sa = -sa; SIZE(*a) = sa; return 0; } } long _ntl_gweights( long aa ) { unsigned long a; long res = 0; if (aa < 0) a = -((unsigned long) aa); else a = aa; while (a) { if (a & 1) res ++; a >>= 1; } return (res); } static long gweights_mp_limb( mp_limb_t a ) { long res = 0; while (a) { if (a & 1) res ++; a >>= 1; } return (res); } long _ntl_gweight( _ntl_gbigint a ) { long i; long sa; mp_limb_t *adata; long res; if (!a) return (0); sa = SIZE(a); if (sa < 0) sa = -sa; adata = DATA(a); res = 0; for (i = 0; i < sa; i++) res += gweights_mp_limb(adata[i]); return (res); } long _ntl_g2logs( long aa ) { long i = 0; unsigned long a; if (aa < 0) a = - ((unsigned long) aa); else a = aa; while (a>=256) i += 8, a >>= 8; if (a >=16) i += 4, a >>= 4; if (a >= 4) i += 2, a >>= 2; if (a >= 2) i += 2; else if (a >= 1) i++; return (i); } long _ntl_g2log(_ntl_gbigint a) { long la; long t; if (!a) return 0; la = SIZE(a); if (la == 0) return 0; if (la < 0) la = -la; COUNT_BITS(t, DATA(a)[la-1]); return NTL_ZZ_NBITS*(la - 1) + t; } long _ntl_gmakeodd(_ntl_gbigint *nn) { _ntl_gbigint n = *nn; long shift; mp_limb_t *ndata; mp_limb_t i; if (ZEROP(n)) return (0); shift = 0; ndata = DATA(n); while (ndata[shift] == 0) shift++; i = ndata[shift]; shift = NTL_ZZ_NBITS * shift; while ((i & 1) == 0) { shift++; i >>= 1; } _ntl_grshift(n, shift, &n); return shift; } long _ntl_gnumtwos(_ntl_gbigint n) { long shift; mp_limb_t *ndata; mp_limb_t i; if (ZEROP(n)) return (0); shift = 0; ndata = DATA(n); while (ndata[shift] == 0) shift++; i = ndata[shift]; shift = NTL_ZZ_NBITS * shift; while ((i & 1) == 0) { shift++; i >>= 1; } return shift; } void _ntl_gand(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { _ntl_gbigint c; long sa; long sb; long sm; long i; long a_alias, b_alias; mp_limb_t *adata, *bdata, *cdata; if (ZEROP(a) || ZEROP(b)) { _ntl_gzero(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = SIZE(a); if (sa < 0) sa = -sa; sb = SIZE(b); if (sb < 0) sb = -sb; sm = (sa > sb ? sb : sa); _ntl_gsetlength(&c, sm); if (a_alias) a = c; if (b_alias) b = c; *cc = c; adata = DATA(a); bdata = DATA(b); cdata = DATA(c); for (i = 0; i < sm; i++) cdata[i] = adata[i] & bdata[i]; STRIP(sm, cdata); SIZE(c) = sm; } void _ntl_gxor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { _ntl_gbigint c; long sa; long sb; long sm; long la; long i; long a_alias, b_alias; mp_limb_t *adata, *bdata, *cdata; if (ZEROP(a)) { _ntl_gcopy(b,cc); _ntl_gabs(cc); return; } if (ZEROP(b)) { _ntl_gcopy(a,cc); _ntl_gabs(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = SIZE(a); if (sa < 0) sa = -sa; sb = SIZE(b); if (sb < 0) sb = -sb; if (sa > sb) { la = sa; sm = sb; } else { la = sb; sm = sa; } _ntl_gsetlength(&c, la); if (a_alias) a = c; if (b_alias) b = c; *cc = c; adata = DATA(a); bdata = DATA(b); cdata = DATA(c); for (i = 0; i < sm; i ++) cdata[i] = adata[i] ^ bdata[i]; if (sa > sb) for (;i < la; i++) cdata[i] = adata[i]; else for (;i < la; i++) cdata[i] = bdata[i]; STRIP(la, cdata); SIZE(c) = la; } void _ntl_gor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { _ntl_gbigint c; long sa; long sb; long sm; long la; long i; long a_alias, b_alias; mp_limb_t *adata, *bdata, *cdata; if (ZEROP(a)) { _ntl_gcopy(b,cc); _ntl_gabs(cc); return; } if (ZEROP(b)) { _ntl_gcopy(a,cc); _ntl_gabs(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = SIZE(a); if (sa < 0) sa = -sa; sb = SIZE(b); if (sb < 0) sb = -sb; if (sa > sb) { la = sa; sm = sb; } else { la = sb; sm = sa; } _ntl_gsetlength(&c, la); if (a_alias) a = c; if (b_alias) b = c; *cc = c; adata = DATA(a); bdata = DATA(b); cdata = DATA(c); for (i = 0; i < sm; i ++) cdata[i] = adata[i] | bdata[i]; if (sa > sb) for (;i < la; i++) cdata[i] = adata[i]; else for (;i < la; i++) cdata[i] = bdata[i]; STRIP(la, cdata); SIZE(c) = la; } void _ntl_gnegate(_ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (a) SIZE(a) = -SIZE(a); } /* * DIRT: this implementation of _ntl_gintoz relies crucially * on the assumption that the number of bits per limb_t is at least * equal to the number of bits per long. */ void _ntl_gintoz(long d, _ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (d == 0) { if (a) SIZE(a) = 0; } else if (d > 0) { if (!a) { _ntl_gsetlength(&a, 1); *aa = a; } SIZE(a) = 1; DATA(a)[0] = d; } else { if (!a) { _ntl_gsetlength(&a, 1); *aa = a; } SIZE(a) = -1; DATA(a)[0] = -((mp_limb_t) d); /* careful! */ } } /* * DIRT: this implementation of _ntl_guintoz relies crucially * on the assumption that the number of bits per limb_t is at least * equal to the number of bits per long. */ void _ntl_guintoz(unsigned long d, _ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (d == 0) { if (a) SIZE(a) = 0; } else { if (!a) { _ntl_gsetlength(&a, 1); *aa = a; } SIZE(a) = 1; DATA(a)[0] = d; } } long _ntl_gtoint(_ntl_gbigint a) { unsigned long res = _ntl_gtouint(a); return NTL_ULONG_TO_LONG(res); } /* * DIRT: this implementation of _ntl_gtouint relies crucially * on the assumption that the number of bits per limb_t is at least * equal to the number of bits per long. */ unsigned long _ntl_gtouint(_ntl_gbigint a) { if (ZEROP(a)) return 0; if (SIZE(a) > 0) return DATA(a)[0]; return -DATA(a)[0]; } long _ntl_gcompare(_ntl_gbigint a, _ntl_gbigint b) { long sa, sb, cmp; mp_limb_t *adata, *bdata; if (!a) sa = 0; else sa = SIZE(a); if (!b) sb = 0; else sb = SIZE(b); if (sa != sb) { if (sa > sb) return 1; else return -1; } if (sa == 0) return 0; adata = DATA(a); bdata = DATA(b); if (sa > 0) { cmp = mpn_cmp(adata, bdata, sa); if (cmp > 0) return 1; else if (cmp < 0) return -1; else return 0; } else { cmp = mpn_cmp(adata, bdata, -sa); if (cmp > 0) return -1; else if (cmp < 0) return 1; else return 0; } } long _ntl_gsign(_ntl_gbigint a) { long sa; if (!a) return 0; sa = SIZE(a); if (sa > 0) return 1; if (sa == 0) return 0; return -1; } void _ntl_gabs(_ntl_gbigint *pa) { _ntl_gbigint a = *pa; if (!a) return; if (SIZE(a) < 0) SIZE(a) = -SIZE(a); } long _ntl_gscompare(_ntl_gbigint a, long b) { if (b == 0) { long sa; if (!a) return 0; sa = SIZE(a); if (sa > 0) return 1; if (sa == 0) return 0; return -1; } else { GRegister(B); _ntl_gintoz(b, &B); return _ntl_gcompare(a, B); } } void _ntl_glshift(_ntl_gbigint n, long k, _ntl_gbigint *rres) { _ntl_gbigint res; mp_limb_t *ndata, *resdata, *resdata1; long limb_cnt, i, sn, nneg, sres; long n_alias; if (ZEROP(n)) { _ntl_gzero(rres); return; } res = *rres; n_alias = (n == res); if (!k) { if (!n_alias) _ntl_gcopy(n, rres); return; } if (k < 0) { if (k < -NTL_MAX_LONG) _ntl_gzero(rres); else _ntl_grshift(n, -k, rres); return; } GET_SIZE_NEG(sn, nneg, n); limb_cnt = k/NTL_ZZ_NBITS; sres = sn + limb_cnt + 1; if (MustAlloc(res, sres)) { _ntl_gsetlength(&res, sres); if (n_alias) n = res; *rres = res; } ndata = DATA(n); resdata = DATA(res); resdata1 = resdata + limb_cnt; k %= NTL_ZZ_NBITS; sres--; if (k != 0) { mp_limb_t t = mpn_lshift(resdata1, ndata, sn, k); if (t != 0) { resdata[sres] = t; sres++; } } else { for (i = sn-1; i >= 0; i--) resdata1[i] = ndata[i]; } for (i = 0; i < limb_cnt; i++) resdata[i] = 0; if (nneg) sres = -sres; SIZE(res) = sres; } void _ntl_grshift(_ntl_gbigint n, long k, _ntl_gbigint *rres) { _ntl_gbigint res; mp_limb_t *ndata, *resdata, *ndata1; long limb_cnt, i, sn, nneg, sres; if (ZEROP(n)) { _ntl_gzero(rres); return; } if (!k) { if (n != *rres) _ntl_gcopy(n, rres); return; } if (k < 0) { if (k < -NTL_MAX_LONG) ghalt("overflow in _ntl_glshift"); _ntl_glshift(n, -k, rres); return; } GET_SIZE_NEG(sn, nneg, n); limb_cnt = k/NTL_ZZ_NBITS; sres = sn - limb_cnt; if (sres <= 0) { _ntl_gzero(rres); return; } res = *rres; if (MustAlloc(res, sres)) { /* n won't move if res aliases n */ _ntl_gsetlength(&res, sres); *rres = res; } ndata = DATA(n); resdata = DATA(res); ndata1 = ndata + limb_cnt; k %= NTL_ZZ_NBITS; if (k != 0) { mpn_rshift(resdata, ndata1, sres, k); if (resdata[sres-1] == 0) sres--; } else { for (i = 0; i < sres; i++) resdata[i] = ndata1[i]; } if (nneg) sres = -sres; SIZE(res) = sres; } void _ntl_gadd(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { long sa, aneg, sb, bneg, sc, cmp; mp_limb_t *adata, *bdata, *cdata, carry; _ntl_gbigint c; long a_alias, b_alias; if (ZEROP(a)) { _ntl_gcopy(b, cc); return; } if (ZEROP(b)) { _ntl_gcopy(a, cc); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sb, bneg, b); if (sa < sb) { SWAP_BIGINT(a, b); SWAP_LONG(sa, sb); SWAP_LONG(aneg, bneg); } /* sa >= sb */ c = *cc; a_alias = (a == c); b_alias = (b == c); if (aneg == bneg) { /* same sign => addition */ sc = sa + 1; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); carry = mpn_add(cdata, adata, sa, bdata, sb); if (carry) cdata[sc-1] = carry; else sc--; if (aneg) sc = -sc; SIZE(c) = sc; } else { /* opposite sign => subtraction */ sc = sa; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); if (sa > sb) cmp = 1; else cmp = mpn_cmp(adata, bdata, sa); if (cmp == 0) { SIZE(c) = 0; } else { if (cmp < 0) cmp = 0; if (cmp > 0) cmp = 1; /* abs(a) != abs(b) && (abs(a) > abs(b) <=> cmp) */ if (cmp) mpn_sub(cdata, adata, sa, bdata, sb); else mpn_sub(cdata, bdata, sb, adata, sa); /* sa == sb */ STRIP(sc, cdata); if (aneg == cmp) sc = -sc; SIZE(c) = sc; } } } void _ntl_gsadd(_ntl_gbigint a, long b, _ntl_gbigint *cc) { GRegister(B); _ntl_gintoz(b, &B); _ntl_gadd(a, B, cc); } void _ntl_gsub(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { long sa, aneg, sb, bneg, sc, cmp, rev; mp_limb_t *adata, *bdata, *cdata, carry; _ntl_gbigint c; long a_alias, b_alias; if (ZEROP(a)) { _ntl_gcopy(b, cc); c = *cc; if (c) SIZE(c) = -SIZE(c); return; } if (ZEROP(b)) { _ntl_gcopy(a, cc); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sb, bneg, b); if (sa < sb) { SWAP_BIGINT(a, b); SWAP_LONG(sa, sb); SWAP_LONG(aneg, bneg); rev = 1; } else rev = 0; /* sa >= sb */ c = *cc; a_alias = (a == c); b_alias = (b == c); if (aneg != bneg) { /* opposite sign => addition */ sc = sa + 1; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); carry = mpn_add(cdata, adata, sa, bdata, sb); if (carry) cdata[sc-1] = carry; else sc--; if (aneg ^ rev) sc = -sc; SIZE(c) = sc; } else { /* same sign => subtraction */ sc = sa; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); if (sa > sb) cmp = 1; else cmp = mpn_cmp(adata, bdata, sa); if (cmp == 0) { SIZE(c) = 0; } else { if (cmp < 0) cmp = 0; if (cmp > 0) cmp = 1; /* abs(a) != abs(b) && (abs(a) > abs(b) <=> cmp) */ if (cmp) mpn_sub(cdata, adata, sa, bdata, sb); else mpn_sub(cdata, bdata, sb, adata, sa); /* sa == sb */ STRIP(sc, cdata); if ((aneg == cmp) ^ rev) sc = -sc; SIZE(c) = sc; } } } void _ntl_gsubpos(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { long sa, sb, sc; mp_limb_t *adata, *bdata, *cdata; _ntl_gbigint c; long a_alias, b_alias; if (ZEROP(a)) { _ntl_gzero(cc); return; } if (ZEROP(b)) { _ntl_gcopy(a, cc); return; } sa = SIZE(a); sb = SIZE(b); c = *cc; a_alias = (a == c); b_alias = (b == c); sc = sa; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); mpn_sub(cdata, adata, sa, bdata, sb); STRIP(sc, cdata); SIZE(c) = sc; } void _ntl_gmul(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { GRegister(mem); long sa, aneg, sb, bneg, alias, sc; mp_limb_t *adata, *bdata, *cdata, msl; _ntl_gbigint c; if (ZEROP(a) || ZEROP(b)) { _ntl_gzero(cc); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sb, bneg, b); if (a == *cc || b == *cc) { c = mem; alias = 1; } else { c = *cc; alias = 0; } sc = sa + sb; if (MustAlloc(c, sc)) _ntl_gsetlength(&c, sc); if (alias) mem = c; else *cc = c; adata = DATA(a); bdata = DATA(b); cdata = DATA(c); if (sa >= sb) msl = mpn_mul(cdata, adata, sa, bdata, sb); else msl = mpn_mul(cdata, bdata, sb, adata, sa); if (!msl) sc--; if (aneg != bneg) sc = -sc; SIZE(c) = sc; if (alias) _ntl_gcopy(mem, cc); } void _ntl_gsq(_ntl_gbigint a, _ntl_gbigint *cc) { _ntl_gmul(a, a, cc); /* this is good enough...eventually, mpn_sqr_n will be called */ } /* * DIRT: this implementation of _ntl_gsmul relies crucially * on the assumption that the number of bits per limb_t is at least * equal to the number of bits per long. */ void _ntl_gsmul(_ntl_gbigint a, long d, _ntl_gbigint *bb) { long sa, sb; long anegative, bnegative; _ntl_gbigint b; mp_limb_t *adata, *bdata; mp_limb_t dd, carry; long a_alias; if (ZEROP(a) || !d) { _ntl_gzero(bb); return; } GET_SIZE_NEG(sa, anegative, a); if (d < 0) { dd = - ((mp_limb_t) d); /* careful ! */ bnegative = 1-anegative; } else { dd = (mp_limb_t) d; bnegative = anegative; } sb = sa + 1; b = *bb; a_alias = (a == b); if (MustAlloc(b, sb)) { _ntl_gsetlength(&b, sb); if (a_alias) a = b; *bb = b; } adata = DATA(a); bdata = DATA(b); if (dd == 2) carry = mpn_lshift(bdata, adata, sa, 1); else carry = mpn_mul_1(bdata, adata, sa, dd); if (carry) bdata[sa] = carry; else sb--; if (bnegative) sb = -sb; SIZE(b) = sb; } /* * DIRT: this implementation of _ntl_gsdiv relies crucially * on the assumption that the number of bits per limb_t is at least * equal to the number of bits per long. */ long _ntl_gsdiv(_ntl_gbigint a, long d, _ntl_gbigint *bb) { long sa, aneg, sb, dneg; _ntl_gbigint b; mp_limb_t dd, *adata, *bdata; long r; if (!d) { ghalt("division by zero in _ntl_gsdiv"); } if (ZEROP(a)) { _ntl_gzero(bb); return (0); } GET_SIZE_NEG(sa, aneg, a); if (d < 0) { dd = - ((mp_limb_t) d); /* careful ! */ dneg = 1; } else { dd = (mp_limb_t) d; dneg = 0; } sb = sa; b = *bb; if (MustAlloc(b, sb)) { /* if b aliases a, then b won't move */ _ntl_gsetlength(&b, sb); *bb = b; } adata = DATA(a); bdata = DATA(b); if (dd == 2) r = mpn_rshift(bdata, adata, sa, 1) >> (NTL_ZZ_NBITS - 1); else r = mpn_divmod_1(bdata, adata, sa, dd); if (bdata[sb-1] == 0) sb--; SIZE(b) = sb; if (aneg || dneg) { if (aneg != dneg) { if (!r) { SIZE(b) = -SIZE(b); } else { _ntl_gsadd(b, 1, &b); SIZE(b) = -SIZE(b); if (dneg) r = r + d; else r = d - r; *bb = b; } } else r = -r; } return r; } /* * DIRT: this implementation of _ntl_gsmod relies crucially * on the assumption that the number of bits per limb_t is at least * equal to the number of bits per long. */ long _ntl_gsmod(_ntl_gbigint a, long d) { long sa, aneg, dneg; mp_limb_t dd, *adata; long r; if (!d) { ghalt("division by zero in _ntl_gsmod"); } if (ZEROP(a)) { return (0); } GET_SIZE_NEG(sa, aneg, a); if (d < 0) { dd = - ((mp_limb_t) d); /* careful ! */ dneg = 1; } else { dd = (mp_limb_t) d; dneg = 0; } adata = DATA(a); if (dd == 2) r = adata[0] & 1; else r = mpn_mod_1(adata, sa, dd); if (aneg || dneg) { if (aneg != dneg) { if (r) { if (dneg) r = r + d; else r = d - r; } } else r = -r; } return r; } void _ntl_gdiv(_ntl_gbigint a, _ntl_gbigint d, _ntl_gbigint *bb, _ntl_gbigint *rr) { GRegister(b); GRegister(rmem); _ntl_gbigint r; long sa, aneg, sb, sd, dneg, sr, in_place; mp_limb_t *adata, *ddata, *bdata, *rdata; if (ZEROP(d)) { ghalt("division by zero in _ntl_gdiv"); } if (ZEROP(a)) { if (bb) _ntl_gzero(bb); if (rr) _ntl_gzero(rr); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sd, dneg, d); if (!aneg && !dneg && rr && *rr != a && *rr != d) { in_place = 1; r = *rr; } else { in_place = 0; r = rmem; } if (sa < sd) { _ntl_gzero(&b); _ntl_gcopy(a, &r); if (aneg) SIZE(r) = -SIZE(r); goto done; } sb = sa-sd+1; if (MustAlloc(b, sb)) _ntl_gsetlength(&b, sb); sr = sd; if (MustAlloc(r, sr)) _ntl_gsetlength(&r, sr); adata = DATA(a); ddata = DATA(d); bdata = DATA(b); rdata = DATA(r); mpn_tdiv_qr(bdata, rdata, 0, adata, sa, ddata, sd); if (bdata[sb-1] == 0) sb--; SIZE(b) = sb; STRIP(sr, rdata); SIZE(r) = sr; done: if (aneg || dneg) { if (aneg != dneg) { if (ZEROP(r)) { SIZE(b) = -SIZE(b); } else { if (bb) { _ntl_gsadd(b, 1, &b); SIZE(b) = -SIZE(b); } if (rr) { if (dneg) _ntl_gadd(r, d, &r); else _ntl_gsub(d, r, &r); } } } else SIZE(r) = -SIZE(r); } if (bb) _ntl_gcopy(b, bb); if (in_place) *rr = r; else { if (rr) _ntl_gcopy(r, rr); rmem = r; } } /* a simplified mod operation: assumes a >= 0, d > 0 are non-negative, * that space for the result has already been allocated, * and that inputs do not alias output. */ static void gmod_simple(_ntl_gbigint a, _ntl_gbigint d, _ntl_gbigint *rr) { GRegister(b); long sa, sb, sd, sr; mp_limb_t *adata, *ddata, *bdata, *rdata; _ntl_gbigint r; if (ZEROP(a)) { _ntl_gzero(rr); return; } sa = SIZE(a); sd = SIZE(d); if (sa < sd) { _ntl_gcopy(a, rr); return; } sb = sa-sd+1; if (MustAlloc(b, sb)) _ntl_gsetlength(&b, sb); sr = sd; r = *rr; adata = DATA(a); ddata = DATA(d); bdata = DATA(b); rdata = DATA(r); mpn_tdiv_qr(bdata, rdata, 0, adata, sa, ddata, sd); STRIP(sr, rdata); SIZE(r) = sr; } void _ntl_gmod(_ntl_gbigint a, _ntl_gbigint d, _ntl_gbigint *rr) { _ntl_gdiv(a, d, 0, rr); } void _ntl_gquickmod(_ntl_gbigint *rr, _ntl_gbigint d) { _ntl_gdiv(*rr, d, 0, rr); } void _ntl_gsqrt(_ntl_gbigint n, _ntl_gbigint *rr) { GRegister(r); long sn, sr; mp_limb_t *ndata, *rdata; if (ZEROP(n)) { _ntl_gzero(rr); return; } sn = SIZE(n); if (sn < 0) ghalt("negative argument to _ntl_sqrt"); sr = (sn+1)/2; _ntl_gsetlength(&r, sr); ndata = DATA(n); rdata = DATA(r); mpn_sqrtrem(rdata, 0, ndata, sn); STRIP(sr, rdata); SIZE(r) = sr; _ntl_gcopy(r, rr); } /* * DIRT: this implementation of _ntl_gsqrts relies crucially * on the assumption that the number of bits per limb_t is at least * equal to the number of bits per long. */ long _ntl_gsqrts(long n) { mp_limb_t ndata, rdata; if (n == 0) { return 0; } if (n < 0) ghalt("negative argument to _ntl_sqrts"); ndata = n; mpn_sqrtrem(&rdata, 0, &ndata, 1); return rdata; } void _ntl_ggcd(_ntl_gbigint m1, _ntl_gbigint m2, _ntl_gbigint *r) { GRegister(s1); GRegister(s2); GRegister(res); long k1, k2, k_min, l1, l2, ss1, ss2, sres; _ntl_gcopy(m1, &s1); _ntl_gabs(&s1); _ntl_gcopy(m2, &s2); _ntl_gabs(&s2); if (ZEROP(s1)) { _ntl_gcopy(s2, r); return; } if (ZEROP(s2)) { _ntl_gcopy(s1, r); return; } k1 = _ntl_gmakeodd(&s1); k2 = _ntl_gmakeodd(&s2); if (k1 <= k2) k_min = k1; else k_min = k2; l1 = _ntl_g2log(s1); l2 = _ntl_g2log(s2); ss1 = SIZE(s1); ss2 = SIZE(s2); if (ss1 >= ss2) sres = ss1; else sres = ss2; /* set to max: gmp documentation is unclear on this point */ _ntl_gsetlength(&res, sres); if (l1 >= l2) SIZE(res) = mpn_gcd(DATA(res), DATA(s1), ss1, DATA(s2), ss2); else SIZE(res) = mpn_gcd(DATA(res), DATA(s2), ss2, DATA(s1), ss1); _ntl_glshift(res, k_min, &res); _ntl_gcopy(res, r); } static long gxxeucl( _ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint *invv, _ntl_gbigint *uu ) { GRegister(a); GRegister(n); GRegister(q); GRegister(w); GRegister(x); GRegister(y); GRegister(z); _ntl_gbigint inv = *invv; _ntl_gbigint u = *uu; long diff; long ilo; long sa; long sn; long temp; long e; long fast; long parity; long gotthem; mp_limb_t *p; long try11; long try12; long try21; long try22; long got11; long got12; long got21; long got22; double hi; double lo; double dt; double fhi, fhi1; double flo, flo1; double num; double den; double dirt; _ntl_gsetlength(&a, (e = (SIZE(ain) > SIZE(nin) ? SIZE(ain) : SIZE(nin)))); _ntl_gsetlength(&n, e); _ntl_gsetlength(&q, e); _ntl_gsetlength(&w, e); _ntl_gsetlength(&x, e); _ntl_gsetlength(&y, e); _ntl_gsetlength(&z, e); _ntl_gsetlength(&inv, e); *invv = inv; _ntl_gsetlength(&u, e); *uu = u; fhi1 = 1.0 + ((double) 32.0)/NTL_FDOUBLE_PRECISION; flo1 = 1.0 - ((double) 32.0)/NTL_FDOUBLE_PRECISION; fhi = 1.0 + ((double) 8.0)/NTL_FDOUBLE_PRECISION; flo = 1.0 - ((double) 8.0)/NTL_FDOUBLE_PRECISION; _ntl_gcopy(ain, &a); _ntl_gcopy(nin, &n); _ntl_gone(&inv); _ntl_gzero(&w); while (SIZE(n) > 0) { gotthem = 0; sa = SIZE(a); sn = SIZE(n); diff = sa - sn; if (!diff || diff == 1) { sa = SIZE(a); p = DATA(a) + (sa-1); num = (double) (*p) * NTL_ZZ_FRADIX; if (sa > 1) num += (*(--p)); num *= NTL_ZZ_FRADIX; if (sa > 2) num += (*(p - 1)); sn = SIZE(n); p = DATA(n) + (sn-1); den = (double) (*p) * NTL_ZZ_FRADIX; if (sn > 1) den += (*(--p)); den *= NTL_ZZ_FRADIX; if (sn > 2) den += (*(p - 1)); hi = fhi1 * (num + 1.0) / den; lo = flo1 * num / (den + 1.0); if (diff > 0) { hi *= NTL_ZZ_FRADIX; lo *= NTL_ZZ_FRADIX; } try11 = 1; try12 = 0; try21 = 0; try22 = 1; parity = 1; fast = 1; while (fast > 0) { parity = 1 - parity; if (hi >= NTL_SP_BOUND) fast = 0; else { ilo = (long)lo; dirt = hi - ilo; if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi) fast = 0; else { dt = lo-ilo; lo = flo / dirt; if (dt > 1.0/NTL_FDOUBLE_PRECISION) hi = fhi / dt; else hi = NTL_SP_BOUND; temp = try11; try11 = try21; if ((NTL_WSP_BOUND - temp) / ilo < try21) fast = 0; else try21 = temp + ilo * try21; temp = try12; try12 = try22; if ((NTL_WSP_BOUND - temp) / ilo < try22) fast = 0; else try22 = temp + ilo * try22; if ((fast > 0) && (parity > 0)) { gotthem = 1; got11 = try11; got12 = try12; got21 = try21; got22 = try22; } } } } } if (gotthem) { _ntl_gsmul(inv, got11, &x); _ntl_gsmul(w, got12, &y); _ntl_gsmul(inv, got21, &z); _ntl_gsmul(w, got22, &w); _ntl_gadd(x, y, &inv); _ntl_gadd(z, w, &w); _ntl_gsmul(a, got11, &x); _ntl_gsmul(n, got12, &y); _ntl_gsmul(a, got21, &z); _ntl_gsmul(n, got22, &n); _ntl_gsub(x, y, &a); _ntl_gsub(n, z, &n); } else { _ntl_gdiv(a, n, &q, &a); _ntl_gmul(q, w, &x); _ntl_gadd(inv, x, &inv); if (!ZEROP(a)) { _ntl_gdiv(n, a, &q, &n); _ntl_gmul(q, inv, &x); _ntl_gadd(w, x, &w); } else { _ntl_gcopy(n, &a); _ntl_gzero(&n); _ntl_gcopy(w, &inv); _ntl_gnegate(&inv); } } } if (_ntl_gscompare(a, 1) == 0) e = 0; else e = 1; _ntl_gcopy(a, &u); *invv = inv; *uu = u; return (e); } #if 0 void _ntl_gexteucl( _ntl_gbigint aa, _ntl_gbigint *xa, _ntl_gbigint bb, _ntl_gbigint *xb, _ntl_gbigint *d ) { GRegister(modcon); GRegister(a); GRegister(b); long anegative = 0; long bnegative = 0; _ntl_gcopy(aa, &a); _ntl_gcopy(bb, &b); if (a && SIZE(a) < 0) { anegative = 1; SIZE(a) = -SIZE(a); } else anegative = 0; if (b && SIZE(b) < 0) { bnegative = 1; SIZE(b) = -SIZE(b); } else bnegative = 0; if (ZEROP(b)) { _ntl_gone(xa); _ntl_gzero(xb); _ntl_gcopy(a, d); goto done; } if (ZEROP(a)) { _ntl_gzero(xa); _ntl_gone(xb); _ntl_gcopy(b, d); goto done; } gxxeucl(a, b, xa, d); _ntl_gmul(a, *xa, xb); _ntl_gsub(*d, *xb, xb); _ntl_gdiv(*xb, b, xb, &modcon); if (!ZEROP(modcon)) { ghalt("non-zero remainder in _ntl_gexteucl BUG"); } done: if (anegative) { _ntl_gnegate(xa); } if (bnegative) { _ntl_gnegate(xb); } } #endif void _ntl_gexteucl( _ntl_gbigint ain, _ntl_gbigint *xap, _ntl_gbigint bin, _ntl_gbigint *xbp, _ntl_gbigint *dp ) { if (ZEROP(bin)) { long asign = _ntl_gsign(ain); _ntl_gcopy(ain, dp); _ntl_gabs(dp); _ntl_gintoz( (asign >= 0 ? 1 : -1), xap); _ntl_gzero(xbp); } else if (ZEROP(ain)) { long bsign = _ntl_gsign(bin); _ntl_gcopy(bin, dp); _ntl_gabs(dp); _ntl_gzero(xap); _ntl_gintoz(bsign, xbp); } else { GRegister(a); GRegister(b); GRegister(xa); GRegister(xb); GRegister(d); GRegister(tmp); long sa, aneg, sb, bneg, rev; mp_limb_t *adata, *bdata, *ddata, *xadata; mp_size_t sxa, sd; GET_SIZE_NEG(sa, aneg, ain); GET_SIZE_NEG(sb, bneg, bin); _ntl_gsetlength(&a, sa+1); /* +1 because mpn_gcdext may need it */ _ntl_gcopy(ain, &a); _ntl_gsetlength(&b, sb+1); /* +1 because mpn_gcdext may need it */ _ntl_gcopy(bin, &b); adata = DATA(a); bdata = DATA(b); if (sa < sb || (sa == sb && mpn_cmp(adata, bdata, sa) < 0)) { SWAP_BIGINT(ain, bin); SWAP_LONG(sa, sb); SWAP_LONG(aneg, bneg); SWAP_LIMB_PTR(adata, bdata); rev = 1; } else rev = 0; _ntl_gsetlength(&d, sa+1); /* +1 because mpn_gcdext may need it... documentation is unclear, but this is what is done in mpz_gcdext */ _ntl_gsetlength(&xa, sa+1); /* ditto */ ddata = DATA(d); xadata = DATA(xa); sd = mpn_gcdext(ddata, xadata, &sxa, adata, sa, bdata, sb); SIZE(d) = sd; SIZE(xa) = sxa; /* Thes two ForceNormal's are work-arounds for GMP bugs in GMP 4.3.0 */ ForceNormal(d); ForceNormal(xa); /* now we normalize xa, so that so that xa in ( -b/2d, b/2d ], which makes the output agree with Euclid's algorithm, regardless of what mpn_gcdext does */ if (!ZEROP(xa)) { _ntl_gcopy(bin, &b); SIZE(b) = sb; if (!ONEP(d)) { _ntl_gdiv(b, d, &b, &tmp); if (!ZEROP(tmp)) ghalt("internal bug in _ntl_gexteucl"); } if (SIZE(xa) > 0) { /* xa positive */ if (_ntl_gcompare(xa, b) > 0) { _ntl_gmod(xa, b, &xa); } _ntl_glshift(xa, 1, &tmp); if (_ntl_gcompare(tmp, b) > 0) { _ntl_gsub(xa, b, &xa); } } else { /* xa negative */ SIZE(xa) = -SIZE(xa); if (_ntl_gcompare(xa, b) > 0) { SIZE(xa) = -SIZE(xa); _ntl_gmod(xa, b, &xa); _ntl_gsub(xa, b, &xa); } else { SIZE(xa) = -SIZE(xa); } _ntl_glshift(xa, 1, &tmp); SIZE(tmp) = -SIZE(tmp); if (_ntl_gcompare(tmp, b) >= 0) { _ntl_gadd(xa, b, &xa); } } } /* end normalize */ if (aneg) _ntl_gnegate(&xa); _ntl_gmul(ain, xa, &tmp); _ntl_gsub(d, tmp, &tmp); _ntl_gdiv(tmp, bin, &xb, &tmp); if (!ZEROP(tmp)) ghalt("internal bug in _ntl_gexteucl"); if (rev) SWAP_BIGINT(xa, xb); _ntl_gcopy(xa, xap); _ntl_gcopy(xb, xbp); _ntl_gcopy(d, dp); } } long _ntl_ginv(_ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint *invv) { GRegister(u); GRegister(d); GRegister(a); GRegister(n); long sz; long sd; mp_size_t su; if (_ntl_gscompare(nin, 1) <= 0) { ghalt("InvMod: second input <= 1"); } if (_ntl_gsign(ain) < 0) { ghalt("InvMod: first input negative"); } if (_ntl_gcompare(ain, nin) >= 0) { ghalt("InvMod: first input too big"); } sz = SIZE(nin) + 2; if (MustAlloc(a, sz)) _ntl_gsetlength(&a, sz); if (MustAlloc(n, sz)) _ntl_gsetlength(&n, sz); if (MustAlloc(d, sz)) _ntl_gsetlength(&d, sz); if (MustAlloc(u, sz)) _ntl_gsetlength(&u, sz); _ntl_gadd(ain, nin, &a); _ntl_gcopy(nin, &n); /* We apply mpn_gcdext to (a, n) = (ain+nin, nin), because that function * only computes the co-factor of the larger input. This way, we avoid * a multiplication and a division. */ sd = mpn_gcdext(DATA(d), DATA(u), &su, DATA(a), SIZE(a), DATA(n), SIZE(n)); SIZE(d) = sd; SIZE(u) = su; /* Thes two ForceNormal's are work-arounds for GMP bugs in GMP 4.3.0 */ ForceNormal(d); ForceNormal(u); if (ONEP(d)) { /* * We make sure that u is in range 0..n-1, just in case * GMP is sloppy. */ if (_ntl_gsign(u) < 0) { _ntl_gadd(u, nin, &u); if (_ntl_gsign(u) < 0) { _ntl_gmod(u, nin, &u); } } else if (_ntl_gcompare(u, nin) >= 0) { _ntl_gsub(u, nin, &u); if (_ntl_gcompare(u, nin) >= 0) { _ntl_gmod(u, nin, &u); } } _ntl_gcopy(u, invv); return 0; } else { _ntl_gcopy(d, invv); return 1; } } void _ntl_ginvmod( _ntl_gbigint a, _ntl_gbigint n, _ntl_gbigint *c ) { if (_ntl_ginv(a, n, c)) ghalt("undefined inverse in _ntl_ginvmod"); } void _ntl_gaddmod( _ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c ) { if (*c != n) { _ntl_gadd(a, b, c); if (_ntl_gcompare(*c, n) >= 0) _ntl_gsubpos(*c, n, c); } else { GRegister(mem); _ntl_gadd(a, b, &mem); if (_ntl_gcompare(mem, n) >= 0) _ntl_gsubpos(mem, n, c); else _ntl_gcopy(mem, c); } } void _ntl_gsubmod( _ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c ) { GRegister(mem); long cmp; if ((cmp=_ntl_gcompare(a, b)) < 0) { _ntl_gadd(n, a, &mem); _ntl_gsubpos(mem, b, c); } else if (!cmp) _ntl_gzero(c); else _ntl_gsubpos(a, b, c); } void _ntl_gsmulmod( _ntl_gbigint a, long d, _ntl_gbigint n, _ntl_gbigint *c ) { GRegister(mem); _ntl_gsmul(a, d, &mem); _ntl_gmod(mem, n, c); } void _ntl_gmulmod( _ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c ) { GRegister(mem); _ntl_gmul(a, b, &mem); _ntl_gmod(mem, n, c); } void _ntl_gsqmod( _ntl_gbigint a, _ntl_gbigint n, _ntl_gbigint *c ) { _ntl_gmulmod(a, a, n, c); } double _ntl_gdoub_aux(_ntl_gbigint n) { double res; mp_limb_t *ndata; long i, sn, nneg; if (!n) return ((double) 0); GET_SIZE_NEG(sn, nneg, n); ndata = DATA(n); res = 0; for (i = sn-1; i >= 0; i--) res = res * NTL_ZZ_FRADIX + ((double) ndata[i]); if (nneg) res = -res; return res; } long _ntl_ground_correction(_ntl_gbigint a, long k, long residual) { long direction; long p; long sgn; long bl; mp_limb_t wh; long i; mp_limb_t *adata; if (SIZE(a) > 0) sgn = 1; else sgn = -1; adata = DATA(a); p = k - 1; bl = (p/NTL_ZZ_NBITS); wh = ((mp_limb_t) 1) << (p - NTL_ZZ_NBITS*bl); if (adata[bl] & wh) { /* bit is 1...we have to see if lower bits are all 0 in order to implement "round to even" */ if (adata[bl] & (wh - ((mp_limb_t) 1))) direction = 1; else { i = bl - 1; while (i >= 0 && adata[i] == 0) i--; if (i >= 0) direction = 1; else direction = 0; } /* use residual to break ties */ if (direction == 0 && residual != 0) { if (residual == sgn) direction = 1; else direction = -1; } if (direction == 0) { /* round to even */ wh = wh << 1; /* * DIRT: if GMP has non-empty "nails", this won't work. */ if (wh == 0) { wh = 1; bl++; } if (adata[bl] & wh) direction = 1; else direction = -1; } } else direction = -1; if (direction == 1) return sgn; return 0; } double _ntl_gdoub(_ntl_gbigint n) { GRegister(tmp); long s; long shamt; long correction; double x; s = _ntl_g2log(n); shamt = s - NTL_DOUBLE_PRECISION; if (shamt <= 0) return _ntl_gdoub_aux(n); _ntl_grshift(n, shamt, &tmp); correction = _ntl_ground_correction(n, shamt, 0); if (correction) _ntl_gsadd(tmp, correction, &tmp); x = _ntl_gdoub_aux(tmp); x = _ntl_ldexp(x, shamt); return x; } double _ntl_glog(_ntl_gbigint n) { GRegister(tmp); static double log_2; static long init = 0; long s; long shamt; long correction; double x; if (!init) { log_2 = log(2.0); init = 1; } if (_ntl_gsign(n) <= 0) ghalt("log argument <= 0"); s = _ntl_g2log(n); shamt = s - NTL_DOUBLE_PRECISION; if (shamt <= 0) return log(_ntl_gdoub_aux(n)); _ntl_grshift(n, shamt, &tmp); correction = _ntl_ground_correction(n, shamt, 0); if (correction) _ntl_gsadd(tmp, correction, &tmp); x = _ntl_gdoub_aux(tmp); return log(x) + shamt*log_2; } /* To implement _ntl_gdoubtoz, I've implemented essentially the * same algorithm as in LIP, processing in blocks of * NTL_SP_NBITS bits, rather than NTL_ZZ_NBITS. * This is conversion is rather delicate, and I don't want to * make any new assumptions about the underlying arithmetic. * This implementation should be quite portable. */ void _ntl_gdoubtoz(double a, _ntl_gbigint *xx) { GRegister(x); long neg, i, t, sz; a = floor(a); if (!_ntl_IsFinite(&a)) ghalt("_ntl_gdoubtoz: attempt to convert non-finite value"); if (a < 0) { a = -a; neg = 1; } else neg = 0; if (a == 0) { _ntl_gzero(xx); return; } sz = 0; while (a >= 1) { a = a*(1.0/NTL_SP_FBOUND); sz++; } i = 0; _ntl_gzero(&x); while (a != 0) { i++; a = a*NTL_SP_FBOUND; t = (long) a; a = a - t; if (i == 1) { _ntl_gintoz(t, &x); } else { _ntl_glshift(x, NTL_SP_NBITS, &x); _ntl_gsadd(x, t, &x); } } if (i > sz) ghalt("bug in _ntl_gdoubtoz"); _ntl_glshift(x, (sz-i)*NTL_SP_NBITS, xx); if (neg) _ntl_gnegate(xx); } /* I've adapted LIP's extended euclidean algorithm to * do rational reconstruction. -- VJS. */ long _ntl_gxxratrecon( _ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint num_bound, _ntl_gbigint den_bound, _ntl_gbigint *num_out, _ntl_gbigint *den_out ) { GRegister(a); GRegister(n); GRegister(q); GRegister(w); GRegister(x); GRegister(y); GRegister(z); GRegister(inv); GRegister(u); GRegister(a_bak); GRegister(n_bak); GRegister(inv_bak); GRegister(w_bak); mp_limb_t *p; long diff; long ilo; long sa; long sn; long snum; long sden; long e; long fast; long temp; long parity; long gotthem; long try11; long try12; long try21; long try22; long got11; long got12; long got21; long got22; double hi; double lo; double dt; double fhi, fhi1; double flo, flo1; double num; double den; double dirt; if (_ntl_gsign(num_bound) < 0) ghalt("rational reconstruction: bad numerator bound"); if (!num_bound) snum = 0; else snum = SIZE(num_bound); if (_ntl_gsign(den_bound) <= 0) ghalt("rational reconstruction: bad denominator bound"); sden = SIZE(den_bound); if (_ntl_gsign(nin) <= 0) ghalt("rational reconstruction: bad modulus"); if (_ntl_gsign(ain) < 0 || _ntl_gcompare(ain, nin) >= 0) ghalt("rational reconstruction: bad residue"); e = SIZE(nin); _ntl_gsetlength(&a, e); _ntl_gsetlength(&n, e); _ntl_gsetlength(&q, e); _ntl_gsetlength(&w, e); _ntl_gsetlength(&x, e); _ntl_gsetlength(&y, e); _ntl_gsetlength(&z, e); _ntl_gsetlength(&inv, e); _ntl_gsetlength(&u, e); _ntl_gsetlength(&a_bak, e); _ntl_gsetlength(&n_bak, e); _ntl_gsetlength(&inv_bak, e); _ntl_gsetlength(&w_bak, e); fhi1 = 1.0 + ((double) 32.0)/NTL_FDOUBLE_PRECISION; flo1 = 1.0 - ((double) 32.0)/NTL_FDOUBLE_PRECISION; fhi = 1.0 + ((double) 8.0)/NTL_FDOUBLE_PRECISION; flo = 1.0 - ((double) 8.0)/NTL_FDOUBLE_PRECISION; _ntl_gcopy(ain, &a); _ntl_gcopy(nin, &n); _ntl_gone(&inv); _ntl_gzero(&w); while (1) { if (SIZE(w) >= sden && _ntl_gcompare(w, den_bound) > 0) break; if (SIZE(n) <= snum && _ntl_gcompare(n, num_bound) <= 0) break; _ntl_gcopy(a, &a_bak); _ntl_gcopy(n, &n_bak); _ntl_gcopy(w, &w_bak); _ntl_gcopy(inv, &inv_bak); gotthem = 0; sa = SIZE(a); sn = SIZE(n); diff = sa - sn; if (!diff || diff == 1) { sa = SIZE(a); p = DATA(a) + (sa-1); num = (double) (*p) * NTL_ZZ_FRADIX; if (sa > 1) num += (*(--p)); num *= NTL_ZZ_FRADIX; if (sa > 2) num += (*(p - 1)); sn = SIZE(n); p = DATA(n) + (sn-1); den = (double) (*p) * NTL_ZZ_FRADIX; if (sn > 1) den += (*(--p)); den *= NTL_ZZ_FRADIX; if (sn > 2) den += (*(p - 1)); hi = fhi1 * (num + 1.0) / den; lo = flo1 * num / (den + 1.0); if (diff > 0) { hi *= NTL_ZZ_FRADIX; lo *= NTL_ZZ_FRADIX; } try11 = 1; try12 = 0; try21 = 0; try22 = 1; parity = 1; fast = 1; while (fast > 0) { parity = 1 - parity; if (hi >= NTL_SP_BOUND) fast = 0; else { ilo = (long)lo; dirt = hi - ilo; if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi) fast = 0; else { dt = lo-ilo; lo = flo / dirt; if (dt > 1.0/NTL_FDOUBLE_PRECISION) hi = fhi / dt; else hi = NTL_SP_BOUND; temp = try11; try11 = try21; if ((NTL_WSP_BOUND - temp) / ilo < try21) fast = 0; else try21 = temp + ilo * try21; temp = try12; try12 = try22; if ((NTL_WSP_BOUND - temp) / ilo < try22) fast = 0; else try22 = temp + ilo * try22; if ((fast > 0) && (parity > 0)) { gotthem = 1; got11 = try11; got12 = try12; got21 = try21; got22 = try22; } } } } } if (gotthem) { _ntl_gsmul(inv, got11, &x); _ntl_gsmul(w, got12, &y); _ntl_gsmul(inv, got21, &z); _ntl_gsmul(w, got22, &w); _ntl_gadd(x, y, &inv); _ntl_gadd(z, w, &w); _ntl_gsmul(a, got11, &x); _ntl_gsmul(n, got12, &y); _ntl_gsmul(a, got21, &z); _ntl_gsmul(n, got22, &n); _ntl_gsub(x, y, &a); _ntl_gsub(n, z, &n); } else { _ntl_gdiv(a, n, &q, &a); _ntl_gmul(q, w, &x); _ntl_gadd(inv, x, &inv); if (!ZEROP(a)) { _ntl_gdiv(n, a, &q, &n); _ntl_gmul(q, inv, &x); _ntl_gadd(w, x, &w); } else { break; } } } _ntl_gcopy(a_bak, &a); _ntl_gcopy(n_bak, &n); _ntl_gcopy(w_bak, &w); _ntl_gcopy(inv_bak, &inv); _ntl_gnegate(&w); while (1) { sa = SIZE(w); if (sa < 0) SIZE(w) = -sa; if (SIZE(w) >= sden && _ntl_gcompare(w, den_bound) > 0) return 0; SIZE(w) = sa; if (SIZE(n) <= snum && _ntl_gcompare(n, num_bound) <= 0) break; fast = 0; sa = SIZE(a); sn = SIZE(n); diff = sa - sn; if (!diff || diff == 1) { sa = SIZE(a); p = DATA(a) + (sa-1); num = (double) (*p) * NTL_ZZ_FRADIX; if (sa > 1) num += (*(--p)); num *= NTL_ZZ_FRADIX; if (sa > 2) num += (*(p - 1)); sn = SIZE(n); p = DATA(n) + (sn-1); den = (double) (*p) * NTL_ZZ_FRADIX; if (sn > 1) den += (*(--p)); den *= NTL_ZZ_FRADIX; if (sn > 2) den += (*(p - 1)); hi = fhi1 * (num + 1.0) / den; lo = flo1 * num / (den + 1.0); if (diff > 0) { hi *= NTL_ZZ_FRADIX; lo *= NTL_ZZ_FRADIX; } if (hi < NTL_SP_BOUND) { ilo = (long)lo; if (ilo == (long)hi) fast = 1; } } if (fast) { if (ilo != 0) { if (ilo == 1) { _ntl_gsub(inv, w, &inv); _ntl_gsubpos(a, n, &a); } else { _ntl_gsmul(w, ilo, &x); _ntl_gsub(inv, x, &inv); _ntl_gsmul(n, ilo, &x); _ntl_gsubpos(a, x, &a); } } } else { _ntl_gdiv(a, n, &q, &a); _ntl_gmul(q, w, &x); _ntl_gsub(inv, x, &inv); } _ntl_gswap(&a, &n); _ntl_gswap(&inv, &w); } if (_ntl_gsign(w) < 0) { _ntl_gnegate(&w); _ntl_gnegate(&n); } _ntl_gcopy(n, num_out); _ntl_gcopy(w, den_out); return 1; } void _ntl_gexp( _ntl_gbigint a, long e, _ntl_gbigint *bb ) { long k; long len_a; GRegister(res); if (!e) { _ntl_gone(bb); return; } if (e < 0) ghalt("negative exponent in _ntl_gexp"); if (_ntl_giszero(a)) { _ntl_gzero(bb); return; } len_a = _ntl_g2log(a); if (len_a > (NTL_MAX_LONG-(NTL_ZZ_NBITS-1))/e) ghalt("overflow in _ntl_gexp"); _ntl_gsetlength(&res, (len_a*e+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); _ntl_gcopy(a, &res); k = 1; while ((k << 1) <= e) k <<= 1; while (k >>= 1) { _ntl_gsq(res, &res); if (e & k) _ntl_gmul(a, res, &res); } _ntl_gcopy(res, bb); } void _ntl_gexps( long a, long e, _ntl_gbigint *bb ) { long k; long len_a; GRegister(res); if (!e) { _ntl_gone(bb); return; } if (e < 0) ghalt("negative exponent in _ntl_zexps"); if (!a) { _ntl_gzero(bb); return; } len_a = _ntl_g2logs(a); if (len_a > (NTL_MAX_LONG-(NTL_ZZ_NBITS-1))/e) ghalt("overflow in _ntl_gexps"); _ntl_gsetlength(&res, (len_a*e+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); _ntl_gintoz(a, &res); k = 1; while ((k << 1) <= e) k <<= 1; while (k >>= 1) { _ntl_gsq(res, &res); if (e & k) _ntl_gsmul(res, a, &res); } _ntl_gcopy(res, bb); } static long OptWinSize(long n) /* finds k that minimizes n/(k+1) + 2^{k-1} */ { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/((double)(k+2)) + ((double)(1L << k)); if (v_new >= v) break; v = v_new; k++; } return k; } /* DIRT: will not work with non-empty "nails" */ static mp_limb_t neg_inv_mod_limb(mp_limb_t m0) { mp_limb_t x; long k; x = 1; k = 1; while (k < NTL_ZZ_NBITS) { x += x * (1 - x * m0); k <<= 1; } return - x; } /* Montgomery reduction: * This computes res = T/b^m mod N, where b = 2^{NTL_ZZ_NBITS}. * It is assumed that N has n limbs, and that T has at most n + m limbs. * Also, inv should be set to -N^{-1} mod b. * Finally, it is assumed that T has space allocated for n + m limbs, * and that res has space allocated for n limbs. * Note: res should not overlap any inputs, and T is destroyed. * Note: res will have at most n limbs, but may not be fully reduced * mod N. In general, we will have res < T/b^m + N. */ /* DIRT: this routine may not work with non-empty "nails" */ static void redc(_ntl_gbigint T, _ntl_gbigint N, long m, mp_limb_t inv, _ntl_gbigint res) { long n, sT, i; mp_limb_t *Ndata, *Tdata, *resdata, q, d, t, c; n = SIZE(N); Ndata = DATA(N); sT = SIZE(T); Tdata = DATA(T); resdata = DATA(res); for (i = sT; i < m+n; i++) Tdata[i] = 0; c = 0; for (i = 0; i < m; i++) { q = Tdata[i]*inv; d = mpn_addmul_1(Tdata+i, Ndata, n, q); t = Tdata[i+n] + d; Tdata[i+n] = t + c; if (t < d || (c == 1 && t + c == 0)) c = 1; else c = 0; } if (c) { mpn_sub_n(resdata, Tdata + m, Ndata, n); } else { for (i = 0; i < n; i++) resdata[i] = Tdata[m + i]; } i = n; STRIP(i, resdata); SIZE(res) = i; SIZE(T) = 0; } #define REDC_CROSS (32) void _ntl_gpowermod(_ntl_gbigint g, _ntl_gbigint e, _ntl_gbigint F, _ntl_gbigint *h) /* h = g^e mod f using "sliding window" algorithm remark: the notation (h, g, e, F) is strange, because I copied the code from BB.c. */ { _ntl_gbigint res, gg, *v, t; long n, i, k, val, cnt, m; long use_redc, sF; mp_limb_t inv; if (_ntl_gsign(g) < 0 || _ntl_gcompare(g, F) >= 0 || _ntl_gscompare(F, 1) <= 0) ghalt("PowerMod: bad args"); if (_ntl_gscompare(e, 0) == 0) { _ntl_gone(h); return; } if (_ntl_gscompare(e, 1) == 0) { _ntl_gcopy(g, h); return; } if (_ntl_gscompare(e, -1) == 0) { _ntl_ginvmod(g, F, h); return; } if (_ntl_gscompare(e, 2) == 0) { _ntl_gsqmod(g, F, h); return; } if (_ntl_gscompare(e, -2) == 0) { res = 0; _ntl_gsqmod(g, F, &res); _ntl_ginvmod(res, F, h); _ntl_gfree(&res); return; } n = _ntl_g2log(e); sF = SIZE(F); res = 0; _ntl_gsetlength(&res, sF*2); t = 0; _ntl_gsetlength(&t, sF*2); use_redc = (DATA(F)[0] & 1) && sF < REDC_CROSS; gg = 0; if (use_redc) { _ntl_glshift(g, sF*NTL_ZZ_NBITS, &res); _ntl_gmod(res, F, &gg); inv = neg_inv_mod_limb(DATA(F)[0]); } else _ntl_gcopy(g, &gg); if (_ntl_gscompare(g, 2) == 0) { /* plain square-and-multiply algorithm, optimized for g == 2 */ _ntl_gbigint F1 = 0; if (use_redc) { long shamt; COUNT_BITS(shamt, DATA(F)[sF-1]); shamt = NTL_ZZ_NBITS - shamt; _ntl_glshift(F, shamt, &F1); } _ntl_gcopy(gg, &res); for (i = n - 2; i >= 0; i--) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); if (_ntl_gbit(e, i)) { _ntl_gadd(res, res, &res); if (use_redc) { while (SIZE(res) > sF) { _ntl_gsubpos(res, F1, &res); } } else { if (_ntl_gcompare(res, F) >= 0) _ntl_gsubpos(res, F, &res); } } } if (use_redc) { _ntl_gcopy(res, &t); redc(t, F, sF, inv, res); if (_ntl_gcompare(res, F) >= 0) { _ntl_gsub(res, F, &res); } } if (_ntl_gsign(e) < 0) _ntl_ginvmod(res, F, &res); _ntl_gcopy(res, h); _ntl_gfree(&res); _ntl_gfree(&gg); _ntl_gfree(&t); _ntl_gfree(&F1); return; } if (n < 16) { /* plain square-and-multiply algorithm */ _ntl_gcopy(gg, &res); for (i = n - 2; i >= 0; i--) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); if (_ntl_gbit(e, i)) { _ntl_gmul(res, gg, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); } } if (use_redc) { _ntl_gcopy(res, &t); redc(t, F, sF, inv, res); if (_ntl_gcompare(res, F) >= 0) { _ntl_gsub(res, F, &res); } } if (_ntl_gsign(e) < 0) _ntl_ginvmod(res, F, &res); _ntl_gcopy(res, h); _ntl_gfree(&res); _ntl_gfree(&gg); _ntl_gfree(&t); return; } k = OptWinSize(n); if (k > 5) k = 5; v = (_ntl_gbigint *) NTL_MALLOC((1L << (k-1)), sizeof(_ntl_gbigint), 0); if (!v) ghalt("out of memory"); for (i = 0; i < (1L << (k-1)); i++) { v[i] = 0; _ntl_gsetlength(&v[i], sF); } _ntl_gcopy(gg, &v[0]); if (k > 1) { _ntl_gsq(gg, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); for (i = 1; i < (1L << (k-1)); i++) { _ntl_gmul(v[i-1], res, &t); if (use_redc) redc(t, F, sF, inv, v[i]); else _ntl_gmod(t, F, &v[i]); } } _ntl_gcopy(gg, &res); val = 0; for (i = n-2; i >= 0; i--) { val = (val << 1) | _ntl_gbit(e, i); if (val == 0) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); } else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); m = m >> 1; } _ntl_gmul(res, v[val >> 1], &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); while (cnt > 0) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); cnt--; } val = 0; } } if (use_redc) { _ntl_gcopy(res, &t); redc(t, F, sF, inv, res); if (_ntl_gcompare(res, F) >= 0) { _ntl_gsub(res, F, &res); } } if (_ntl_gsign(e) < 0) _ntl_ginvmod(res, F, &res); _ntl_gcopy(res, h); _ntl_gfree(&res); _ntl_gfree(&gg); _ntl_gfree(&t); for (i = 0; i < (1L << (k-1)); i++) _ntl_gfree(&v[i]); free(v); } long _ntl_gsize(_ntl_gbigint rep) { if (!rep) return 0; else if (SIZE(rep) < 0) return -SIZE(rep); else return SIZE(rep); } long _ntl_gisone(_ntl_gbigint rep) { return rep != 0 && SIZE(rep) == 1 && DATA(rep)[0] == 1; } long _ntl_gsptest(_ntl_gbigint rep) { return !rep || SIZE(rep) == 0 || ((SIZE(rep) == 1 || SIZE(rep) == -1) && DATA(rep)[0] < ((mp_limb_t) NTL_SP_BOUND)); } long _ntl_gwsptest(_ntl_gbigint rep) { return !rep || SIZE(rep) == 0 || ((SIZE(rep) == 1 || SIZE(rep) == -1) && DATA(rep)[0] < ((mp_limb_t) NTL_WSP_BOUND)); } long _ntl_gcrtinrange(_ntl_gbigint g, _ntl_gbigint a) { long sa, sg, i; mp_limb_t carry, u, v; mp_limb_t *adata, *gdata; if (!a || SIZE(a) <= 0) return 0; sa = SIZE(a); if (!g) return 1; sg = SIZE(g); if (sg == 0) return 1; if (sg < 0) sg = -sg; if (sa-sg > 1) return 1; if (sa-sg < 0) return 0; adata = DATA(a); gdata = DATA(g); carry=0; if (sa-sg == 1) { if (adata[sa-1] > ((mp_limb_t) 1)) return 1; carry = 1; } i = sg-1; u = 0; v = 0; while (i >= 0 && u == v) { u = (carry << (NTL_ZZ_NBITS-1)) + (adata[i] >> 1); v = gdata[i]; carry = (adata[i] & 1); i--; } if (u == v) { if (carry) return 1; return (SIZE(g) > 0); } else return (u > v); } /* DIRT: this routine will not work with non-empty "nails" */ void _ntl_gfrombytes(_ntl_gbigint *x, const unsigned char *p, long n) { long BytesPerLimb; long lw, r, i, j; mp_limb_t *xp, t; if (n <= 0) { x = 0; return; } BytesPerLimb = NTL_ZZ_NBITS/8; lw = n/BytesPerLimb; r = n - lw*BytesPerLimb; if (r != 0) lw++; else r = BytesPerLimb; _ntl_gsetlength(x, lw); xp = DATA(*x); for (i = 0; i < lw-1; i++) { t = 0; for (j = 0; j < BytesPerLimb; j++) { t >>= 8; t += (((mp_limb_t)(*p)) & ((mp_limb_t) 255)) << ((BytesPerLimb-1)*8); p++; } xp[i] = t; } t = 0; for (j = 0; j < r; j++) { t >>= 8; t += (((mp_limb_t)(*p)) & ((mp_limb_t) 255)) << ((BytesPerLimb-1)*8); p++; } t >>= (BytesPerLimb-r)*8; xp[lw-1] = t; STRIP(lw, xp); SIZE(*x) = lw; } /* DIRT: this routine will not work with non-empty "nails" */ void _ntl_gbytesfromz(unsigned char *p, _ntl_gbigint a, long n) { long BytesPerLimb; long lbits, lbytes, min_bytes, min_words, r; long i, j; mp_limb_t *ap, t; if (n < 0) n = 0; BytesPerLimb = NTL_ZZ_NBITS/8; lbits = _ntl_g2log(a); lbytes = (lbits+7)/8; min_bytes = (lbytes < n) ? lbytes : n; min_words = min_bytes/BytesPerLimb; r = min_bytes - min_words*BytesPerLimb; if (r != 0) min_words++; else r = BytesPerLimb; if (a) ap = DATA(a); else ap = 0; for (i = 0; i < min_words-1; i++) { t = ap[i]; for (j = 0; j < BytesPerLimb; j++) { *p = t & ((mp_limb_t) 255); t >>= 8; p++; } } if (min_words > 0) { t = ap[min_words-1]; for (j = 0; j < r; j++) { *p = t & ((mp_limb_t) 255); t >>= 8; p++; } } for (j = min_bytes; j < n; j++) { *p = 0; p++; } } long _ntl_gblock_construct_alloc(_ntl_gbigint *x, long d, long n) { long d1, sz, AllocAmt, m, j, alloc; char *p; _ntl_gbigint t; /* check n value */ if (n <= 0) ghalt("block construct: n must be positive"); /* check d value */ if (d <= 0) ghalt("block construct: d must be positive"); if (NTL_OVERFLOW(d, NTL_ZZ_NBITS, NTL_ZZ_NBITS)) ghalt("block construct: d too large"); d1 = d + 1; #ifdef NTL_SMALL_MP_SIZE_T /* this makes sure that numbers don't get too big for GMP */ if (d1 >= (1L << (NTL_BITS_PER_INT-4))) ghalt("size too big for GMP"); #endif if (STORAGE_OVF(d1)) ghalt("block construct: d too large"); sz = STORAGE(d1); AllocAmt = NTL_MAX_ALLOC_BLOCK/sz; if (AllocAmt == 0) AllocAmt = 1; if (AllocAmt < n) m = AllocAmt; else m = n; p = (char *) NTL_MALLOC(m, sz, 0); if (!p) ghalt("out of memory in _ntl_gblock_construct"); *x = (_ntl_gbigint) p; for (j = 0; j < m; j++) { t = (_ntl_gbigint) p; alloc = (d1 << 2) | 1; if (j < m-1) alloc |= 2; ALLOC(t) = alloc; SIZE(t) = 0; p += sz; } return m; } void _ntl_gblock_construct_set(_ntl_gbigint x, _ntl_gbigint *y, long i) { long d1, sz; d1 = ALLOC(x) >> 2; sz = STORAGE(d1); *y = (_ntl_gbigint) (((char *) x) + i*sz); } long _ntl_gblock_destroy(_ntl_gbigint x) { long d1, sz, alloc, m; char *p; _ntl_gbigint t; d1 = ALLOC(x) >> 2; sz = STORAGE(d1); p = (char *) x; m = 1; for (;;) { t = (_ntl_gbigint) p; alloc = ALLOC(t); if ((alloc & 1) == 0) ghalt("corrupted memory detected in _ntl_gblock_destroy"); if ((alloc & 2) == 0) break; m++; p += sz; } free(x); return m; } long _ntl_gblock_storage(long d) { long d1, sz; d1 = d + 1; sz = STORAGE(d1) + sizeof(_ntl_gbigint); return sz; } /* * This is a completely portable MulMod routine. */ #define SP_MUL_MOD(r, a, b, n) \ { \ long l__a = (a); \ long l__b = (b); \ long l__n = (n); \ long l__q; \ unsigned long l__res; \ \ l__q = (long) ((((double) l__a) * ((double) l__b)) / ((double) l__n)); \ l__res = ((unsigned long) l__a)*((unsigned long) l__b) - \ ((unsigned long) l__q)*((unsigned long) l__n); \ if (l__res >> (NTL_BITS_PER_LONG-1)) \ l__res += l__n; \ else if (((long) l__res) >= l__n) \ l__res -= l__n; \ \ r = (long) l__res; \ } #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING) && !defined(NTL_CLEAN_INT)) #define SP_MUL_MOD2(res, a, b, n, bninv) \ do { \ long _a = (a); \ long _b = (b); \ long _n = (n); \ double _bninv = (bninv); \ long _q, _res; \ \ _q = (long) (((double) _a) * _bninv); \ _res = _a*_b - _q*_n; \ \ _res += (_res >> (NTL_BITS_PER_LONG-1)) & _n; \ _res -= _n; \ _res += (_res >> (NTL_BITS_PER_LONG-1)) & _n; \ \ res = _res; \ } while (0) #else /* * This is a completely portable MulMod routine. */ #define SP_MUL_MOD2(res, a, b, n, bninv) \ do { \ long _a = (a); \ long _b = (b); \ long _n = (n); \ double _bninv = (bninv); \ long _q; \ unsigned long _res; \ \ _q = (long) (((double) _a) * _bninv); \ _res = ((unsigned long) _a)*((unsigned long) _b) - \ ((unsigned long) _q)*((unsigned long) _n); \ \ if (_res >> (NTL_BITS_PER_LONG-1)) \ _res += _n; \ else if (((long) _res) >= _n) \ _res -= _n; \ \ res = (long) _res; \ } while (0) #endif static long SpecialPower(long e, long p) { long a; long x, y; a = (long) ((((mp_limb_t) 1) << (NTL_ZZ_NBITS-2)) % ((mp_limb_t) p)); SP_MUL_MOD(a, a, 2, p); SP_MUL_MOD(a, a, 2, p); x = 1; y = a; while (e) { if (e & 1) SP_MUL_MOD(x, x, y, p); SP_MUL_MOD(y, y, y, p); e = e >> 1; } return x; } static void sp_ext_eucl(long *dd, long *ss, long *tt, long a, long b) { long u, v, u0, v0, u1, v1, u2, v2, q, r; long aneg = 0, bneg = 0; if (a < 0) { if (a < -NTL_MAX_LONG) ghalt("integer overflow"); a = -a; aneg = 1; } if (b < 0) { if (b < -NTL_MAX_LONG) ghalt("integer overflow"); b = -b; bneg = 1; } u1=1; v1=0; u2=0; v2=1; u = a; v = b; while (v != 0) { q = u / v; r = u % v; u = v; v = r; u0 = u2; v0 = v2; u2 = u1 - q*u2; v2 = v1- q*v2; u1 = u0; v1 = v0; } if (aneg) u1 = -u1; if (bneg) v1 = -v1; *dd = u; *ss = u1; *tt = v1; } static long sp_inv_mod(long a, long n) { long d, s, t; sp_ext_eucl(&d, &s, &t, a, n); if (d != 1) ghalt("inverse undefined"); if (s < 0) return s + n; else return s; } // FIXME: in a thread safe implementation, I have to rethink // this strategy, as multiple threads may be accessing the same // CRT structures...I may have to separate tables that are // initialized once and shareable, from scratch space, which needs // to be thread local struct crt_body_gmp { _ntl_gbigint *v; long sbuf; long n; _ntl_gbigint buf; }; struct crt_body_gmp1 { long n; long levels; long *primes; long *inv_vec; long *val_vec; long *index_vec; _ntl_gbigint *prod_vec; _ntl_gbigint *rem_vec; _ntl_gbigint *coeff_vec; _ntl_gbigint temps[2]; _ntl_gbigint modulus; }; struct crt_body { long strategy; union { struct crt_body_gmp G; struct crt_body_gmp1 G1; } U; }; void _ntl_gcrt_struct_init(void **crt_struct, long n, _ntl_gbigint p, const long *primes) { struct crt_body *c; c = (struct crt_body *) NTL_MALLOC(1, sizeof(struct crt_body), 0); if (!c) ghalt("out of memory"); if (n >= 600) { struct crt_body_gmp1 *C = &c->U.G1; long *q; long i, j; long levels, vec_len; long *val_vec, *inv_vec; long *index_vec; _ntl_gbigint *prod_vec, *rem_vec, *coeff_vec; _ntl_gbigint *temps; C->modulus = 0; _ntl_gcopy(p, &C->modulus); temps = &C->temps[0]; temps[0] = 0; temps[1] = 0; q = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!q) ghalt("out of memory"); val_vec = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!val_vec) ghalt("out of memory"); inv_vec = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!inv_vec) ghalt("out of memory"); for (i = 0; i < n; i++) q[i] = primes[i]; levels = 0; while ((n >> levels) >= 16) levels++; vec_len = (1L << levels) - 1; index_vec = (long *) NTL_MALLOC((vec_len+1), sizeof(long), 0); if (!index_vec) ghalt("out of memory"); prod_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0); if (!prod_vec) ghalt("out of memory"); rem_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0); if (!rem_vec) ghalt("out of memory"); coeff_vec = (_ntl_gbigint *) NTL_MALLOC(n, sizeof(_ntl_gbigint), 0); if (!coeff_vec) ghalt("out of memory"); for (i = 0; i < vec_len; i++) prod_vec[i] = 0; for (i = 0; i < vec_len; i++) rem_vec[i] = 0; for (i = 0; i < n; i++) coeff_vec[i] = 0; index_vec[0] = 0; index_vec[1] = n; for (i = 0; i <= levels-2; i++) { long start = (1L << i) - 1; long finish = (1L << (i+1)) - 2; for (j = finish; j >= start; j--) { index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2; index_vec[2*j+1] = index_vec[j]; } index_vec[2*finish+3] = n; } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { /* multiply primes index_vec[i]..index_vec[i+1]-1 into * prod_vec[i] */ _ntl_gone(&prod_vec[i]); for (j = index_vec[i]; j < index_vec[i+1]; j++) _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { for (j = index_vec[i]; j < index_vec[i+1]; j++) _ntl_gsdiv(prod_vec[i], q[j], &coeff_vec[j]); } for (i = (1L << (levels-1)) - 2; i >= 0; i--) _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]); /*** new asymptotically fast code to compute inv_vec ***/ _ntl_gone(&rem_vec[0]); for (i = 0; i < (1L << (levels-1)) - 1; i++) { _ntl_gmod(rem_vec[i], prod_vec[2*i+1], &temps[0]); _ntl_gmul(temps[0], prod_vec[2*i+2], &temps[1]); _ntl_gmod(temps[1], prod_vec[2*i+1], &rem_vec[2*i+1]); _ntl_gmod(rem_vec[i], prod_vec[2*i+2], &temps[0]); _ntl_gmul(temps[0], prod_vec[2*i+1], &temps[1]); _ntl_gmod(temps[1], prod_vec[2*i+2], &rem_vec[2*i+2]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { for (j = index_vec[i]; j < index_vec[i+1]; j++) { long tt, tt1, tt2; _ntl_gsdiv(prod_vec[i], q[j], &temps[0]); tt = _ntl_gsmod(temps[0], q[j]); tt1 = _ntl_gsmod(rem_vec[i], q[j]); SP_MUL_MOD(tt2, tt, tt1, q[j]); inv_vec[j] = sp_inv_mod(tt2, q[j]); } } #if 0 /* the following is asymptotically the bottleneck...but it * it probably doesn't matter. */ fprintf(stderr, "checking in lip\n"); for (i = 0; i < n; i++) { long tt; _ntl_gsdiv(prod_vec[0], q[i], &temps[0]); tt = mpn_mod_1(DATA(temps[0]), SIZE(temps[0]), q[i]); if (inv_vec[i] != sp_inv_mod(tt, q[i])) fprintf(stderr, "oops in lip\n"); /* inv_vec[i] = sp_inv_mod(tt, q[i]); */ } #endif c->strategy = 2; C->n = n; C->primes = q; C->val_vec = val_vec; C->inv_vec = inv_vec; C->levels = levels; C->index_vec = index_vec; C->prod_vec = prod_vec; C->rem_vec = rem_vec; C->coeff_vec = coeff_vec; *crt_struct = (void *) c; return; } { struct crt_body_gmp *C = &c->U.G; long i; c->strategy = 1; C->n = n; C->v = (_ntl_gbigint *) NTL_MALLOC(n, sizeof(_ntl_gbigint), 0); if (!C->v) ghalt("out of memory"); for (i = 0; i < n; i++) C->v[i] = 0; C->sbuf = SIZE(p)+2; C->buf = 0; _ntl_gsetlength(&C->buf, C->sbuf); *crt_struct = (void *) c; return; } } void _ntl_gcrt_struct_insert(void *crt_struct, long i, _ntl_gbigint m) { struct crt_body *c = (struct crt_body *) crt_struct; switch (c->strategy) { case 1: { _ntl_gcopy(m, &c->U.G.v[i]); break; } default: ghalt("_ntl_gcrt_struct_insert: inconsistent strategy"); } /* end switch */ } void _ntl_gcrt_struct_free(void *crt_struct) { struct crt_body *c = (struct crt_body *) crt_struct; switch (c->strategy) { case 1: { struct crt_body_gmp *C = &c->U.G; long i, n; n = C->n; for (i = 0; i < n; i++) _ntl_gfree(&C->v[i]); _ntl_gfree(&C->buf); free(C->v); free(c); break; } case 2: { struct crt_body_gmp1 *C = &c->U.G1; long n = C->n; long levels = C->levels; long *primes = C->primes; long *inv_vec = C->inv_vec; long *val_vec = C->val_vec; long *index_vec = C->index_vec; _ntl_gbigint *prod_vec = C->prod_vec; _ntl_gbigint *rem_vec = C->rem_vec; _ntl_gbigint *coeff_vec = C->coeff_vec; _ntl_gbigint *temps = C->temps; _ntl_gbigint modulus = C->modulus; long vec_len = (1L << levels) - 1; long i; for (i = 0; i < vec_len; i++) _ntl_gfree(&prod_vec[i]); for (i = 0; i < vec_len; i++) _ntl_gfree(&rem_vec[i]); for (i = 0; i < n; i++) _ntl_gfree(&coeff_vec[i]); _ntl_gfree(&temps[0]); _ntl_gfree(&temps[1]); _ntl_gfree(&modulus); free(primes); free(inv_vec); free(val_vec); free(index_vec); free(prod_vec); free(rem_vec); free(coeff_vec); free(c); break; } default: ghalt("_ntl_gcrt_struct_free: inconsistent strategy"); } /* end case */ } static void gadd_mul_many(_ntl_gbigint *res, _ntl_gbigint *a, long *b, long n, long sz) { mp_limb_t *xx, *yy; long i, sx; long sy; mp_limb_t carry; sx = sz + 2; if (MustAlloc(*res, sx)) _ntl_gsetlength(res, sx); xx = DATA(*res); for (i = 0; i < sx; i++) xx[i] = 0; for (i = 0; i < n; i++) { if (!a[i]) continue; yy = DATA(a[i]); sy = SIZE(a[i]); if (!sy || !b[i]) continue; carry = mpn_addmul_1(xx, yy, sy, b[i]); yy = xx + sy; *yy += carry; if (*yy < carry) { /* unsigned comparison! */ do { yy++; *yy += 1; } while (*yy == 0); } } while (sx > 0 && xx[sx-1] == 0) sx--; SIZE(*res) = sx; } void _ntl_gcrt_struct_eval(void *crt_struct, _ntl_gbigint *x, const long *b) { struct crt_body *c = (struct crt_body *) crt_struct; switch (c->strategy) { case 1: { struct crt_body_gmp *C = &c->U.G; mp_limb_t *xx, *yy; _ntl_gbigint *a; long i, sx, n; long sy; mp_limb_t carry; n = C->n; sx = C->sbuf; xx = DATA(C->buf); for (i = 0; i < sx; i++) xx[i] = 0; a = C->v; for (i = 0; i < n; i++) { if (!a[i]) continue; yy = DATA(a[i]); sy = SIZE(a[i]); if (!sy || !b[i]) continue; carry = mpn_addmul_1(xx, yy, sy, b[i]); yy = xx + sy; *yy += carry; if (*yy < carry) { /* unsigned comparison! */ do { yy++; *yy += 1; } while (*yy == 0); } } while (sx > 0 && xx[sx-1] == 0) sx--; SIZE(C->buf) = sx; _ntl_gcopy(C->buf, x); break; } case 2: { struct crt_body_gmp1 *C = &c->U.G1; long n = C->n; long levels = C->levels; long *primes = C->primes; long *inv_vec = C->inv_vec; long *val_vec = C->val_vec; long *index_vec = C->index_vec; _ntl_gbigint *prod_vec = C->prod_vec; _ntl_gbigint *rem_vec = C->rem_vec; _ntl_gbigint *coeff_vec = C->coeff_vec; _ntl_gbigint *temps = C->temps; long vec_len = (1L << levels) - 1; long i, j; for (i = 0; i < n; i++) { SP_MUL_MOD(val_vec[i], b[i], inv_vec[i], primes[i]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { long j1 = index_vec[i]; long j2 = index_vec[i+1]; gadd_mul_many(&rem_vec[i], &coeff_vec[j1], &val_vec[j1], j2-j1, SIZE(prod_vec[i])); } for (i = (1L << (levels-1)) - 2; i >= 0; i--) { _ntl_gmul(prod_vec[2*i+1], rem_vec[2*i+2], &temps[0]); _ntl_gmul(rem_vec[2*i+1], prod_vec[2*i+2], &temps[1]); _ntl_gadd(temps[0], temps[1], &rem_vec[i]); } /* temps[0] = rem_vec[0] mod prod_vec[0] (least absolute residue) */ _ntl_gmod(rem_vec[0], prod_vec[0], &temps[0]); _ntl_gsub(temps[0], prod_vec[0], &temps[1]); _ntl_gnegate(&temps[1]); if (_ntl_gcompare(temps[0], temps[1]) > 0) { _ntl_gnegate(&temps[1]); _ntl_gcopy(temps[1], &temps[0]); } _ntl_gmod(temps[0], C->modulus, &temps[1]); _ntl_gcopy(temps[1], x); break; } default: ghalt("_crt_gstruct_eval: inconsistent strategy"); } /* end case */ } long _ntl_gcrt_struct_special(void *crt_struct) { struct crt_body *c = (struct crt_body *) crt_struct; return (c->strategy == 2); } struct rem_body_lip { long n; long *primes; }; struct rem_body_gmp { long n; long levels; long *primes; long *index_vec; _ntl_gbigint *prod_vec; _ntl_gbigint *rem_vec; }; struct rem_body_gmp1 { long n; long levels; long *primes; long *index_vec; long *len_vec; mp_limb_t *inv_vec; long *corr_vec; double *corraux_vec; _ntl_gbigint *prod_vec; _ntl_gbigint *rem_vec; }; struct rem_body { long strategy; union { struct rem_body_lip L; struct rem_body_gmp G; struct rem_body_gmp1 G1; } U; }; void _ntl_grem_struct_init(void **rem_struct, long n, _ntl_gbigint modulus, const long *p) { struct rem_body *r; r = (struct rem_body *) NTL_MALLOC(1, sizeof(struct rem_body), 0); if (!r) ghalt("out of memory"); if ( n >= 32 && n <= 256) { struct rem_body_gmp1 *R = &r->U.G1; long *q; long i, j; long levels, vec_len; long *index_vec; long *len_vec, *corr_vec; double *corraux_vec; mp_limb_t *inv_vec; _ntl_gbigint *prod_vec, *rem_vec; q = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!q) ghalt("out of memory"); for (i = 0; i < n; i++) q[i] = p[i]; levels = 0; while ((n >> levels) >= 4) levels++; vec_len = (1L << levels) - 1; index_vec = (long *) NTL_MALLOC((vec_len+1), sizeof(long), 0); if (!index_vec) ghalt("out of memory"); len_vec = (long *) NTL_MALLOC(vec_len, sizeof(long), 0); if (!len_vec) ghalt("out of memory"); inv_vec = (mp_limb_t *) NTL_MALLOC(vec_len, sizeof(mp_limb_t), 0); if (!inv_vec) ghalt("out of memory"); corr_vec = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!corr_vec) ghalt("out of memory"); corraux_vec = (double *) NTL_MALLOC(n, sizeof(double), 0); if (!corraux_vec) ghalt("out of memory"); prod_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0); if (!prod_vec) ghalt("out of memory"); rem_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0); if (!rem_vec) ghalt("out of memory"); for (i = 0; i < vec_len; i++) prod_vec[i] = 0; for (i = 0; i < vec_len; i++) rem_vec[i] = 0; index_vec[0] = 0; index_vec[1] = n; for (i = 0; i <= levels-2; i++) { long start = (1L << i) - 1; long finish = (1L << (i+1)) - 2; for (j = finish; j >= start; j--) { index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2; index_vec[2*j+1] = index_vec[j]; } index_vec[2*finish+3] = n; } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { /* multiply primes index_vec[i]..index_vec[i+1]-1 into * prod_vec[i] */ _ntl_gone(&prod_vec[i]); for (j = index_vec[i]; j < index_vec[i+1]; j++) _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]); } for (i = (1L << (levels-1)) - 2; i >= 3; i--) _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]); for (i = 3; i < vec_len; i++) len_vec[i] = _ntl_gsize(prod_vec[i]); /* Set len_vec[1] = len_vec[2] = * max(_ntl_gsize(modulus), len_vec[3..6]). * This is a bit paranoid, but it makes the code * more robust. */ j = _ntl_gsize(modulus); for (i = 3; i <= 6; i++) if (len_vec[i] > j) j = len_vec[i]; len_vec[1] = len_vec[2] = j; for (i = 3; i < vec_len; i++) inv_vec[i] = neg_inv_mod_limb(DATA(prod_vec[i])[0]); for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { for (j = index_vec[i]; j < index_vec[i+1]; j++) { corr_vec[j] = SpecialPower(len_vec[1] - len_vec[i], q[j]); corraux_vec[j] = ((double) corr_vec[j])/((double) q[j]); } } /* allocate length in advance to streamline eval code */ _ntl_gsetlength(&rem_vec[0], len_vec[1]); /* a special temp */ for (i = 1; i < vec_len; i++) _ntl_gsetlength(&rem_vec[i], len_vec[i]); r->strategy = 2; R->n = n; R->primes = q; R->levels = levels; R->index_vec = index_vec; R->len_vec = len_vec; R->inv_vec = inv_vec; R->corr_vec = corr_vec; R->corraux_vec = corraux_vec; R->prod_vec = prod_vec; R->rem_vec = rem_vec; *rem_struct = (void *) r; } else if (n >= 32) { struct rem_body_gmp *R = &r->U.G; long *q; long i, j; long levels, vec_len; long *index_vec; _ntl_gbigint *prod_vec, *rem_vec; q = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!q) ghalt("out of memory"); for (i = 0; i < n; i++) q[i] = p[i]; levels = 0; while ((n >> levels) >= 4) levels++; vec_len = (1L << levels) - 1; index_vec = (long *) NTL_MALLOC((vec_len+1), sizeof(long), 0); if (!index_vec) ghalt("out of memory"); prod_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0); if (!prod_vec) ghalt("out of memory"); rem_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0); if (!rem_vec) ghalt("out of memory"); for (i = 0; i < vec_len; i++) prod_vec[i] = 0; for (i = 0; i < vec_len; i++) rem_vec[i] = 0; index_vec[0] = 0; index_vec[1] = n; for (i = 0; i <= levels-2; i++) { long start = (1L << i) - 1; long finish = (1L << (i+1)) - 2; for (j = finish; j >= start; j--) { index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2; index_vec[2*j+1] = index_vec[j]; } index_vec[2*finish+3] = n; } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { /* multiply primes index_vec[i]..index_vec[i+1]-1 into * prod_vec[i] */ _ntl_gone(&prod_vec[i]); for (j = index_vec[i]; j < index_vec[i+1]; j++) _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]); } for (i = (1L << (levels-1)) - 2; i >= 3; i--) _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]); /* allocate length in advance to streamline eval code */ _ntl_gsetlength(&rem_vec[1], _ntl_gsize(modulus)); _ntl_gsetlength(&rem_vec[2], _ntl_gsize(modulus)); for (i = 1; i < (1L << (levels-1)) - 1; i++) { _ntl_gsetlength(&rem_vec[2*i+1], _ntl_gsize(prod_vec[2*i+1])); _ntl_gsetlength(&rem_vec[2*i+2], _ntl_gsize(prod_vec[2*i+2])); } r->strategy = 1; R->n = n; R->primes = q; R->levels = levels; R->index_vec = index_vec; R->prod_vec = prod_vec; R->rem_vec = rem_vec; *rem_struct = (void *) r; } else { struct rem_body_lip *R = &r->U.L; long *q; long i; r->strategy = 0; R->n = n; q = (long *) NTL_MALLOC(n, sizeof(long), 0); if (!q) ghalt("out of memory"); R->primes = q; for (i = 0; i < n; i++) q[i] = p[i]; *rem_struct = (void *) r; } } void _ntl_grem_struct_free(void *rem_struct) { struct rem_body *r = (struct rem_body *) rem_struct; switch (r->strategy) { case 0: { free(r->U.L.primes); free(r); break; } case 1: { struct rem_body_gmp *R = &r->U.G; long levels = R->levels; long vec_len = (1L << levels) - 1; long i; for (i = 0; i < vec_len; i++) _ntl_gfree(&R->prod_vec[i]); for (i = 0; i < vec_len; i++) _ntl_gfree(&R->rem_vec[i]); free(R->primes); free(R->index_vec); free(R->prod_vec); free(R->rem_vec); free(r); break; } case 2: { struct rem_body_gmp1 *R = &r->U.G1; long levels = R->levels; long vec_len = (1L << levels) - 1; long i; for (i = 0; i < vec_len; i++) _ntl_gfree(&R->prod_vec[i]); for (i = 0; i < vec_len; i++) _ntl_gfree(&R->rem_vec[i]); free(R->primes); free(R->index_vec); free(R->len_vec); free(R->corr_vec); free(R->inv_vec); free(R->corraux_vec); free(R->prod_vec); free(R->rem_vec); free(r); break; } default: ghalt("_ntl_grem_struct_free: inconsistent strategy"); } /* end switch */ } void _ntl_grem_struct_eval(void *rem_struct, long *x, _ntl_gbigint a) { struct rem_body *r = (struct rem_body *) rem_struct; switch (r->strategy) { case 0: { struct rem_body_lip *R = &r->U.L; long n = R->n; long *q = R->primes; long j; mp_limb_t *adata; long sa; if (!a) sa = 0; else sa = SIZE(a); if (sa == 0) { for (j = 0; j < n; j++) x[j] = 0; break; } adata = DATA(a); for (j = 0; j < n; j++) x[j] = mpn_mod_1(adata, sa, q[j]); break; } case 1: { struct rem_body_gmp *R = &r->U.G; long n = R->n; long levels = R->levels; long *q = R->primes; long *index_vec = R->index_vec; _ntl_gbigint *prod_vec = R->prod_vec; _ntl_gbigint *rem_vec = R->rem_vec; long vec_len = (1L << levels) - 1; long i, j; if (ZEROP(a)) { for (j = 0; j < n; j++) x[j] = 0; break; } _ntl_gcopy(a, &rem_vec[1]); _ntl_gcopy(a, &rem_vec[2]); for (i = 1; i < (1L << (levels-1)) - 1; i++) { gmod_simple(rem_vec[i], prod_vec[2*i+1], &rem_vec[2*i+1]); gmod_simple(rem_vec[i], prod_vec[2*i+2], &rem_vec[2*i+2]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { long lo = index_vec[i]; long hi = index_vec[i+1]; mp_limb_t *s1p = DATA(rem_vec[i]); long s1size = SIZE(rem_vec[i]); if (s1size == 0) { for (j = lo; j U.G1; long n = R->n; long levels = R->levels; long *q = R->primes; long *index_vec = R->index_vec; long *len_vec = R->len_vec; long *corr_vec = R->corr_vec; double *corraux_vec = R->corraux_vec; mp_limb_t *inv_vec = R->inv_vec; _ntl_gbigint *prod_vec = R->prod_vec; _ntl_gbigint *rem_vec = R->rem_vec; long vec_len = (1L << levels) - 1; long i, j; if (ZEROP(a)) { for (j = 0; j < n; j++) x[j] = 0; break; } _ntl_gcopy(a, &rem_vec[1]); _ntl_gcopy(a, &rem_vec[2]); for (i = 1; i < (1L << (levels-1)) - 1; i++) { _ntl_gcopy(rem_vec[i], &rem_vec[0]); redc(rem_vec[0], prod_vec[2*i+1], len_vec[i]-len_vec[2*i+1], inv_vec[2*i+1], rem_vec[2*i+1]); redc(rem_vec[i], prod_vec[2*i+2], len_vec[i]-len_vec[2*i+2], inv_vec[2*i+2], rem_vec[2*i+2]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { long lo = index_vec[i]; long hi = index_vec[i+1]; mp_limb_t *s1p = DATA(rem_vec[i]); long s1size = SIZE(rem_vec[i]); if (s1size == 0) { for (j = lo; j 0) { \ (*__p)++; \ if (*__p != 0) break; \ __p++; \ __n--; \ } \ } while (0); #define _ntl_g_inc_carry(c, p, n) \ do { \ mp_limb_t * __p = (p); \ long __n = (n); \ long __addc = 1; \ while (__n > 0) { \ (*__p)++; \ if (*__p != 0) { __addc = 0; break; } \ __p++; \ __n--; \ } \ c += __addc; \ } while (0); #define _ntl_g_dec(p, n) \ do { \ mp_limb_t * __p = (p); \ mp_limb_t __tmp; \ long __n = (n); \ while (__n > 0) { \ __tmp = *__p; \ (*__p)--; \ if (__tmp != 0) break; \ __p++; \ __n--; \ } \ } while (0); /* sub==0 means an addmul w += x*y, sub==1 means a submul w -= x*y. */ void _ntl_gaorsmul_1(_ntl_gbigint x, long yy, long sub, _ntl_gbigint *ww) { long xsize, wsize, wsize_signed, new_wsize, min_size, dsize; _ntl_gbigint w; mp_limb_t *xp; mp_limb_t *wp; mp_limb_t cy; mp_limb_t y; if (ZEROP(x) || yy == 0) return; if (ZEROP(*ww)) { _ntl_gsmul(x, yy, ww); if (sub) SIZE(*ww) = -SIZE(*ww); return; } if (yy == 1) { if (sub) _ntl_gsub(*ww, x, ww); else _ntl_gadd(*ww, x, ww); return; } if (yy == -1) { if (sub) _ntl_gadd(*ww, x, ww); else _ntl_gsub(*ww, x, ww); return; } if (*ww == x) { GRegister(tmp); _ntl_gsmul(x, yy, &tmp); if (sub) _ntl_gsub(*ww, tmp, ww); else _ntl_gadd(*ww, tmp, ww); return; } xsize = SIZE(x); if (xsize < 0) { xsize = -xsize; sub = 1-sub; } if (yy < 0) { y = - ((mp_limb_t) yy); /* careful! */ sub = 1-sub; } else { y = (mp_limb_t) yy; } w = *ww; wsize_signed = SIZE(w); if (wsize_signed < 0) { sub = 1-sub; wsize = -wsize_signed; } else { wsize = wsize_signed; } if (wsize > xsize) { new_wsize = wsize; min_size = xsize; } else { new_wsize = xsize; min_size = wsize; } if (MustAlloc(w, new_wsize+1)) { _ntl_gsetlength(&w, new_wsize+1); *ww = w; } wp = DATA(w); xp = DATA(x); if (sub == 0) { /* addmul of absolute values */ cy = mpn_addmul_1 (wp, xp, min_size, y); wp += min_size; xp += min_size; dsize = xsize - wsize; if (dsize != 0) { mp_limb_t cy2; if (dsize > 0) { cy2 = mpn_mul_1 (wp, xp, dsize, y); } else { dsize = -dsize; cy2 = 0; } cy = cy2 + mpn_add_1 (wp, wp, dsize, cy); } wp[dsize] = cy; new_wsize += (cy != 0); } else { /* submul of absolute values */ cy = mpn_submul_1 (wp, xp, min_size, y); if (wsize >= xsize) { /* if w bigger than x, then propagate borrow through it */ if (wsize != xsize) { cy = mpn_sub_1 (wp+xsize, wp+xsize, wsize-xsize, cy); } if (cy != 0) { /* Borrow out of w, take twos complement negative to get absolute value, flip sign of w. */ wp[new_wsize] = ~-cy; /* extra limb is 0-cy */ _ntl_mpn_com_n (wp, wp, new_wsize); new_wsize++; _ntl_g_inc(wp, new_wsize); wsize_signed = -wsize_signed; } } else /* wsize < xsize */ { /* x bigger than w, so want x*y-w. Submul has given w-x*y, so take twos complement and use an mpn_mul_1 for the rest. */ mp_limb_t cy2; /* -(-cy*b^n + w-x*y) = (cy-1)*b^n + ~(w-x*y) + 1 */ _ntl_mpn_com_n (wp, wp, wsize); _ntl_g_inc_carry(cy, wp, wsize); cy -= 1; /* If cy-1 == -1 then hold that -1 for latter. mpn_submul_1 never returns cy==MP_LIMB_T_MAX so that value always indicates a -1. */ cy2 = (cy == ((mp_limb_t) -1)); cy += cy2; _ntl_MPN_MUL_1C (cy, wp+wsize, xp+wsize, xsize-wsize, y, cy); wp[new_wsize] = cy; new_wsize += (cy != 0); /* Apply any -1 from above. The value at wp+wsize is non-zero because y!=0 and the high limb of x will be non-zero. */ if (cy2) { _ntl_g_dec(wp+wsize, new_wsize-wsize); } wsize_signed = -wsize_signed; } /* submul can produce high zero limbs due to cancellation, both when w has more limbs or x has more */ STRIP(new_wsize, wp); } SIZE(w) = (wsize_signed >= 0 ? new_wsize : -new_wsize); } void _ntl_gsaddmul(_ntl_gbigint x, long yy, _ntl_gbigint *ww) { _ntl_gaorsmul_1(x, yy, 0, ww); } void _ntl_gssubmul(_ntl_gbigint x, long yy, _ntl_gbigint *ww) { _ntl_gaorsmul_1(x, yy, 1, ww); } void _ntl_gaorsmul(_ntl_gbigint x, _ntl_gbigint y, long sub, _ntl_gbigint *ww) { GRegister(tmp); _ntl_gmul(x, y, &tmp); if (sub) _ntl_gsub(*ww, tmp, ww); else _ntl_gadd(*ww, tmp, ww); } void _ntl_gaddmul(_ntl_gbigint x, _ntl_gbigint y, _ntl_gbigint *ww) { _ntl_gaorsmul(x, y, 0, ww); } void _ntl_gsubmul(_ntl_gbigint x, _ntl_gbigint y, _ntl_gbigint *ww) { _ntl_gaorsmul(x, y, 1, ww); } ntl-6.2.1/src/gen_gmp_aux.c000644 000765 000024 00000004232 12377144456 016060 0ustar00shoupstaff000000 000000 #include #include #include #include #ifndef NTL_GMP_LIP int main() { fprintf(stderr, "NTL_GMP_LIP flag not set\n"); return 0; } #else #include #include void print2k(FILE *f, long k, long bpl) { long m, l; long first; if (k <= 0) { fprintf(f, "((double) 1.0)"); return; } m = bpl - 2; first = 1; fprintf(f, "("); while (k > 0) { if (k > m) l = m; else l = k; k = k - l; if (first) first = 0; else fprintf(f, "*"); fprintf(f, "((double)(1L<<%ld))", l); } fprintf(f, ")"); } void Error(const char *s) { fprintf(stderr, "%s\n", s); abort(); } int main() { long bpl; long ntl_zz_nbits, ntl_wsp_nbits, ntl_sp_nbits; fprintf(stderr, "NTL_GMP_LIP flag set\n"); bpl = NTL_BITS_PER_LONG; /* * We require that the number of bits per limb quantity correspond to the * number of bits of a long, or possibly a "long long" that is twice as wide * as a long. These restrictions will almost certainly be satisfied, unless * GMP is installed using the newly proposed "nail" option. */ ntl_zz_nbits = 0; if (sizeof(mp_limb_t) == sizeof(long) && mp_bits_per_limb == bpl) ntl_zz_nbits = bpl; else if (sizeof(mp_limb_t) == 2*sizeof(long) && mp_bits_per_limb == 2*bpl) ntl_zz_nbits = 2*bpl; else Error("sorry...this is a funny gmp"); if (sizeof(mp_size_t) != sizeof(long) && sizeof(mp_size_t) != sizeof(int)) Error("sorry...this is a funny gmp"); ntl_wsp_nbits = bpl - 2; ntl_sp_nbits = NTL_NBITS_MAX; if (sizeof(mp_size_t) < sizeof(long)) { printf("#define NTL_SMALL_MP_SIZE_T\n"); fprintf(stderr, "setting NTL_SMALL_MP_SIZE_T\n"); } fprintf(stderr, "NTL_ZZ_NBITS = %ld\n", ntl_zz_nbits); fprintf(stderr, "NTL_WSP_NBITS = %ld\n", ntl_wsp_nbits); fprintf(stderr, "NTL_SP_NBITS = %ld\n", ntl_sp_nbits); printf("#define NTL_ZZ_NBITS (%ld)\n", ntl_zz_nbits); printf("#define NTL_ZZ_FRADIX "); print2k(stdout, ntl_zz_nbits, bpl); printf("\n"); return 0; } #endif ntl-6.2.1/src/lip.c000644 000765 000024 00000000157 12377144456 014355 0ustar00shoupstaff000000 000000 #include #ifdef NTL_GMP_LIP #include "g_lip_impl.h" #else #include "c_lip_impl.h" #endif ntl-6.2.1/src/lzz_p.c000644 000765 000024 00000012753 12377144456 014734 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL zz_pInfoT *Build_zz_pInfo(FFTPrimeInfo *info) { return NTL_NEW_OP zz_pInfoT(INIT_FFT, info); } zz_pInfoT::zz_pInfoT(long NewP, long maxroot) { ref_count = 1; if (maxroot < 0) Error("zz_pContext: maxroot may not be negative"); if (NewP <= 1) Error("zz_pContext: p must be > 1"); if (NumBits(NewP) > NTL_SP_NBITS) Error("zz_pContext: modulus too big"); ZZ P, B, M, M1, MinusM; long n, i; long q, t; p = NewP; pinv = 1/double(p); p_info = 0; p_own = 0; conv(P, p); sqr(B, P); LeftShift(B, B, maxroot+NTL_FFTFudge); set(M); n = 0; while (M <= B) { UseFFTPrime(n); q = FFTPrime[n]; n++; mul(M, M, q); } if (n > 4) Error("zz_pInit: too many primes"); NumPrimes = n; PrimeCnt = n; MaxRoot = CalcMaxRoot(q); if (maxroot < MaxRoot) MaxRoot = maxroot; negate(MinusM, M); MinusMModP = rem(MinusM, p); if (!(CoeffModP = (long *) NTL_MALLOC(n, sizeof(long), 0))) Error("out of space"); if (!(x = (double *) NTL_MALLOC(n, sizeof(double), 0))) Error("out of space"); if (!(u = (long *) NTL_MALLOC(n, sizeof(long), 0))) Error("out of space"); for (i = 0; i < n; i++) { q = FFTPrime[i]; div(M1, M, q); t = rem(M1, q); t = InvMod(t, q); if (NTL_zz_p_QUICK_CRT) mul(M1, M1, t); CoeffModP[i] = rem(M1, p); x[i] = ((double) t)/((double) q); u[i] = t; } } zz_pInfoT::zz_pInfoT(INIT_FFT_TYPE, FFTPrimeInfo *info) { ref_count = 1; p = info->q; pinv = info->qinv; p_info = info; p_own = 0; NumPrimes = 1; PrimeCnt = 0; MaxRoot = CalcMaxRoot(p); } zz_pInfoT::zz_pInfoT(INIT_USER_FFT_TYPE, long q) { ref_count = 1; long w; if (!IsFFTPrime(q, w)) Error("invalid user supplied prime"); p = q; pinv = 1/((double) q); p_info = NTL_NEW_OP FFTPrimeInfo(); if (!p_info) Error("out of memory"); long bigtab = 0; #ifdef NTL_FFT_BIGTAB bigtab = 1; #endif InitFFTPrimeInfo(*p_info, q, w, bigtab); p_own = 1; NumPrimes = 1; PrimeCnt = 0; MaxRoot = CalcMaxRoot(p); } zz_pInfoT::~zz_pInfoT() { if (!p_info) { free(CoeffModP); free(x); free(u); } else { if (p_own) delete p_info; } } NTL_THREAD_LOCAL zz_pInfoT *zz_pInfo = 0; typedef zz_pInfoT *zz_pInfoPtr; static void CopyPointer(zz_pInfoPtr& dst, zz_pInfoPtr src) { if (src == dst) return; if (dst) { dst->ref_count--; if (dst->ref_count < 0) Error("internal error: negative zz_pContext ref_count"); if (dst->ref_count == 0) delete dst; } if (src) { if (src->ref_count == NTL_MAX_LONG) Error("internal error: zz_pContext ref_count overflow"); src->ref_count++; } dst = src; } void zz_p::init(long p, long maxroot) { zz_pContext c(p, maxroot); c.restore(); } void zz_p::FFTInit(long index) { zz_pContext c(INIT_FFT, index); c.restore(); } void zz_p::UserFFTInit(long q) { zz_pContext c(INIT_USER_FFT, q); c.restore(); } zz_pContext::zz_pContext(long p, long maxroot) { ptr = NTL_NEW_OP zz_pInfoT(p, maxroot); } // FIXME: maybe store FFT contexts in a global table, // so we don't go through the trouble of creating and destroying // them so much // FIXME: in a thread-safe impl: with my idea for having // thread local copies of certain FFT tables (and NumFFTPrimes) // I have to be careful when installing a "foreign" zz_pContext // -- and for that matter, a "foreign" ZZ_pContext -- from // another thread. The issue is that the foreign thread may // have seen more FFTPrimes. So I'll need to perform // a special check, and if necessary, refresh the local // view of the FFT tables. zz_pContext::zz_pContext(INIT_FFT_TYPE, long index) { if (index < 0) Error("bad FFT prime index"); // allows non-consecutive indices...I'm not sure why while (NumFFTPrimes < index) UseFFTPrime(NumFFTPrimes); UseFFTPrime(index); ptr = 0; CopyPointer(ptr, FFTTables[index]->zz_p_context); } zz_pContext::zz_pContext(INIT_USER_FFT_TYPE, long q) { ptr = NTL_NEW_OP zz_pInfoT(INIT_USER_FFT, q); } zz_pContext::zz_pContext(const zz_pContext& a) { ptr = 0; CopyPointer(ptr, a.ptr); } zz_pContext& zz_pContext::operator=(const zz_pContext& a) { CopyPointer(ptr, a.ptr); return *this; } zz_pContext::~zz_pContext() { CopyPointer(ptr, 0); } void zz_pContext::save() { CopyPointer(ptr, zz_pInfo); } void zz_pContext::restore() const { CopyPointer(zz_pInfo, ptr); } zz_pBak::~zz_pBak() { if (MustRestore) CopyPointer(zz_pInfo, ptr); CopyPointer(ptr, 0); } void zz_pBak::save() { MustRestore = 1; CopyPointer(ptr, zz_pInfo); } void zz_pBak::restore() { MustRestore = 0; CopyPointer(zz_pInfo, ptr); } static inline long reduce(long a, long p) { if (a >= 0 && a < p) return a; else { a = a % p; if (a < 0) a += p; return a; } } zz_p to_zz_p(long a) { return zz_p(reduce(a, zz_p::modulus()), INIT_LOOP_HOLE); } void conv(zz_p& x, long a) { x._zz_p__rep = reduce(a, zz_p::modulus()); } zz_p to_zz_p(const ZZ& a) { return zz_p(rem(a, zz_p::modulus()), INIT_LOOP_HOLE); } void conv(zz_p& x, const ZZ& a) { x._zz_p__rep = rem(a, zz_p::modulus()); } istream& operator>>(istream& s, zz_p& x) { NTL_ZZRegister(y); s >> y; conv(x, y); return s; } ostream& operator<<(ostream& s, zz_p a) { NTL_ZZRegister(y); y = rep(a); s << y; return s; } NTL_END_IMPL ntl-6.2.1/src/lzz_pE.c000644 000765 000024 00000005446 12377144456 015042 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL zz_pEInfoT::zz_pEInfoT(const zz_pX& NewP) { ref_count = 1; build(p, NewP); _card_init = 0; _card_base = zz_p::modulus(); _card_exp = deg(NewP); } const ZZ& zz_pE::cardinality() { if (!zz_pEInfo) Error("zz_pE::cardinality: undefined modulus"); // FIXME: in a thread-safe impl, we need some kind of mutex here if (!zz_pEInfo->_card_init) { power(zz_pEInfo->_card, zz_pEInfo->_card_base, zz_pEInfo->_card_exp); zz_pEInfo->_card_init = 1; } return zz_pEInfo->_card; } NTL_THREAD_LOCAL zz_pEInfoT *zz_pEInfo = 0; // FIXME: in a thread-safe impl, we need to use shared_ptr's typedef zz_pEInfoT *zz_pEInfoPtr; static void CopyPointer(zz_pEInfoPtr& dst, zz_pEInfoPtr src) { if (src == dst) return; if (dst) { dst->ref_count--; if (dst->ref_count < 0) Error("internal error: negative zz_pEContext ref_count"); if (dst->ref_count == 0) delete dst; } if (src) { if (src->ref_count == NTL_MAX_LONG) Error("internal error: zz_pEContext ref_count overflow"); src->ref_count++; } dst = src; } void zz_pE::init(const zz_pX& p) { zz_pEContext c(p); c.restore(); } zz_pEContext::zz_pEContext(const zz_pX& p) { ptr = NTL_NEW_OP zz_pEInfoT(p); } zz_pEContext::zz_pEContext(const zz_pEContext& a) { ptr = 0; CopyPointer(ptr, a.ptr); } zz_pEContext& zz_pEContext::operator=(const zz_pEContext& a) { CopyPointer(ptr, a.ptr); return *this; } zz_pEContext::~zz_pEContext() { CopyPointer(ptr, 0); } void zz_pEContext::save() { CopyPointer(ptr, zz_pEInfo); } void zz_pEContext::restore() const { CopyPointer(zz_pEInfo, ptr); } zz_pEBak::~zz_pEBak() { if (MustRestore) CopyPointer(zz_pEInfo, ptr); CopyPointer(ptr, 0); } void zz_pEBak::save() { MustRestore = 1; CopyPointer(ptr, zz_pEInfo); } void zz_pEBak::restore() { MustRestore = 0; CopyPointer(zz_pEInfo, ptr); } const zz_pE& zz_pE::zero() { NTL_THREAD_LOCAL static zz_pE z(INIT_NO_ALLOC); return z; } istream& operator>>(istream& s, zz_pE& x) { zz_pX y; s >> y; conv(x, y); return s; } void div(zz_pE& x, const zz_pE& a, const zz_pE& b) { zz_pE t; inv(t, b); mul(x, a, t); } void div(zz_pE& x, const zz_pE& a, long b) { NTL_zz_pRegister(B); B = b; inv(B, B); mul(x, a, B); } void div(zz_pE& x, const zz_pE& a, const zz_p& b) { NTL_zz_pRegister(B); B = b; inv(B, B); mul(x, a, B); } void div(zz_pE& x, long a, const zz_pE& b) { zz_pE t; inv(t, b); mul(x, a, t); } void div(zz_pE& x, const zz_p& a, const zz_pE& b) { zz_pE t; inv(t, b); mul(x, a, t); } void inv(zz_pE& x, const zz_pE& a) { InvMod(x._zz_pE__rep, a._zz_pE__rep, zz_pE::modulus()); } NTL_END_IMPL ntl-6.2.1/src/lzz_pEX.c000644 000765 000024 00000163665 12377144456 015202 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL const zz_pEX& zz_pEX::zero() { NTL_THREAD_LOCAL static zz_pEX z; return z; } istream& operator>>(istream& s, zz_pEX& x) { s >> x.rep; x.normalize(); return s; } ostream& operator<<(ostream& s, const zz_pEX& a) { return s << a.rep; } void zz_pEX::normalize() { long n; const zz_pE* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const zz_pEX& a) { return a.rep.length() == 0; } long IsOne(const zz_pEX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } long operator==(const zz_pEX& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); long da = deg(a); if (da > 0) return 0; NTL_zz_pRegister(bb); bb = b; if (da < 0) return IsZero(bb); return a.rep[0] == bb; } long operator==(const zz_pEX& a, const zz_p& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } long operator==(const zz_pEX& a, const zz_pE& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } void SetCoeff(zz_pEX& x, long i, const zz_pE& a) { long j, m; if (i < 0) Error("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { zz_pE aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(zz_pEX& x, long i, const zz_p& aa) { long j, m; if (i < 0) Error("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); NTL_zz_pRegister(a); // watch out for aliases! a = aa; m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } x.rep[i] = a; x.normalize(); } void SetCoeff(zz_pEX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else { NTL_zz_pRegister(T); T = a; SetCoeff(x, i, T); } } void SetCoeff(zz_pEX& x, long i) { long j, m; if (i < 0) Error("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(zz_pEX& x) { clear(x); SetCoeff(x, 1); } long IsX(const zz_pEX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const zz_pE& coeff(const zz_pEX& a, long i) { if (i < 0 || i > deg(a)) return zz_pE::zero(); else return a.rep[i]; } const zz_pE& LeadCoeff(const zz_pEX& a) { if (IsZero(a)) return zz_pE::zero(); else return a.rep[deg(a)]; } const zz_pE& ConstTerm(const zz_pEX& a) { if (IsZero(a)) return zz_pE::zero(); else return a.rep[0]; } void conv(zz_pEX& x, const zz_pE& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(zz_pEX& x, long a) { if (a == 0) clear(x); else if (a == 1) set(x); else { NTL_zz_pRegister(T); T = a; conv(x, T); } } void conv(zz_pEX& x, const ZZ& a) { NTL_zz_pRegister(T); conv(T, a); conv(x, T); } void conv(zz_pEX& x, const zz_p& a) { if (IsZero(a)) clear(x); else if (IsOne(a)) set(x); else { x.rep.SetLength(1); conv(x.rep[0], a); x.normalize(); } } void conv(zz_pEX& x, const zz_pX& aa) { zz_pX a = aa; // in case a aliases the rep of a coefficient of x long n = deg(a)+1; long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], coeff(a, i)); } void conv(zz_pEX& x, const vec_zz_pE& a) { x.rep = a; x.normalize(); } /* additional legacy conversions for v6 conversion regime */ void conv(zz_pEX& x, const ZZX& a) { long n = a.rep.length(); long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], a.rep[i]); x.normalize(); } /* ------------------------------------- */ void add(zz_pEX& x, const zz_pEX& a, const zz_pEX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const zz_pE *ap, *bp; zz_pE* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(zz_pEX& x, const zz_pEX& a, const zz_pE& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(zz_pEX& x, const zz_pEX& a, const zz_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(zz_pEX& x, const zz_pEX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(zz_pEX& x, const zz_pEX& a, const zz_pEX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const zz_pE *ap, *bp; zz_pE* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(zz_pEX& x, const zz_pEX& a, const zz_pE& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(zz_pEX& x, const zz_pEX& a, const zz_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(zz_pEX& x, const zz_pEX& a, long b) { if (a.rep.length() == 0) { conv(x, b); negate(x, x); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(zz_pEX& x, const zz_pE& b, const zz_pEX& a) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (x.rep.MaxLength() == 0) { negate(x, a); add(x.rep[0], x.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); sub(xp[0], b, a.rep[0]); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) negate(xp[i], ap[i]); x.normalize(); } } void sub(zz_pEX& x, const zz_p& a, const zz_pEX& b) { NTL_zz_pRegister(T); // avoids aliasing problems T = a; negate(x, b); add(x, x, T); } void sub(zz_pEX& x, long a, const zz_pEX& b) { NTL_zz_pRegister(T); T = a; negate(x, b); add(x, x, T); } void mul(zz_pEX& c, const zz_pEX& a, const zz_pEX& b) { if (&a == &b) { sqr(c, a); return; } if (IsZero(a) || IsZero(b)) { clear(c); return; } if (deg(a) == 0) { mul(c, b, ConstTerm(a)); return; } if (deg(b) == 0) { mul(c, a, ConstTerm(b)); return; } // general case...Kronecker subst zz_pX A, B, C; long da = deg(a); long db = deg(b); long n = zz_pE::degree(); long n2 = 2*n-1; if (NTL_OVERFLOW(da+db+1, n2, 0)) Error("overflow in zz_pEX mul"); long i, j; A.rep.SetLength((da+1)*n2); for (i = 0; i <= da; i++) { const zz_pX& coeff = rep(a.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) A.rep[n2*i + j] = coeff.rep[j]; } A.normalize(); B.rep.SetLength((db+1)*n2); for (i = 0; i <= db; i++) { const zz_pX& coeff = rep(b.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) B.rep[n2*i + j] = coeff.rep[j]; } B.normalize(); mul(C, A, B); long Clen = C.rep.length(); long lc = (Clen + n2 - 1)/n2; long dc = lc - 1; c.rep.SetLength(dc+1); zz_pX tmp; for (i = 0; i <= dc; i++) { tmp.rep.SetLength(n2); for (j = 0; j < n2 && n2*i + j < Clen; j++) tmp.rep[j] = C.rep[n2*i + j]; for (; j < n2; j++) clear(tmp.rep[j]); tmp.normalize(); conv(c.rep[i], tmp); } c.normalize(); } void mul(zz_pEX& x, const zz_pEX& a, const zz_pE& b) { if (IsZero(b)) { clear(x); return; } zz_pE t; t = b; long i, da; const zz_pE *ap; zz_pE* xp; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(zz_pEX& x, const zz_pEX& a, const zz_p& b) { if (IsZero(b)) { clear(x); return; } NTL_zz_pRegister(t); t = b; long i, da; const zz_pE *ap; zz_pE* xp; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(zz_pEX& x, const zz_pEX& a, long b) { NTL_zz_pRegister(t); t = b; mul(x, a, t); } void sqr(zz_pEX& c, const zz_pEX& a) { if (IsZero(a)) { clear(c); return; } if (deg(a) == 0) { zz_pE res; sqr(res, ConstTerm(a)); conv(c, res); return; } // general case...Kronecker subst zz_pX A, C; long da = deg(a); long n = zz_pE::degree(); long n2 = 2*n-1; if (NTL_OVERFLOW(2*da+1, n2, 0)) Error("overflow in zz_pEX sqr"); long i, j; A.rep.SetLength((da+1)*n2); for (i = 0; i <= da; i++) { const zz_pX& coeff = rep(a.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) A.rep[n2*i + j] = coeff.rep[j]; } A.normalize(); sqr(C, A); long Clen = C.rep.length(); long lc = (Clen + n2 - 1)/n2; long dc = lc - 1; c.rep.SetLength(dc+1); zz_pX tmp; for (i = 0; i <= dc; i++) { tmp.rep.SetLength(n2); for (j = 0; j < n2 && n2*i + j < Clen; j++) tmp.rep[j] = C.rep[n2*i + j]; for (; j < n2; j++) clear(tmp.rep[j]); tmp.normalize(); conv(c.rep[i], tmp); } c.normalize(); } void MulTrunc(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, long n) { if (n < 0) Error("MulTrunc: bad args"); zz_pEX t; mul(t, a, b); trunc(x, t, n); } void SqrTrunc(zz_pEX& x, const zz_pEX& a, long n) { if (n < 0) Error("SqrTrunc: bad args"); zz_pEX t; sqr(t, a); trunc(x, t, n); } void CopyReverse(zz_pEX& x, const zz_pEX& a, long hi) // x[0..hi] = reverse(a[0..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi+1; m = a.rep.length(); x.rep.SetLength(n); const zz_pE* ap = a.rep.elts(); zz_pE* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void trunc(zz_pEX& x, const zz_pEX& a, long m) // x = a % X^m, output may alias input { if (m < 0) Error("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; zz_pE* xp; const zz_pE* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void random(zz_pEX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void negate(zz_pEX& x, const zz_pEX& a) { long n = a.rep.length(); x.rep.SetLength(n); const zz_pE* ap = a.rep.elts(); zz_pE* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } static void MulByXModAux(zz_pEX& h, const zz_pEX& a, const zz_pEX& f) { long i, n, m; zz_pE* hh; const zz_pE *aa, *ff; zz_pE t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) Error("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(zz_pEX& h, const zz_pEX& a, const zz_pEX& f) { if (&h == &f) { zz_pEX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void PlainMul(zz_pEX& x, const zz_pEX& a, const zz_pEX& b) { long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } long d = da+db; const zz_pE *ap, *bp; zz_pE *xp; zz_pEX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; zz_pX t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(bp[i-j])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void SetSize(vec_zz_pX& x, long n, long m) { x.SetLength(n); long i; for (i = 0; i < n; i++) x[i].rep.SetMaxLength(m); } void PlainDivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pE *qp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) Error("zz_pEX: division by zero"); if (da < db) { r = a; clear(q); return; } zz_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_pX x; SetSize(x, da+1, 2*zz_pE::degree()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainRem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b, vec_zz_pX& x) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) Error("zz_pEX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b, vec_zz_pX& x) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pE *qp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) Error("zz_pEX: division by zero"); if (da < db) { r = a; clear(q); return; } zz_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDiv(zz_pEX& q, const zz_pEX& a, const zz_pEX& b) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pE *qp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) Error("zz_pEX: division by zero"); if (da < db) { clear(q); return; } zz_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_pX x; SetSize(x, da+1-db, 2*zz_pE::degree()); for (i = db; i <= da; i++) x[i-db] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j-db], xp[i+j-db], s); } } } void PlainRem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) Error("zz_pEX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_pX x; SetSize(x, da + 1, 2*zz_pE::degree()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void RightShift(zz_pEX& x, const zz_pEX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) Error("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(zz_pEX& x, const zz_pEX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void NewtonInv(zz_pEX& c, const zz_pEX& a, long e) { zz_pE x; inv(x, ConstTerm(a)); if (e == 1) { conv(c, x); return; } vec_long E; E.SetLength(0); append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long L = E.length(); zz_pEX g, g0, g1, g2; g.rep.SetMaxLength(E[0]); g0.rep.SetMaxLength(E[0]); g1.rep.SetMaxLength((3*E[0]+1)/2); g2.rep.SetMaxLength(E[0]); conv(g, x); long i; for (i = L-1; i > 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); sub(g, g, g2); } c = g; } void InvTrunc(zz_pEX& c, const zz_pEX& a, long e) { if (e < 0) Error("InvTrunc: bad args"); if (e == 0) { clear(c); return; } if (NTL_OVERFLOW(e, 1, 0)) Error("overflow in InvTrunc"); NewtonInv(c, a, e); } const long zz_pEX_MOD_PLAIN = 0; const long zz_pEX_MOD_MUL = 1; void build(zz_pEXModulus& F, const zz_pEX& f) { long n = deg(f); if (n <= 0) Error("build(zz_pEXModulus,zz_pEX): deg(f) <= 0"); if (NTL_OVERFLOW(n, zz_pE::degree(), 0)) Error("build(zz_pEXModulus,zz_pEX): overflow"); F.tracevec.SetLength(0); F.f = f; F.n = n; if (F.n < zz_pE::ModCross()) { F.method = zz_pEX_MOD_PLAIN; } else { F.method = zz_pEX_MOD_MUL; zz_pEX P1; zz_pEX P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); trunc(F.f0, f, n); F.hlc = ConstTerm(P2); } } zz_pEXModulus::zz_pEXModulus() { n = -1; method = zz_pEX_MOD_PLAIN; } zz_pEXModulus::~zz_pEXModulus() { } zz_pEXModulus::zz_pEXModulus(const zz_pEX& ff) { n = -1; method = zz_pEX_MOD_PLAIN; build(*this, ff); } void UseMulRem21(zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX P1; zz_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); sub(r, r, P1); } void UseMulDivRem21(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX P1; zz_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); sub(r, r, P1); q = P2; } void UseMulDiv21(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX P1; zz_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); q = P2; } void rem(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F) { if (F.method == zz_pEX_MOD_PLAIN) { PlainRem(x, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulRem21(x, a, F); return; } zz_pEX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulRem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F) { if (F.method == zz_pEX_MOD_PLAIN) { PlainDivRem(q, r, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDivRem21(q, r, a, F); return; } zz_pEX buf(INIT_SIZE, 2*n-1); zz_pEX qbuf(INIT_SIZE, n-1); zz_pEX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulDivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F) { if (F.method == zz_pEX_MOD_PLAIN) { PlainDiv(q, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDiv21(q, a, F); return; } zz_pEX buf(INIT_SIZE, 2*n-1); zz_pEX qbuf(INIT_SIZE, n-1); zz_pEX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) UseMulDivRem21(qbuf, buf, buf, F); else UseMulDiv21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(zz_pEX& c, const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F) { if (deg(a) >= F.n || deg(b) >= F.n) Error("MulMod: bad args"); zz_pEX t; mul(t, a, b); rem(c, t, F); } void SqrMod(zz_pEX& c, const zz_pEX& a, const zz_pEXModulus& F) { if (deg(a) >= F.n) Error("MulMod: bad args"); zz_pEX t; sqr(t, a); rem(c, t, F); } void UseMulRem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { zz_pEX P1; zz_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); sub(P1, a, P1); r = P1; } void UseMulDivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { zz_pEX P1; zz_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); sub(P1, a, P1); r = P1; q = P2; } void UseMulDiv(zz_pEX& q, const zz_pEX& a, const zz_pEX& b) { zz_pEX P1; zz_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); q = P2; } void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < zz_pE::DivCross() || sa-sb < zz_pE::DivCross()) PlainDivRem(q, r, a, b); else if (sa < 4*sb) UseMulDivRem(q, r, a, b); else { zz_pEXModulus B; build(B, b); DivRem(q, r, a, B); } } void div(zz_pEX& q, const zz_pEX& a, const zz_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < zz_pE::DivCross() || sa-sb < zz_pE::DivCross()) PlainDiv(q, a, b); else if (sa < 4*sb) UseMulDiv(q, a, b); else { zz_pEXModulus B; build(B, b); div(q, a, B); } } void div(zz_pEX& q, const zz_pEX& a, const zz_pE& b) { zz_pE T; inv(T, b); mul(q, a, T); } void div(zz_pEX& q, const zz_pEX& a, const zz_p& b) { NTL_zz_pRegister(T); inv(T, b); mul(q, a, T); } void div(zz_pEX& q, const zz_pEX& a, long b) { NTL_zz_pRegister(T); T = b; inv(T, T); mul(q, a, T); } void rem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < zz_pE::DivCross() || sa-sb < zz_pE::DivCross()) PlainRem(r, a, b); else if (sa < 4*sb) UseMulRem(r, a, b); else { zz_pEXModulus B; build(B, b); rem(r, a, B); } } void GCD(zz_pEX& x, const zz_pEX& a, const zz_pEX& b) { zz_pE t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; zz_pEX u(INIT_SIZE, n), v(INIT_SIZE, n); vec_zz_pX tmp; SetSize(tmp, n, 2*zz_pE::degree()); u = a; v = b; do { PlainRem(u, u, v, tmp); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } void XGCD(zz_pEX& d, zz_pEX& s, zz_pEX& t, const zz_pEX& a, const zz_pEX& b) { zz_pE z; if (IsZero(b)) { set(s); clear(t); d = a; } else if (IsZero(a)) { clear(s); set(t); d = b; } else { long e = max(deg(a), deg(b)) + 1; zz_pEX temp(INIT_SIZE, e), u(INIT_SIZE, e), v(INIT_SIZE, e), u0(INIT_SIZE, e), v0(INIT_SIZE, e), u1(INIT_SIZE, e), v1(INIT_SIZE, e), u2(INIT_SIZE, e), v2(INIT_SIZE, e), q(INIT_SIZE, e); set(u1); clear(v1); clear(u2); set(v2); u = a; v = b; do { DivRem(q, u, u, v); swap(u, v); u0 = u2; v0 = v2; mul(temp, q, u2); sub(u2, u1, temp); mul(temp, q, v2); sub(v2, v1, temp); u1 = u0; v1 = v0; } while (!IsZero(v)); d = u; s = u1; t = v1; } if (IsZero(d)) return; if (IsOne(LeadCoeff(d))) return; /* make gcd monic */ inv(z, LeadCoeff(d)); mul(d, d, z); mul(s, s, z); mul(t, t, z); } void IterBuild(zz_pE* a, long n) { long i, k; zz_pE b, t; if (n <= 0) return; negate(a[0], a[0]); for (k = 1; k <= n-1; k++) { negate(b, a[k]); add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void BuildFromRoots(zz_pEX& x, const vec_zz_pE& a) { long n = a.length(); if (n == 0) { set(x); return; } x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); } void eval(zz_pE& b, const zz_pEX& f, const zz_pE& a) // does a Horner evaluation { zz_pE acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_zz_pE& b, const zz_pEX& f, const vec_zz_pE& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_zz_pE bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(zz_pEX& f, const vec_zz_pE& a, const vec_zz_pE& b) { long m = a.length(); if (b.length() != m) Error("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_zz_pE prod; prod = a; zz_pE t1, t2; long k, i; vec_zz_pE res; res.SetLength(m); for (k = 0; k < m; k++) { const zz_pE& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(zz_pEX& x, const vec_zz_pE& v, long low, long high, const vec_zz_pEX& H, long n, vec_zz_pX& t) { zz_pX s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_zz_pE& h = H[i-low].rep; long m = h.length(); const zz_pX& w = rep(v[i]); for (j = 0; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) conv(x.rep[j], t[j]); x.normalize(); } void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEXArgument& A, const zz_pEXModulus& F) { if (deg(g) <= 0) { x = g; return; } zz_pEX s, t; vec_zz_pX scratch; SetSize(scratch, deg(F), 2*zz_pE::degree()); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const zz_pEX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(zz_pEXArgument& A, const zz_pEX& h, const zz_pEXModulus& F, long m) { long i; if (m <= 0 || deg(h) >= F.n) Error("build: bad args"); if (m > F.n) m = F.n; if (zz_pEXArgBound > 0) { double sz = zz_p::storage(); sz = sz*zz_pE::degree(); sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_zz_p); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_zz_pE); sz = sz/1024; m = min(m, long(zz_pEXArgBound/sz)); m = max(m, 1); } A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], h, F); } NTL_THREAD_LOCAL long zz_pEXArgBound = 0; void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } zz_pEXArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(zz_pEX& x1, zz_pEX& x2, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& h, const zz_pEXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } zz_pEXArgument A; build(A, h, F, m); zz_pEX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(zz_pEX& x1, zz_pEX& x2, zz_pEX& x3, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& g3, const zz_pEX& h, const zz_pEXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } zz_pEXArgument A; build(A, h, F, m); zz_pEX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } void build(zz_pEXTransMultiplier& B, const zz_pEX& b, const zz_pEXModulus& F) { long db = deg(b); if (db >= F.n) Error("build TransMultiplier: bad args"); zz_pEX t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, d); // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, d); if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, db); } void TransMulMod(zz_pEX& x, const zz_pEX& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F) { if (deg(a) >= F.n) Error("TransMulMod: bad args"); zz_pEX t1, t2; mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); LeftShift(t2, t2, 1); sub(x, t1, t2); } void ShiftSub(zz_pEX& U, const zz_pEX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void UpdateMap(vec_zz_pE& x, const vec_zz_pE& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F) { zz_pEX xx; TransMulMod(xx, to_zz_pEX(a), B, F); x = xx.rep; } static void ProjectPowers(vec_zz_pE& x, const zz_pEX& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F) { if (k < 0 || NTL_OVERFLOW(k, 1, 0) || deg(a) >= F.n) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; zz_pEXTransMultiplier M; build(M, H.H[m], F); zz_pEX s; s = a; x.SetLength(k); long i; for (i = 0; i <= l; i++) { long m1 = min(m, k-i*m); for (long j = 0; j < m1; j++) InnerProduct(x[i*m+j], H.H[j].rep, s.rep); if (i < l) TransMulMod(s, s, M, F); } } static void ProjectPowers(vec_zz_pE& x, const zz_pEX& a, long k, const zz_pEX& h, const zz_pEXModulus& F) { if (k < 0 || deg(a) >= F.n || deg(h) >= F.n) Error("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0);; return; } long m = SqrRoot(k); zz_pEXArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F) { ProjectPowers(x, to_zz_pEX(a), k, H, F); } void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F) { ProjectPowers(x, to_zz_pEX(a), k, h, F); } void BerlekampMassey(zz_pEX& h, const vec_zz_pE& a, long m) { zz_pEX Lambda, Sigma, Temp; long L; zz_pE Delta, Delta1, t1; long shamt; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(Delta1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(t1, Lambda.rep[i], a[r-i-1]); add(Delta1, Delta1, t1); } if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftSub(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftSub(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void MinPolySeq(zz_pEX& h, const vec_zz_pE& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) Error("MinPoly: bad args"); if (a.length() < 2*m) Error("MinPoly: sequence too short"); BerlekampMassey(h, a, m); } void DoMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m, const zz_pEX& R) { vec_zz_pE x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) Error("ProbMinPoly: bad args"); zz_pEX R; random(R, n); DoMinPolyMod(h, g, F, m, R); } void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } void MinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pEX h, h1; long n = F.n; if (m < 1 || m > n) Error("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ zz_pEX h2, h3; zz_pEX R; zz_pEXTransMultiplier H1; for (;;) { random(R, n); build(H1, h1, F); TransMulMod(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m) { if (m < 1 || m > F.n) Error("IrredPoly: bad args"); zz_pEX R; set(R); DoMinPolyMod(h, g, F, m, R); } void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F) { IrredPolyMod(h, g, F, F.n); } void MinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F) { MinPolyMod(hh, g, F, F.n); } void diff(zz_pEX& x, const zz_pEX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void MakeMonic(zz_pEX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; zz_pE t; inv(t, LeadCoeff(x)); mul(x, x, t); } long divide(zz_pEX& q, const zz_pEX& a, const zz_pEX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } zz_pEX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const zz_pEX& a, const zz_pEX& b) { if (IsZero(b)) return IsZero(a); zz_pEX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } static long OptWinSize(long n) // finds k that minimizes n/(k+1) + 2^{k-1} { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/(double(k+2)) + double(1L << k); if (v_new >= v) break; v = v_new; k++; } return k; } void PowerMod(zz_pEX& h, const zz_pEX& g, const ZZ& e, const zz_pEXModulus& F) // h = g^e mod f using "sliding window" algorithm { if (deg(g) >= F.n) Error("PowerMod: bad args"); if (e == 0) { set(h); return; } if (e == 1) { h = g; return; } if (e == -1) { InvMod(h, g, F); return; } if (e == 2) { SqrMod(h, g, F); return; } if (e == -2) { SqrMod(h, g, F); InvMod(h, h, F); return; } long n = NumBits(e); zz_pEX res; res.SetMaxLength(F.n); set(res); long i; if (n < 16) { // plain square-and-multiply algorithm for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, g, F); } if (e < 0) InvMod(res, res, F); h = res; return; } long k = OptWinSize(n); k = min(k, 3); vec_zz_pEX v; v.SetLength(1L << (k-1)); v[0] = g; if (k > 1) { zz_pEX t; SqrMod(t, g, F); for (i = 1; i < (1L << (k-1)); i++) MulMod(v[i], v[i-1], t, F); } long val; long cnt; long m; val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | bit(e, i); if (val == 0) SqrMod(res, res, F); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { SqrMod(res, res, F); m = m >> 1; } MulMod(res, res, v[val >> 1], F); while (cnt > 0) { SqrMod(res, res, F); cnt--; } val = 0; } } if (e < 0) InvMod(res, res, F); h = res; } void InvMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvMod: bad args"); zz_pEX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) Error("zz_pEX InvMod: can't compute multiplicative inverse"); } long InvModStatus(zz_pEX& x, const zz_pEX& a, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvModStatus: bad args"); zz_pEX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) Error("MulMod: bad args"); zz_pEX t; mul(t, a, b); rem(x, t, f); } void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("SqrMod: bad args"); zz_pEX t; sqr(t, a); rem(x, t, f); } void PowerXMod(zz_pEX& hh, const ZZ& e, const zz_pEXModulus& F) { if (F.n < 0) Error("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; zz_pEX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) MulByXMod(h, h, F.f); } if (e < 0) InvMod(h, h, F); hh = h; } void reverse(zz_pEX& x, const zz_pEX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) Error("overflow in reverse"); if (&x == &a) { zz_pEX tmp; CopyReverse(tmp, a, hi); x = tmp; } else CopyReverse(x, a, hi); } void power(zz_pEX& x, const zz_pEX& a, long e) { if (e < 0) { Error("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) Error("overflow in power"); zz_pEX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } static void FastTraceVec(vec_zz_pE& S, const zz_pEXModulus& f) { long n = deg(f); zz_pEX x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); S.SetLength(n); S[0] = n; long i; for (i = 1; i < n; i++) S[i] = coeff(x, i); } void PlainTraceVec(vec_zz_pE& S, const zz_pEX& ff) { if (deg(ff) <= 0) Error("TraceVec: bad args"); zz_pEX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; zz_pX acc, t; zz_pE t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } } void TraceVec(vec_zz_pE& S, const zz_pEX& f) { if (deg(f) < zz_pE::DivCross()) PlainTraceVec(S, f); else FastTraceVec(S, f); } static void ComputeTraceVec(const zz_pEXModulus& F) { vec_zz_pE& S = *((vec_zz_pE *) &F.tracevec); if (S.length() > 0) return; if (F.method == zz_pEX_MOD_PLAIN) { PlainTraceVec(S, F.f); } else { FastTraceVec(S, F); } } void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEXModulus& F) { long n = F.n; if (deg(a) >= n) Error("trace: bad args"); // FIXME: in a thread-safe impl, we need some kind of mutex here if (F.tracevec.length() == 0) ComputeTraceVec(F); InnerProduct(x, a.rep, F.tracevec); } void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) Error("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(zz_pE& rres, const zz_pEX& a, const zz_pEX& b) { zz_pE res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; zz_pE lc; set(res); long n = max(deg(a),deg(b)) + 1; zz_pEX u(INIT_SIZE, n), v(INIT_SIZE, n); vec_zz_pX tmp; SetSize(tmp, n, 2*zz_pE::degree()); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v, tmp); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } } rres = res; } void resultant(zz_pE& rres, const zz_pEX& a, const zz_pEX& b) { PlainResultant(rres, a, b); } void NormMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) Error("norm: bad args"); if (IsZero(a)) { clear(x); return; } zz_pE t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { zz_pE t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } // tower stuff... void InnerProduct(zz_pEX& x, const vec_zz_p& v, long low, long high, const vec_zz_pEX& H, long n, vec_zz_pE& t) { zz_pE s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_zz_pE& h = H[i-low].rep; long m = h.length(); const zz_p& w = v[i]; for (j = 0; j < m; j++) { mul(s, h[j], w); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) x.rep[j] = t[j]; x.normalize(); } void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEXArgument& A, const zz_pEXModulus& F) { if (deg(g) <= 0) { conv(x, g); return; } zz_pEX s, t; vec_zz_pE scratch; scratch.SetLength(deg(F)); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const zz_pEX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } zz_pEXArgument A; build(A, h, F, m); CompTower(x, g, A, F); } void PrepareProjection(vec_vec_zz_p& tt, const vec_zz_pE& s, const vec_zz_p& proj) { long l = s.length(); tt.SetLength(l); zz_pXMultiplier M; long i; for (i = 0; i < l; i++) { build(M, rep(s[i]), zz_pE::modulus()); UpdateMap(tt[i], proj, M, zz_pE::modulus()); } } void ProjectedInnerProduct(zz_p& x, const vec_zz_pE& a, const vec_vec_zz_p& b) { long n = min(a.length(), b.length()); zz_p t, res; res = 0; long i; for (i = 0; i < n; i++) { project(t, b[i], rep(a[i])); res += t; } x = res; } void PrecomputeProj(vec_zz_p& proj, const zz_pX& f) { long n = deg(f); if (n <= 0) Error("PrecomputeProj: bad args"); if (ConstTerm(f) != 0) { proj.SetLength(1); proj[0] = 1; } else { proj.SetLength(n); clear(proj); proj[n-1] = 1; } } void ProjectPowersTower(vec_zz_p& x, const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F, const vec_zz_p& proj) { long n = F.n; if (a.length() > n || k < 0 || NTL_OVERFLOW(k, 1, 0)) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; zz_pEXTransMultiplier M; build(M, H.H[m], F); vec_zz_pE s(INIT_SIZE, n); s = a; x.SetLength(k); vec_vec_zz_p tt; for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); zz_p* w = &x[i*m]; PrepareProjection(tt, s, proj); for (long j = 0; j < m1; j++) ProjectedInnerProduct(w[j], H.H[j].rep, tt); if (i < l) UpdateMap(s, s, M, F); } } void ProjectPowersTower(vec_zz_p& x, const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F, const vec_zz_p& proj) { if (a.length() > F.n || k < 0) Error("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); zz_pEXArgument H; build(H, h, F, m); ProjectPowersTower(x, a, k, H, F, proj); } void DoMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m, const vec_zz_pE& R, const vec_zz_p& proj) { vec_zz_p x; ProjectPowersTower(x, R, 2*m, g, F, proj); MinPolySeq(h, x, m); } void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m) { long n = F.n; if (m < 1 || m > n*zz_pE::degree()) Error("ProbMinPoly: bad args"); vec_zz_pE R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); vec_zz_p proj; PrecomputeProj(proj, zz_pE::modulus()); DoMinPolyTower(h, g, F, m, R, proj); } void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m, const vec_zz_p& proj) { long n = F.n; if (m < 1 || m > n*zz_pE::degree()) Error("ProbMinPoly: bad args"); vec_zz_pE R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); DoMinPolyTower(h, g, F, m, R, proj); } void MinPolyTower(zz_pX& hh, const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pX h; zz_pEX h1; long n = F.n; if (m < 1 || m > n*zz_pE::degree()) { Error("MinPoly: bad args"); } vec_zz_p proj; PrecomputeProj(proj, zz_pE::modulus()); /* probabilistically compute min-poly */ ProbMinPolyTower(h, g, F, m, proj); if (deg(h) == m) { hh = h; return; } CompTower(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; zz_pX h2; zz_pEX h3; vec_zz_pE R; zz_pEXTransMultiplier H1; for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyTower(h2, g, F, m-deg(h), R, proj); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompTower(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m) { if (m < 1 || m > deg(F)*zz_pE::degree()) Error("IrredPoly: bad args"); vec_zz_pE R; R.SetLength(1); R[0] = 1; vec_zz_p proj; proj.SetLength(1); proj[0] = 1; DoMinPolyTower(h, g, F, m, R, proj); } NTL_END_IMPL ntl-6.2.1/src/lzz_pEXFactoring.c000644 000765 000024 00000067364 12377144456 017036 0ustar00shoupstaff000000 000000 #include #include #include #include #include NTL_START_IMPL static void IterPower(zz_pE& c, const zz_pE& a, long n) { zz_pE res; long i; res = a; for (i = 0; i < n; i++) power(res, res, zz_p::modulus()); c = res; } void SquareFreeDecomp(vec_pair_zz_pEX_long& u, const zz_pEX& ff) { zz_pEX f = ff; if (!IsOne(LeadCoeff(f))) Error("SquareFreeDecomp: bad args"); zz_pEX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long k, d; long p = to_long(zz_p::modulus()); d = deg(r)/p; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) IterPower(f.rep[k], r.rep[k*p], zz_pE::degree()-1); m = m*p; } } while (!finished); } static void AbsTraceMap(zz_pEX& h, const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX res, tmp; long k = NumBits(zz_pE::cardinality())-1; res = a; tmp = a; long i; for (i = 0; i < k-1; i++) { SqrMod(tmp, tmp, F); add(res, res, tmp); } h = res; } void FrobeniusMap(zz_pEX& h, const zz_pEXModulus& F) { PowerXMod(h, zz_pE::cardinality(), F); } static void RecFindRoots(vec_zz_pE& x, const zz_pEX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } zz_pEX h; zz_pEX r; { zz_pEXModulus F; build(F, f); do { random(r, deg(F)); if (IsOdd(zz_pE::cardinality())) { PowerMod(h, r, RightShift(zz_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_zz_pE& x, const zz_pEX& ff) { zz_pEX f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoots: bad args"); x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } void split(zz_pEX& f1, zz_pEX& g1, zz_pEX& f2, zz_pEX& g2, const zz_pEX& f, const zz_pEX& g, const vec_zz_pE& roots, long lo, long mid) { long r = mid-lo+1; zz_pEXModulus F; build(F, f); vec_zz_pE lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; zz_pEX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } void RecFindFactors(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& g, const vec_zz_pE& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } zz_pEX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } void FindFactors(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& g, const vec_zz_pE& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } void IterFindFactors(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& g, const vec_zz_pE& roots) { long r = roots.length(); long i; zz_pEX h; factors.SetLength(r); for (i = 0; i < r; i++) { sub(h, g, roots[i]); GCD(factors[i], f, h); } } void TraceMap(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& b) { if (d < 0) Error("TraceMap: bad args"); zz_pEX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(zz_pEX& y, const zz_pEX& h, long q, const zz_pEXModulus& F) { if (q < 0) Error("PowerCompose: bad args"); zz_pEX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const zz_pEX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; zz_pEXModulus F; build(F, f); zz_pEX b, r, s; FrobeniusMap(b, F); long all_zero = 1; long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); all_zero = all_zero && IsZero(s); if (deg(s) > 0) return 0; } if (!all_zero || (n & 1)) return 1; PowerCompose(s, b, n/2, F); return !IsX(s); } NTL_THREAD_LOCAL long zz_pEX_BlockingFactor = 10; void RootEDF(vec_zz_pEX& factors, const zz_pEX& f, long verbose) { vec_zz_pE roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); sub(factors[j], factors[j], roots[j]); } } void EDFSplit(vec_zz_pEX& v, const zz_pEX& f, const zz_pEX& b, long d) { zz_pEX a, g, h; zz_pEXModulus F; vec_zz_pE roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } void RecEDF(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& b, long d, long verbose) { vec_zz_pEX v; long i; zz_pEX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { zz_pEX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_zz_pEX& factors, const zz_pEX& ff, const zz_pEX& bb, long d, long verbose) { zz_pEX f = ff; zz_pEX b = bb; if (!IsOne(LeadCoeff(f))) Error("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_zz_pEX& factors, const zz_pEX& ff, long verbose) { zz_pEX f = ff; if (!IsOne(LeadCoeff(f))) Error("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; zz_pEXModulus F; build(F, f); zz_pEX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } FrobeniusMap(h, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_zz_pEX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } zz_pEX hh; vec_zz_pEX v; long i; for (i = 0; i < u.length(); i++) { const zz_pEX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_zz_pEX_long& factors, const zz_pEX& f, long verbose) { if (!IsOne(LeadCoeff(f))) Error("CanZass: bad args"); double t; vec_pair_zz_pEX_long sfd; vec_zz_pEX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(zz_pEX& f, const vec_pair_zz_pEX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); zz_pEX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } long BaseCase(const zz_pEX& h, long q, long a, const zz_pEXModulus& F) { long b, e; zz_pEX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } void TandemPowerCompose(zz_pEX& y1, zz_pEX& y2, const zz_pEX& h, long q1, long q2, const zz_pEXModulus& F) { zz_pEX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } long RecComputeDegree(long u, const zz_pEX& h, const zz_pEXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); zz_pEX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long RecComputeDegree(const zz_pEX& h, const zz_pEXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } void FindRoot(zz_pE& root, const zz_pEX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { zz_pEXModulus F; zz_pEX h, h1, f; zz_pEX r; f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoot: bad args"); if (deg(f) == 0) Error("FindRoot: bad args"); while (deg(f) > 1) { build(F, f); random(r, deg(F)); if (IsOdd(zz_pE::cardinality())) { PowerMod(h, r, RightShift(zz_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const zz_pEX& h, long q, long a, const zz_pEXModulus& F) { long e; zz_pEX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); sub(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const zz_pEX& h, const zz_pEXModulus& F, const FacVec& fvec) { long q1, q2; zz_pEX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const zz_pEX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; zz_pEXModulus F; build(F, f); zz_pEX h; FrobeniusMap(h, F); zz_pEX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const zz_pEX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; zz_pEXModulus F; build(F, f); zz_pEX h; FrobeniusMap(h, F); long CompTableSize = 2*SqrRoot(deg(f)); zz_pEXArgument H; build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; zz_pEX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { sub(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { CompMod(g, g, H, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_zz_pEX& h, const zz_pEX& f, const zz_pEX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { zz_pEX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); sub(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); sub(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(zz_pEX& x, const zz_pEX& f, const zz_pEX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_zz_pEX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_zz_pE a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(zz_pEX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(zz_pEX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { zz_pEX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(zz_pEX& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } #if 0 void BuildIrred(zz_pEX& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (n == 1) { SetX(f); return; } zz_pEX g; do { random(g, n); SetCoeff(g, n); } while (!IterIrredTest(g)); f = g; } #endif void BuildRandomIrred(zz_pEX& f, const zz_pEX& g) { zz_pEXModulus G; zz_pEX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_THREAD_LOCAL long zz_pEX_GCDTableSize = 4; NTL_THREAD_LOCAL char zz_pEX_stem[256] = ""; NTL_THREAD_LOCAL double zz_pEXFileThresh = NTL_FILE_THRESH; NTL_THREAD_LOCAL static vec_zz_pEX BabyStepFile; NTL_THREAD_LOCAL static vec_zz_pEX GiantStepFile; NTL_THREAD_LOCAL static long use_files; // FIXME: thread-safe impl: need unique file names static double CalcTableSize(long n, long k) { double sz = zz_p::storage(); sz = sz*zz_pE::degree(); sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_zz_p); sz = sz*n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_zz_pE); sz = sz * k; sz = sz/1024; return sz; } static void GenerateBabySteps(zz_pEX& h1, const zz_pEX& f, const zz_pEX& h, long k, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } zz_pEXModulus F; build(F, f); zz_pEXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); h1 = h; long i; if (!use_files) { BabyStepFile.kill(); BabyStepFile.SetLength(k-1); } for (i = 1; i <= k-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName(zz_pEX_stem, "baby", i)); s << h1 << "\n"; s.close(); } else BabyStepFile(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const zz_pEX& f, const zz_pEX& h, long l, long verbose) { double t; if (verbose) { cerr << "generating giant steps..."; t = GetTime(); } zz_pEXModulus F; build(F, f); zz_pEXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); zz_pEX h1; h1 = h; long i; if (!use_files) { GiantStepFile.kill(); GiantStepFile.SetLength(l); } for (i = 1; i <= l-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName(zz_pEX_stem, "giant", i)); s << h1 << "\n"; s.close(); } else GiantStepFile(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (use_files) { ofstream s; OpenWrite(s, FileName(zz_pEX_stem, "giant", i)); s << h1 << "\n"; s.close(); } else GiantStepFile(i) = h1; if (verbose) cerr << (GetTime()-t) << "\n"; } static void FileCleanup(long k, long l) { if (use_files) { long i; for (i = 1; i <= k-1; i++) remove(FileName(zz_pEX_stem, "baby", i)); for (i = 1; i <= l; i++) remove(FileName(zz_pEX_stem, "giant", i)); } else { BabyStepFile.kill(); GiantStepFile.kill(); } } static void NewAddFactor(vec_pair_zz_pEX_long& u, const zz_pEX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_zz_pEX_long& u, zz_pEX& f, const zz_pEXModulus& F, vec_zz_pEX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; zz_pEX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(zz_pEX& g, long gs, const zz_pEXModulus& F) { if (use_files) { ifstream s; OpenRead(s, FileName(zz_pEX_stem, "giant", gs)); s >> g; s.close(); } else g = GiantStepFile(gs); rem(g, g, F); } static void FetchBabySteps(vec_zz_pEX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { if (use_files) { ifstream s; OpenRead(s, FileName(zz_pEX_stem, "baby", i)); s >> v[i]; s.close(); } else v[i] = BabyStepFile(i); } } static void GiantRefine(vec_pair_zz_pEX_long& u, const zz_pEX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_zz_pEX BabyStep; FetchBabySteps(BabyStep, k); vec_zz_pEX buf(INIT_SIZE, zz_pEX_GCDTableSize); zz_pEX f; f = ff; zz_pEXModulus F; build(F, f); zz_pEX g; zz_pEX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); sub(buf[size-1], g, BabyStep[bs]); } else { sub(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == zz_pEX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_zz_pEX_long& factors, const zz_pEX& ff, long k, long gs, const vec_zz_pEX& BabyStep, long verbose) { vec_zz_pEX buf(INIT_SIZE, zz_pEX_GCDTableSize); zz_pEX f; f = ff; zz_pEXModulus F; build(F, f); zz_pEX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); sub(buf[size], buf[size], g); size++; if (size == zz_pEX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_zz_pEX_long& factors, const vec_pair_zz_pEX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_zz_pEX BabyStep; long i; for (i = 0; i < u.length(); i++) { const zz_pEX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_zz_pEX_long& factors, const zz_pEX& f, const zz_pEX& h, long verbose) { if (!IsOne(LeadCoeff(f))) Error("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } if (!zz_pEX_stem[0]) sprintf(zz_pEX_stem, "ddf-%ld", RandomBnd(10000)); long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; zz_pEX h1; if (CalcTableSize(deg(f), k + l - 1) > zz_pEXFileThresh) use_files = 1; else use_files = 0; GenerateBabySteps(h1, f, h, k, verbose); GenerateGiantSteps(f, h1, l, verbose); vec_pair_zz_pEX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); FileCleanup(k, l); } long IterComputeDegree(const zz_pEX& h, const zz_pEXModulus& F) { long n = deg(F); if (n == 1 || IsX(h)) return 1; long B = n/2; long k = SqrRoot(B); long l = (B+k-1)/k; zz_pEXArgument H; #if 0 double n2 = sqrt(double(n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); zz_pEX h1; h1 = h; vec_zz_pEX baby; baby.SetLength(k); SetX(baby[0]); long i; for (i = 1; i <= k-1; i++) { baby[i] = h1; CompMod(h1, h1, H, F); if (IsX(h1)) return i+1; } build(H, h1, F, sz); long j; for (j = 2; j <= l; j++) { CompMod(h1, h1, H, F); for (i = k-1; i >= 0; i--) { if (h1 == baby[i]) return j*k-i; } } return n; } NTL_END_IMPL ntl-6.2.1/src/lzz_pEXTest.c000644 000765 000024 00000001473 12377144457 016027 0ustar00shoupstaff000000 000000 #include #include NTL_CLIENT int main() { zz_p::init(17); zz_pX P; BuildIrred(P, 10); zz_pE::init(P); zz_pEX f, g, h; random(f, 20); SetCoeff(f, 20); random(h, 20); g = MinPolyMod(h, f); if (deg(g) < 0) Error("bad zz_pEXTest (1)"); if (CompMod(g, h, f) != 0) Error("bad zz_pEXTest (2)"); vec_pair_zz_pEX_long v; long i; for (i = 0; i < 5; i++) { long n = RandomBnd(20)+1; cerr << n << " "; random(f, n); SetCoeff(f, n); v = CanZass(f); g = mul(v); if (f != g) cerr << "oops1\n"; long i; for (i = 0; i < v.length(); i++) if (!DetIrredTest(v[i].a)) Error("bad zz_pEXTest (3)"); } cerr << "\n"; cerr << "zz_pEXTest OK\n"; } ntl-6.2.1/src/lzz_pX.c000644 000765 000024 00000163213 12377144456 015062 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL // NOTE: these are declared extern in lzz_pX.h const long zz_pX_mod_crossover[5] = {45, 45, 90, 180, 180}; const long zz_pX_mul_crossover[5] = {90, 400, 600, 1500, 1500}; const long zz_pX_newton_crossover[5] = {150, 150, 300, 700, 700}; const long zz_pX_div_crossover[5] = {180, 180, 350, 750, 750}; const long zz_pX_halfgcd_crossover[5] = {90, 90, 180, 350, 350}; const long zz_pX_gcd_crossover[5] = {400, 400, 800, 1400, 1400}; const long zz_pX_bermass_crossover[5] = {400, 480, 900, 1600, 1600}; const long zz_pX_trace_crossover[5] = {200, 350, 450, 800, 800}; const zz_pX& zz_pX::zero() { NTL_THREAD_LOCAL static zz_pX z; return z; } istream& operator>>(istream& s, zz_pX& x) { s >> x.rep; x.normalize(); return s; } ostream& operator<<(ostream& s, const zz_pX& a) { return s << a.rep; } void zz_pX::normalize() { long n; const zz_p* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const zz_pX& a) { return a.rep.length() == 0; } long IsOne(const zz_pX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } void GetCoeff(zz_p& x, const zz_pX& a, long i) { if (i < 0 || i > deg(a)) clear(x); else x = a.rep[i]; } void SetCoeff(zz_pX& x, long i, zz_p a) { long j, m; if (i < 0) Error("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } x.rep[i] = a; x.normalize(); } void SetCoeff(zz_pX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else SetCoeff(x, i, to_zz_p(a)); } void SetCoeff(zz_pX& x, long i) { long j, m; if (i < 0) Error("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) Error("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(zz_pX& x) { clear(x); SetCoeff(x, 1); } long IsX(const zz_pX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const zz_p coeff(const zz_pX& a, long i) { if (i < 0 || i > deg(a)) return zz_p::zero(); else return a.rep[i]; } const zz_p LeadCoeff(const zz_pX& a) { if (IsZero(a)) return zz_p::zero(); else return a.rep[deg(a)]; } const zz_p ConstTerm(const zz_pX& a) { if (IsZero(a)) return zz_p::zero(); else return a.rep[0]; } void conv(zz_pX& x, zz_p a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(zz_pX& x, long a) { if (a == 0) { x.rep.SetLength(0); return; } zz_p t; conv(t, a); conv(x, t); } void conv(zz_pX& x, const ZZ& a) { if (a == 0) { x.rep.SetLength(0); return; } zz_p t; conv(t, a); conv(x, t); } void conv(zz_pX& x, const vec_zz_p& a) { x.rep = a; x.normalize(); } void add(zz_pX& x, const zz_pX& a, const zz_pX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const zz_p *ap, *bp; zz_p* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(zz_pX& x, const zz_pX& a, zz_p b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(zz_pX& x, const zz_pX& a, const zz_pX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const zz_p *ap, *bp; zz_p* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(zz_pX& x, const zz_pX& a, zz_p b) { if (a.rep.length() == 0) { x.rep.SetLength(1); negate(x.rep[0], b); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); } x.normalize(); } void sub(zz_pX& x, zz_p a, const zz_pX& b) { negate(x, b); add(x, x, a); } void negate(zz_pX& x, const zz_pX& a) { long n = a.rep.length(); x.rep.SetLength(n); const zz_p* ap = a.rep.elts(); zz_p* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } void mul(zz_pX& x, const zz_pX& a, const zz_pX& b) { if (&a == &b) { sqr(x, a); return; } if (deg(a) > NTL_zz_pX_MUL_CROSSOVER && deg(b) > NTL_zz_pX_MUL_CROSSOVER) FFTMul(x, a, b); else PlainMul(x, a, b); } void sqr(zz_pX& x, const zz_pX& a) { if (deg(a) > NTL_zz_pX_MUL_CROSSOVER) FFTSqr(x, a); else PlainSqr(x, a); } /* "plain" multiplication and squaring actually incorporates Karatsuba */ void PlainMul(zz_p *xp, const zz_p *ap, long sa, const zz_p *bp, long sb) { if (sa == 0 || sb == 0) return; long sx = sa+sb-1; if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const zz_p *t = ap; ap = bp; bp = t; } } long i, j; for (i = 0; i < sx; i++) clear(xp[i]); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (i = 0; i < sb; i++) { long t1 = rep(bp[i]); mulmod_precon_t bpinv = PrepMulModPrecon(t1, p, pinv); // ((double) t1)*pinv; zz_p *xp1 = xp+i; for (j = 0; j < sa; j++) { long t2; t2 = MulModPrecon(rep(ap[j]), t1, p, bpinv); xp1[j].LoopHole() = AddMod(t2, rep(xp1[j]), p); } } } NTL_THREAD_LOCAL static vec_double a_buf, b_buf; static inline void reduce(zz_p& r, double x, long p, double pinv) { long rr = long(x - double(p)*double(long(x*pinv))); if (rr < 0) rr += p; if (rr >= p) rr -= p; r.LoopHole() = rr; } void PlainMul_FP(zz_p *xp, const zz_p *aap, long sa, const zz_p *bbp, long sb) { if (sa == 0 || sb == 0) return; double *ap = a_buf.elts(); double *bp = b_buf.elts(); long d = sa+sb-2; long i, j, jmin, jmax; for (i = 0; i < sa; i++) ap[i] = double(rep(aap[i])); for (i = 0; i < sb; i++) bp[i] = double(rep(bbp[i])); double accum; long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (i = 0; i <= d; i++) { jmin = max(0, i-(sb-1)); jmax = min((sa-1), i); accum = 0; for (j = jmin; j <= jmax; j++) { accum += ap[j]*bp[i-j]; } reduce(xp[i], accum, p, pinv); } } #define KARX (16) void KarFold(zz_p *T, const zz_p *b, long sb, long hsa) { long m = sb - hsa; long i; for (i = 0; i < m; i++) add(T[i], b[i], b[hsa+i]); for (i = m; i < hsa; i++) T[i] = b[i]; } void KarSub(zz_p *T, const zz_p *b, long sb) { long i; for (i = 0; i < sb; i++) sub(T[i], T[i], b[i]); } void KarAdd(zz_p *T, const zz_p *b, long sb) { long i; for (i = 0; i < sb; i++) add(T[i], T[i], b[i]); } void KarFix(zz_p *c, const zz_p *b, long sb, long hsa) { long i; for (i = 0; i < hsa; i++) c[i] = b[i]; for (i = hsa; i < sb; i++) add(c[i], c[i], b[i]); } void KarMul(zz_p *c, const zz_p *a, long sa, const zz_p *b, long sb, zz_p *stk) { if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const zz_p *t = a; a = b; b = t; } } if (sb < KARX) { PlainMul(c, a, sa, b, sb); return; } long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long hsa2 = hsa << 1; zz_p *T1, *T2, *T3; T1 = stk; stk += hsa; T2 = stk; stk += hsa; T3 = stk; stk += hsa2 - 1; /* compute T1 = a_lo + a_hi */ KarFold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ KarFold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ KarMul(T3, T1, hsa, T2, hsa, stk); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ KarMul(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk); KarSub(T3, c + hsa2, sa + sb - hsa2 - 1); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ KarMul(c, a, hsa, b, hsa, stk); KarSub(T3, c, hsa2 - 1); clear(c[hsa2 - 1]); /* finally, add T3 * X^{hsa} to c */ KarAdd(c+hsa, T3, hsa2-1); } else { /* degenerate case */ zz_p *T; T = stk; stk += hsa + sb - 1; /* recursively compute b*a_hi into high part of c */ KarMul(c + hsa, a + hsa, sa - hsa, b, sb, stk); /* recursively compute b*a_lo into T */ KarMul(T, a, hsa, b, sb, stk); KarFix(c, T, hsa + sb - 1, hsa); } } void KarMul_FP(zz_p *c, const zz_p *a, long sa, const zz_p *b, long sb, zz_p *stk) { if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const zz_p *t = a; a = b; b = t; } } if (sb < KARX) { PlainMul_FP(c, a, sa, b, sb); return; } long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long hsa2 = hsa << 1; zz_p *T1, *T2, *T3; T1 = stk; stk += hsa; T2 = stk; stk += hsa; T3 = stk; stk += hsa2 - 1; /* compute T1 = a_lo + a_hi */ KarFold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ KarFold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ KarMul_FP(T3, T1, hsa, T2, hsa, stk); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ KarMul_FP(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk); KarSub(T3, c + hsa2, sa + sb - hsa2 - 1); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ KarMul_FP(c, a, hsa, b, hsa, stk); KarSub(T3, c, hsa2 - 1); clear(c[hsa2 - 1]); /* finally, add T3 * X^{hsa} to c */ KarAdd(c+hsa, T3, hsa2-1); } else { /* degenerate case */ zz_p *T; T = stk; stk += hsa + sb - 1; /* recursively compute b*a_hi into high part of c */ KarMul_FP(c + hsa, a + hsa, sa - hsa, b, sb, stk); /* recursively compute b*a_lo into T */ KarMul_FP(T, a, hsa, b, sb, stk); KarFix(c, T, hsa + sb - 1, hsa); } } void PlainMul(zz_pX& c, const zz_pX& a, const zz_pX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sa == 0 || sb == 0) { clear(c); return; } if (sa == 1) { mul(c, b, a.rep[0]); return; } if (sb == 1) { mul(c, a, b.rep[0]); return; } if (&a == &b) { PlainSqr(c, a); return; } vec_zz_p mem; const zz_p *ap, *bp; zz_p *cp; if (&a == &c) { mem = a.rep; ap = mem.elts(); } else ap = a.rep.elts(); if (&b == &c) { mem = b.rep; bp = mem.elts(); } else bp = b.rep.elts(); c.rep.SetLength(sa+sb-1); cp = c.rep.elts(); long p = zz_p::modulus(); long use_FP = ((p < NTL_SP_BOUND/KARX) && (double(p)*double(p) < NTL_FDOUBLE_PRECISION/KARX)); if (sa < KARX || sb < KARX) { if (use_FP) { a_buf.SetLength(max(sa, sb)); b_buf.SetLength(max(sa, sb)); PlainMul_FP(cp, ap, sa, bp, sb); } else PlainMul(cp, ap, sa, bp, sb); } else { /* karatsuba */ long n, hn, sp; n = max(sa, sb); sp = 0; do { hn = (n+1) >> 1; sp += (hn << 2) - 1; n = hn; } while (n >= KARX); vec_zz_p stk; stk.SetLength(sp); if (use_FP) { a_buf.SetLength(max(sa, sb)); b_buf.SetLength(max(sa, sb)); KarMul_FP(cp, ap, sa, bp, sb, stk.elts()); } else KarMul(cp, ap, sa, bp, sb, stk.elts()); } c.normalize(); } void PlainSqr_FP(zz_p *xp, const zz_p *aap, long sa) { if (sa == 0) return; long da = sa-1; long d = 2*da; long i, j, jmin, jmax, m, m2; double *ap = a_buf.elts(); for (i = 0; i < sa; i++) ap[i] = double(rep(aap[i])); double accum; long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (i = 0; i <= d; i++) { jmin = max(0, i-da); jmax = min(da, i); m = jmax - jmin + 1; m2 = m >> 1; jmax = jmin + m2 - 1; accum = 0; for (j = jmin; j <= jmax; j++) { accum += ap[j]*ap[i-j]; } accum += accum; if (m & 1) { accum += ap[jmax + 1]*ap[jmax + 1]; } reduce(xp[i], accum, p, pinv); } } void PlainSqr(zz_p *xp, const zz_p *ap, long sa) { if (sa == 0) return; long i, j, k, cnt; cnt = 2*sa-1; for (i = 0; i < cnt; i++) clear(xp[i]); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); long t1, t2; i = -1; for (j = 0; j <= sa-2; j++) { i += 2; t1 = MulMod(rep(ap[j]), rep(ap[j]), p, pinv); t2 = rep(xp[i-1]); t2 = AddMod(t2, t2, p); t2 = AddMod(t2, t1, p); xp[i-1].LoopHole() = t2; cnt = sa - 1 - j; const zz_p *ap1 = ap+(j+1); zz_p *xp1 = xp+i; t1 = rep(ap[j]); mulmod_precon_t tpinv = PrepMulModPrecon(t1, p, pinv); // ((double) t1)*pinv; for (k = 0; k < cnt; k++) { t2 = MulModPrecon(rep(ap1[k]), t1, p, tpinv); t2 = AddMod(t2, rep(xp1[k]), p); xp1[k].LoopHole() = t2; } t2 = rep(*xp1); t2 = AddMod(t2, t2, p); (*xp1).LoopHole() = t2; } t1 = rep(ap[sa-1]); t1 = MulMod(t1, t1, p, pinv); xp[2*sa-2].LoopHole() = t1; } #define KARSX (30) void KarSqr(zz_p *c, const zz_p *a, long sa, zz_p *stk) { if (sa < KARSX) { PlainSqr(c, a, sa); return; } long hsa = (sa + 1) >> 1; long hsa2 = hsa << 1; zz_p *T1, *T2; T1 = stk; stk += hsa; T2 = stk; stk += hsa2-1; KarFold(T1, a, sa, hsa); KarSqr(T2, T1, hsa, stk); KarSqr(c + hsa2, a+hsa, sa-hsa, stk); KarSub(T2, c + hsa2, sa + sa - hsa2 - 1); KarSqr(c, a, hsa, stk); KarSub(T2, c, hsa2 - 1); clear(c[hsa2 - 1]); KarAdd(c+hsa, T2, hsa2-1); } void KarSqr_FP(zz_p *c, const zz_p *a, long sa, zz_p *stk) { if (sa < KARSX) { PlainSqr_FP(c, a, sa); return; } long hsa = (sa + 1) >> 1; long hsa2 = hsa << 1; zz_p *T1, *T2; T1 = stk; stk += hsa; T2 = stk; stk += hsa2-1; KarFold(T1, a, sa, hsa); KarSqr_FP(T2, T1, hsa, stk); KarSqr_FP(c + hsa2, a+hsa, sa-hsa, stk); KarSub(T2, c + hsa2, sa + sa - hsa2 - 1); KarSqr_FP(c, a, hsa, stk); KarSub(T2, c, hsa2 - 1); clear(c[hsa2 - 1]); KarAdd(c+hsa, T2, hsa2-1); } void PlainSqr(zz_pX& c, const zz_pX& a) { if (IsZero(a)) { clear(c); return; } vec_zz_p mem; const zz_p *ap; zz_p *cp; long sa = a.rep.length(); if (&a == &c) { mem = a.rep; ap = mem.elts(); } else ap = a.rep.elts(); c.rep.SetLength(2*sa-1); cp = c.rep.elts(); long p = zz_p::modulus(); long use_FP = ((p < NTL_SP_BOUND/KARSX) && (double(p)*double(p) < NTL_FDOUBLE_PRECISION/KARSX)); if (sa < KARSX) { if (use_FP) { a_buf.SetLength(sa); PlainSqr_FP(cp, ap, sa); } else PlainSqr(cp, ap, sa); } else { /* karatsuba */ long n, hn, sp; n = sa; sp = 0; do { hn = (n+1) >> 1; sp += hn+hn+hn - 1; n = hn; } while (n >= KARSX); vec_zz_p stk; stk.SetLength(sp); if (use_FP) { a_buf.SetLength(sa); KarSqr_FP(cp, ap, sa, stk.elts()); } else KarSqr(cp, ap, sa, stk.elts()); } c.normalize(); } void PlainDivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b) { long da, db, dq, i, j, LCIsOne; const zz_p *bp; zz_p *qp; zz_p *xp; zz_p LCInv, t; zz_p s; da = deg(a); db = deg(b); if (db < 0) Error("zz_pX: division by zero"); if (da < db) { r = a; clear(q); return; } zz_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_p x; if (&r == &a) xp = r.rep.elts(); else { x = a.rep; xp = x.elts(); } dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (i = dq; i >= 0; i--) { t = xp[i+db]; if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long T = rep(t); mulmod_precon_t Tpinv = PrepMulModPrecon(T, p, pinv); // ((double) T)*pinv; for (j = db-1; j >= 0; j--) { long S = MulModPrecon(rep(bp[j]), T, p, Tpinv); S = AddMod(S, rep(xp[i+j]), p); xp[i+j].LoopHole() = S; } } r.rep.SetLength(db); if (&r != &a) { for (i = 0; i < db; i++) r.rep[i] = xp[i]; } r.normalize(); } void PlainDiv(zz_pX& q, const zz_pX& a, const zz_pX& b) { long da, db, dq, i, j, LCIsOne; const zz_p *bp; zz_p *qp; zz_p *xp; zz_p LCInv, t; zz_p s; da = deg(a); db = deg(b); if (db < 0) Error("zz_pX: division by zero"); if (da < db) { clear(q); return; } zz_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_p x; x.SetLength(da+1-db); for (i = db; i <= da; i++) x[i-db] = a.rep[i]; xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (i = dq; i >= 0; i--) { t = xp[i]; if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long T = rep(t); mulmod_precon_t Tpinv = PrepMulModPrecon(T, p, pinv); // ((double) T)*pinv; long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { long S = MulModPrecon(rep(bp[j]), T, p, Tpinv); S = AddMod(S, rep(xp[i+j-db]), p); xp[i+j-db].LoopHole() = S; } } } void PlainRem(zz_pX& r, const zz_pX& a, const zz_pX& b) { long da, db, dq, i, j, LCIsOne; const zz_p *bp; zz_p *xp; zz_p LCInv, t; zz_p s; da = deg(a); db = deg(b); if (db < 0) Error("zz_pX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_p x; if (&r == &a) xp = r.rep.elts(); else { x = a.rep; xp = x.elts(); } dq = da - db; long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (i = dq; i >= 0; i--) { t = xp[i+db]; if (!LCIsOne) mul(t, t, LCInv); negate(t, t); long T = rep(t); mulmod_precon_t Tpinv = PrepMulModPrecon(T, p, pinv); // ((double) T)*pinv; for (j = db-1; j >= 0; j--) { long S = MulModPrecon(rep(bp[j]), T, p, Tpinv); S = AddMod(S, rep(xp[i+j]), p); xp[i+j].LoopHole() = S; } } r.rep.SetLength(db); if (&r != &a) { for (i = 0; i < db; i++) r.rep[i] = xp[i]; } r.normalize(); } void mul(zz_pX& x, const zz_pX& a, zz_p b) { if (IsZero(b)) { clear(x); return; } if (IsOne(b)) { x = a; return; } long i, da; const zz_p *ap; zz_p* xp; long t; t = rep(b); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); mulmod_precon_t bpinv = PrepMulModPrecon(t, p, pinv); // t*pinv; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) xp[i].LoopHole() = MulModPrecon(rep(ap[i]), t, p, bpinv); x.normalize(); } void PlainGCD(zz_pX& x, const zz_pX& a, const zz_pX& b) { zz_p t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; zz_pX u(INIT_SIZE, n), v(INIT_SIZE, n); u = a; v = b; do { PlainRem(u, u, v); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } void PlainXGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b) { zz_p z; if (IsZero(b)) { set(s); clear(t); d = a; } else if (IsZero(a)) { clear(s); set(t); d = b; } else { long e = max(deg(a), deg(b)) + 1; zz_pX temp(INIT_SIZE, e), u(INIT_SIZE, e), v(INIT_SIZE, e), u0(INIT_SIZE, e), v0(INIT_SIZE, e), u1(INIT_SIZE, e), v1(INIT_SIZE, e), u2(INIT_SIZE, e), v2(INIT_SIZE, e), q(INIT_SIZE, e); set(u1); clear(v1); clear(u2); set(v2); u = a; v = b; do { DivRem(q, u, u, v); swap(u, v); u0 = u2; v0 = v2; mul(temp, q, u2); sub(u2, u1, temp); mul(temp, q, v2); sub(v2, v1, temp); u1 = u0; v1 = v0; } while (!IsZero(v)); d = u; s = u1; t = v1; } if (IsZero(d)) return; if (IsOne(LeadCoeff(d))) return; /* make gcd monic */ inv(z, LeadCoeff(d)); mul(d, d, z); mul(s, s, z); mul(t, t, z); } void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) Error("MulMod: bad args"); zz_pX t; mul(t, a, b); rem(x, t, f); } void SqrMod(zz_pX& x, const zz_pX& a, const zz_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("SqrMod: bad args"); zz_pX t; sqr(t, a); rem(x, t, f); } void InvMod(zz_pX& x, const zz_pX& a, const zz_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvMod: bad args"); zz_pX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) Error("zz_pX InvMod: can't compute multiplicative inverse"); } long InvModStatus(zz_pX& x, const zz_pX& a, const zz_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) Error("InvModStatus: bad args"); zz_pX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } static void MulByXModAux(zz_pX& h, const zz_pX& a, const zz_pX& f) { long i, n, m; zz_p* hh; const zz_p *aa, *ff; zz_p t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) Error("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(zz_pX& h, const zz_pX& a, const zz_pX& f) { if (&h == &f) { zz_pX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void random(zz_pX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void fftRep::SetSize(long NewK) { if (NewK < -1 || NewK >= NTL_BITS_PER_LONG-1) Error("bad arg to fftRep::SetSize()"); if (NewK <= MaxK) { k = NewK; return; } if (MaxK == -1) NumPrimes = zz_pInfo->NumPrimes; else if (NumPrimes != zz_pInfo->NumPrimes) Error("fftRep: inconsistent use"); long i, n; if (MaxK != -1) for (i = 0; i < zz_pInfo->NumPrimes; i++) free(tbl[i]); n = 1L << NewK; for (i = 0; i < zz_pInfo->NumPrimes; i++) { if ( !(tbl[i] = (long *) NTL_MALLOC(n, sizeof(long), 0)) ) Error("out of space in fftRep::SetSize()"); } k = MaxK = NewK; } fftRep::fftRep(const fftRep& R) { k = MaxK = R.k; NumPrimes = 0; if (k < 0) return; NumPrimes = R.NumPrimes; long i, j, n; n = 1L << k; for (i = 0; i < NumPrimes; i++) { if ( !(tbl[i] = (long *) NTL_MALLOC(n, sizeof(long), 0)) ) Error("out of space in fftRep"); for (j = 0; j < n; j++) tbl[i][j] = R.tbl[i][j]; } } fftRep& fftRep::operator=(const fftRep& R) { if (this == &R) return *this; if (MaxK >= 0 && R.MaxK >= 0 && NumPrimes != R.NumPrimes) Error("fftRep: inconsistent use"); if (R.k < 0) { k = -1; return *this; } NumPrimes = R.NumPrimes; if (R.k > MaxK) { long i, n; if (MaxK != -1) { for (i = 0; i < NumPrimes; i++) free(tbl[i]); } n = 1L << R.k; for (i = 0; i < NumPrimes; i++) { if ( !(tbl[i] = (long *) NTL_MALLOC(n, sizeof(long), 0)) ) Error("out of space in fftRep"); } k = MaxK = R.k; } else { k = R.k; } long i, j, n; n = 1L << k; for (i = 0; i < NumPrimes; i++) for (j = 0; j < n; j++) tbl[i][j] = R.tbl[i][j]; return *this; } fftRep::~fftRep() { if (MaxK == -1) return; for (long i = 0; i < NumPrimes; i++) free(tbl[i]); } void FromModularRep(zz_p& res, long *a) { long n = zz_pInfo->NumPrimes; long p = zz_pInfo->p; double pinv = zz_pInfo->pinv; long *CoeffModP = zz_pInfo->CoeffModP; double *x = zz_pInfo->x; long *u = zz_pInfo->u; long MinusMModP = zz_pInfo->MinusMModP; long q, s, t; long i; double y; // I've re-written the following code in v5.3 so that it is // a bit more robust. #if (NTL_zz_p_QUICK_CRT) y = 0; for (i = 0; i < n; i++) y = y + ((double) a[i])*x[i]; y = floor(y + 0.5); y = y - floor(y*pinv)*double(p); while (y >= p) y -= p; while (y < 0) y += p; q = long(y); t = 0; for (i = 0; i < n; i++) { // DIRT: uses undocumented MulMod feature (see ZZ.h) // a[i] is not reduced mod p s = MulMod(a[i], CoeffModP[i], p, pinv); t = AddMod(t, s, p); } s = MulMod(q, MinusMModP, p, pinv); t = AddMod(t, s, p); res.LoopHole() = t; #else y = 0; t = 0; for (i = 0; i < n; i++) { s = MulMod2(a[i], u[i], FFTPrime[i], x[i]); y = y + double(s)*FFTPrimeInv[i]; // DIRT: uses undocumented MulMod feature (see ZZ.h) // a[i] is not reduced mod p s = MulMod(s, CoeffModP[i], p, pinv); t = AddMod(t, s, p); } q = (long) (y + 0.5); // DIRT: uses undocumented MulMod feature (see ZZ.h) // q may not be reduced mod p s = MulMod(q, MinusMModP, p, pinv); t = AddMod(t, s, p); res.LoopHole() = t; #endif } void TofftRep(fftRep& y, const zz_pX& x, long k, long lo, long hi) // computes an n = 2^k point convolution. // if deg(x) >= 2^k, then x is first reduced modulo X^n-1. { long n, i, j, m, j1; zz_p accum; long NumPrimes = zz_pInfo->NumPrimes; if (k > zz_pInfo->MaxRoot) Error("Polynomial too big for FFT"); if (lo < 0) Error("bad arg to TofftRep"); hi = min(hi, deg(x)); y.SetSize(k); n = 1L << k; m = max(hi-lo + 1, 0); const zz_p *xx = x.rep.elts(); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { for (j = 0; j < n; j++) { if (j >= m) { y.tbl[0][j] = 0; } else { accum = xx[j+lo]; for (j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); y.tbl[0][j] = rep(accum); } } } else { for (j = 0; j < n; j++) { if (j >= m) { for (i = 0; i < NumPrimes; i++) y.tbl[i][j] = 0; } else { accum = xx[j+lo]; for (j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); for (i = 0; i < NumPrimes; i++) { long q = FFTPrime[i]; long t = rep(accum); if (t >= q) t -= q; y.tbl[i][j] = t; } } } } if (p_info) { long *yp = &y.tbl[0][0]; FFTFwd(yp, yp, k, *p_info); } else { for (i = 0; i < zz_pInfo->NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTFwd(yp, yp, k, i); } } } void RevTofftRep(fftRep& y, const vec_zz_p& x, long k, long lo, long hi, long offset) // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. { long n, i, j, m, j1; zz_p accum; long NumPrimes = zz_pInfo->NumPrimes; if (k > zz_pInfo->MaxRoot) Error("Polynomial too big for FFT"); if (lo < 0) Error("bad arg to TofftRep"); hi = min(hi, x.length()-1); y.SetSize(k); n = 1L << k; m = max(hi-lo + 1, 0); const zz_p *xx = x.elts(); FFTPrimeInfo *p_info = zz_pInfo->p_info; offset = offset & (n-1); if (p_info) { for (j = 0; j < n; j++) { if (j >= m) { y.tbl[0][offset] = 0; } else { accum = xx[j+lo]; for (j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); y.tbl[0][offset] = rep(accum); } offset = (offset + 1) & (n-1); } } else { for (j = 0; j < n; j++) { if (j >= m) { for (i = 0; i < NumPrimes; i++) y.tbl[i][offset] = 0; } else { accum = xx[j+lo]; for (j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); for (i = 0; i < NumPrimes; i++) { long q = FFTPrime[i]; long t = rep(accum); if (t >= q) t -= q; y.tbl[i][offset] = t; } } offset = (offset + 1) & (n-1); } } if (p_info) { long *yp = &y.tbl[0][0]; FFTRev1(yp, yp, k, *p_info); } else { for (i = 0; i < zz_pInfo->NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } } } void FromfftRep(zz_pX& x, fftRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { long k, n, i, j, l; long NumPrimes = zz_pInfo->NumPrimes; long t[4]; k = y.k; n = (1L << k); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { long *yp = &y.tbl[0][0]; FFTRev1(yp, yp, k, *p_info); } else { for (i = 0; i < NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } } hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.rep.SetLength(l); if (p_info) { zz_p *xp = x.rep.elts(); long *yp = &y.tbl[0][0]; for (j = 0; j < l; j++) xp[j].LoopHole() = yp[j+lo]; } else { for (j = 0; j < l; j++) { for (i = 0; i < NumPrimes; i++) t[i] = y.tbl[i][j+lo]; FromModularRep(x.rep[j], t); } } x.normalize(); } void RevFromfftRep(vec_zz_p& x, fftRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // using "inverted" evaluation points. // only the coefficients lo..hi are computed { long k, n, i, j, l; long NumPrimes = zz_pInfo->NumPrimes; long t[4]; k = y.k; n = (1L << k); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { long *yp = &y.tbl[0][0]; FFTFwd(yp, yp, k, *p_info); } else { for (i = 0; i < NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTFwd(yp, yp, k, i); } } hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.SetLength(l); if (p_info) { zz_p *xp = x.elts(); long *yp = &y.tbl[0][0]; for (j = 0; j < l; j++) xp[j].LoopHole() = yp[j+lo]; } else { for (j = 0; j < l; j++) { for (i = 0; i < NumPrimes; i++) t[i] = y.tbl[i][j+lo]; FromModularRep(x[j], t); } } } void NDFromfftRep(zz_pX& x, const fftRep& y, long lo, long hi, fftRep& z) { long k, n, i, j, l; long NumPrimes = zz_pInfo->NumPrimes; long t[4]; k = y.k; n = (1L << k); z.SetSize(k); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { long *zp = &z.tbl[0][0]; const long *yp = &y.tbl[0][0]; FFTRev1(zp, yp, k, *p_info); } else { for (i = 0; i < NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *yp = &y.tbl[i][0]; FFTRev1(zp, yp, k, i); } } hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.rep.SetLength(l); if (p_info) { zz_p *xp = x.rep.elts(); long *zp = &z.tbl[0][0]; for (j = 0; j < l; j++) xp[j].LoopHole() = zp[j+lo]; } else { for (j = 0; j < l; j++) { for (i = 0; i < NumPrimes; i++) t[i] = z.tbl[i][j+lo]; FromModularRep(x.rep[j], t); } } x.normalize(); } void NDFromfftRep(zz_pX& x, fftRep& y, long lo, long hi) { fftRep z; NDFromfftRep(x, y, lo, hi, z); } void FromfftRep(zz_p* x, fftRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { long k, n, i, j; long NumPrimes = zz_pInfo->NumPrimes; long t[4]; k = y.k; n = (1L << k); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { long *yp = &y.tbl[0][0]; FFTRev1(yp, yp, k, *p_info); for (j = lo; j <= hi; j++) { if (j >= n) clear(x[j-lo]); else { x[j-lo].LoopHole() = y.tbl[0][j]; } } } else { for (i = 0; i < NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } for (j = lo; j <= hi; j++) { if (j >= n) clear(x[j-lo]); else { for (i = 0; i < zz_pInfo->NumPrimes; i++) t[i] = y.tbl[i][j]; FromModularRep(x[j-lo], t); } } } } void mul(fftRep& z, const fftRep& x, const fftRep& y) { long k, n, i, j; if (x.k != y.k) Error("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { long *zp = &z.tbl[0][0]; const long *xp = &x.tbl[0][0]; const long *yp = &y.tbl[0][0]; long q = p_info->q; double qinv = p_info->qinv; for (j = 0; j < n; j++) zp[j] = MulMod(xp[j], yp[j], q, qinv); } else { for (i = 0; i < zz_pInfo->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = FFTPrime[i]; double qinv = FFTPrimeInv[i]; for (j = 0; j < n; j++) zp[j] = MulMod(xp[j], yp[j], q, qinv); } } } void sub(fftRep& z, const fftRep& x, const fftRep& y) { long k, n, i, j; if (x.k != y.k) Error("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { long *zp = &z.tbl[0][0]; const long *xp = &x.tbl[0][0]; const long *yp = &y.tbl[0][0]; long q = p_info->q; for (j = 0; j < n; j++) zp[j] = SubMod(xp[j], yp[j], q); } else { for (i = 0; i < zz_pInfo->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = FFTPrime[i]; for (j = 0; j < n; j++) zp[j] = SubMod(xp[j], yp[j], q); } } } void add(fftRep& z, const fftRep& x, const fftRep& y) { long k, n, i, j; if (x.k != y.k) Error("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { long *zp = &z.tbl[0][0]; const long *xp = &x.tbl[0][0]; const long *yp = &y.tbl[0][0]; long q = p_info->q; for (j = 0; j < n; j++) zp[j] = AddMod(xp[j], yp[j], q); } else { for (i = 0; i < zz_pInfo->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = FFTPrime[i]; for (j = 0; j < n; j++) zp[j] = AddMod(xp[j], yp[j], q); } } } void reduce(fftRep& x, const fftRep& a, long k) // reduces a 2^l point FFT-rep to a 2^k point FFT-rep // input may alias output { long i, j, l, n; long* xp; const long* ap; l = a.k; n = 1L << k; if (l < k) Error("reduce: bad operands"); x.SetSize(k); for (i = 0; i < zz_pInfo->NumPrimes; i++) { ap = &a.tbl[i][0]; xp = &x.tbl[i][0]; for (j = 0; j < n; j++) xp[j] = ap[j << (l-k)]; } } void AddExpand(fftRep& x, const fftRep& a) // x = x + (an "expanded" version of a) { long i, j, l, k, n; l = x.k; k = a.k; n = 1L << k; if (l < k) Error("AddExpand: bad args"); FFTPrimeInfo *p_info = zz_pInfo->p_info; if (p_info) { long q = p_info->q; const long *ap = &a.tbl[0][0]; long *xp = &x.tbl[0][0]; for (j = 0; j < n; j++) { long j1 = j << (l-k); xp[j1] = AddMod(xp[j1], ap[j], q); } } else { for (i = 0; i < zz_pInfo->NumPrimes; i++) { long q = FFTPrime[i]; const long *ap = &a.tbl[i][0]; long *xp = &x.tbl[i][0]; for (j = 0; j < n; j++) { long j1 = j << (l-k); xp[j1] = AddMod(xp[j1], ap[j], q); } } } } void FFTMul(zz_pX& x, const zz_pX& a, const zz_pX& b) { long k, d; if (IsZero(a) || IsZero(b)) { clear(x); return; } d = deg(a) + deg(b); k = NextPowerOfTwo(d+1); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(R1, a, k); TofftRep(R2, b, k); mul(R1, R1, R2); FromfftRep(x, R1, 0, d); } void FFTSqr(zz_pX& x, const zz_pX& a) { long k, d; if (IsZero(a)) { clear(x); return; } d = 2*deg(a); k = NextPowerOfTwo(d+1); fftRep R1(INIT_SIZE, k); TofftRep(R1, a, k); mul(R1, R1, R1); FromfftRep(x, R1, 0, d); } void CopyReverse(zz_pX& x, const zz_pX& a, long lo, long hi) // x[0..hi-lo] = reverse(a[lo..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const zz_p* ap = a.rep.elts(); zz_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void copy(zz_pX& x, const zz_pX& a, long lo, long hi) // x[0..hi-lo] = a[lo..hi], with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const zz_p* ap = a.rep.elts(); zz_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = lo + i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void rem21(zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long i, da, ds, n, kk; da = deg(a); n = F.n; if (da > 2*n-2) Error("bad args to rem(zz_pX,zz_pX,zz_pXModulus)"); if (da < n) { x = a; return; } if (!F.UseFFT || da - n <= NTL_zz_pX_MOD_CROSSOVER) { PlainRem(x, a, F.f); return; } fftRep R1(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); TofftRep(R1, a, F.l, n, 2*(n-1)); mul(R1, R1, F.HRep); FromfftRep(P1, R1, n-2, 2*n-4); TofftRep(R1, P1, F.k); mul(R1, R1, F.FRep); FromfftRep(P1, R1, 0, n-1); ds = deg(P1); kk = 1L << F.k; x.rep.SetLength(n); const zz_p* aa = a.rep.elts(); const zz_p* ss = P1.rep.elts(); zz_p* xx = x.rep.elts(); for (i = 0; i < n; i++) { if (i <= ds) sub(xx[i], aa[i], ss[i]); else xx[i] = aa[i]; if (i + kk <= da) add(xx[i], xx[i], aa[i+kk]); } x.normalize(); } void DivRem21(zz_pX& q, zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long i, da, ds, n, kk; da = deg(a); n = F.n; if (da > 2*n-2) Error("bad args to rem(zz_pX,zz_pX,zz_pXModulus)"); if (da < n) { x = a; clear(q); return; } if (!F.UseFFT || da - n <= NTL_zz_pX_MOD_CROSSOVER) { PlainDivRem(q, x, a, F.f); return; } fftRep R1(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n), qq; TofftRep(R1, a, F.l, n, 2*(n-1)); mul(R1, R1, F.HRep); FromfftRep(P1, R1, n-2, 2*n-4); qq = P1; TofftRep(R1, P1, F.k); mul(R1, R1, F.FRep); FromfftRep(P1, R1, 0, n-1); ds = deg(P1); kk = 1L << F.k; x.rep.SetLength(n); const zz_p* aa = a.rep.elts(); const zz_p* ss = P1.rep.elts(); zz_p* xx = x.rep.elts(); for (i = 0; i < n; i++) { if (i <= ds) sub(xx[i], aa[i], ss[i]); else xx[i] = aa[i]; if (i + kk <= da) add(xx[i], xx[i], aa[i+kk]); } x.normalize(); q = qq; } void div21(zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long da, n; da = deg(a); n = F.n; if (da > 2*n-2) Error("bad args to rem(zz_pX,zz_pX,zz_pXModulus)"); if (da < n) { clear(x); return; } if (!F.UseFFT || da - n <= NTL_zz_pX_MOD_CROSSOVER) { PlainDiv(x, a, F.f); return; } fftRep R1(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); TofftRep(R1, a, F.l, n, 2*(n-1)); mul(R1, R1, F.HRep); FromfftRep(x, R1, n-2, 2*n-4); } void rem(zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) Error("rem: uninitialized modulus"); if (da <= 2*n-2) { rem21(x, a, F); return; } else if (!F.UseFFT || da-n <= NTL_zz_pX_MOD_CROSSOVER) { PlainRem(x, a, F.f); return; } zz_pX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); rem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) Error("DivRem: uninitialized modulus"); if (da <= 2*n-2) { DivRem21(q, r, a, F); return; } else if (!F.UseFFT || da-n <= NTL_zz_pX_MOD_CROSSOVER) { PlainDivRem(q, r, a, F.f); return; } zz_pX buf(INIT_SIZE, 2*n-1); zz_pX qbuf(INIT_SIZE, n-1); zz_pX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); DivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(zz_pX& q, const zz_pX& a, const zz_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) Error("div: uninitialized modulus"); if (da <= 2*n-2) { div21(q, a, F); return; } else if (!F.UseFFT || da-n <= NTL_zz_pX_MOD_CROSSOVER) { PlainDiv(q, a, F.f); return; } zz_pX buf(INIT_SIZE, 2*n-1); zz_pX qbuf(INIT_SIZE, n-1); zz_pX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) DivRem21(qbuf, buf, buf, F); else div21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pXModulus& F) { long da, db, d, n, k; da = deg(a); db = deg(b); n = F.n; if (n < 0) Error("MulMod: uninitialized modulus"); if (da >= n || db >= n) Error("bad args to MulMod(zz_pX,zz_pX,zz_pX,zz_pXModulus)"); if (da < 0 || db < 0) { clear(x); return; } if (!F.UseFFT || da <= NTL_zz_pX_MUL_CROSSOVER || db <= NTL_zz_pX_MUL_CROSSOVER) { zz_pX P1; mul(P1, a, b); rem(x, P1, F); return; } d = da + db + 1; k = NextPowerOfTwo(d); k = max(k, F.k); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); TofftRep(R1, a, k); TofftRep(R2, b, k); mul(R1, R1, R2); NDFromfftRep(P1, R1, n, d-1, R2); // save R1 for future use TofftRep(R2, P1, F.l); mul(R2, R2, F.HRep); FromfftRep(P1, R2, n-2, 2*n-4); TofftRep(R2, P1, F.k); mul(R2, R2, F.FRep); reduce(R1, R1, F.k); sub(R1, R1, R2); FromfftRep(x, R1, 0, n-1); } void SqrMod(zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long da, d, n, k; da = deg(a); n = F.n; if (n < 0) Error("SqrMod: uninitialized modulus"); if (da >= n) Error("bad args to SqrMod(zz_pX,zz_pX,zz_pXModulus)"); if (!F.UseFFT || da <= NTL_zz_pX_MUL_CROSSOVER) { zz_pX P1; sqr(P1, a); rem(x, P1, F); return; } d = 2*da + 1; k = NextPowerOfTwo(d); k = max(k, F.k); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); TofftRep(R1, a, k); mul(R1, R1, R1); NDFromfftRep(P1, R1, n, d-1, R2); // save R1 for future use TofftRep(R2, P1, F.l); mul(R2, R2, F.HRep); FromfftRep(P1, R2, n-2, 2*n-4); TofftRep(R2, P1, F.k); mul(R2, R2, F.FRep); reduce(R1, R1, F.k); sub(R1, R1, R2); FromfftRep(x, R1, 0, n-1); } void PlainInvTrunc(zz_pX& x, const zz_pX& a, long m) /* x = (1/a) % X^m, input not output, constant term a is nonzero */ { long i, k, n, lb; zz_p v, t; zz_p s; const zz_p* ap; zz_p* xp; n = deg(a); if (n < 0) Error("division by zero"); inv(s, ConstTerm(a)); if (n == 0) { conv(x, s); return; } ap = a.rep.elts(); x.rep.SetLength(m); xp = x.rep.elts(); xp[0] = s; long is_one = IsOne(s); for (k = 1; k < m; k++) { clear(v); lb = max(k-n, 0); for (i = lb; i <= k-1; i++) { mul(t, xp[i], ap[k-i]); add(v, v, t); } xp[k] = v; negate(xp[k], xp[k]); if (!is_one) mul(xp[k], xp[k], s); } x.normalize(); } void trunc(zz_pX& x, const zz_pX& a, long m) // x = a % X^m, output may alias input { if (m < 0) Error("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; zz_p* xp; const zz_p* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void CyclicReduce(zz_pX& x, const zz_pX& a, long m) // computes x = a mod X^m-1 { long n = deg(a); long i, j; zz_p accum; if (n < m) { x = a; return; } if (&x != &a) x.rep.SetLength(m); for (i = 0; i < m; i++) { accum = a.rep[i]; for (j = i + m; j <= n; j += m) add(accum, accum, a.rep[j]); x.rep[i] = accum; } if (&x == &a) x.rep.SetLength(m); x.normalize(); } void InvTrunc(zz_pX& x, const zz_pX& a, long m) { if (m < 0) Error("InvTrunc: bad args"); if (m == 0) { clear(x); return; } if (NTL_OVERFLOW(m, 1, 0)) Error("overflow in InvTrunc"); if (&x == &a) { zz_pX la; la = a; if (m > NTL_zz_pX_NEWTON_CROSSOVER && deg(a) > 0) NewtonInvTrunc(x, la, m); else PlainInvTrunc(x, la, m); } else { if (m > NTL_zz_pX_NEWTON_CROSSOVER && deg(a) > 0) NewtonInvTrunc(x, a, m); else PlainInvTrunc(x, a, m); } } void build(zz_pXModulus& x, const zz_pX& f) { x.f = f; x.n = deg(f); x.tracevec.SetLength(0); if (x.n <= 0) Error("build: deg(f) must be at least 1"); if (x.n <= NTL_zz_pX_MOD_CROSSOVER + 1) { x.UseFFT = 0; return; } x.UseFFT = 1; x.k = NextPowerOfTwo(x.n); x.l = NextPowerOfTwo(2*x.n - 3); TofftRep(x.FRep, f, x.k); zz_pX P1(INIT_SIZE, x.n+1), P2(INIT_SIZE, x.n); CopyReverse(P1, f, 0, x.n); InvTrunc(P2, P1, x.n-1); CopyReverse(P1, P2, 0, x.n-2); TofftRep(x.HRep, P1, x.l); } zz_pXModulus::zz_pXModulus(const zz_pX& ff) { build(*this, ff); } zz_pXMultiplier::zz_pXMultiplier(const zz_pX& b, const zz_pXModulus& F) { build(*this, b, F); } void build(zz_pXMultiplier& x, const zz_pX& b, const zz_pXModulus& F) { long db; long n = F.n; if (n < 0) Error("build zz_pXMultiplier: uninitialized modulus"); x.b = b; db = deg(b); if (db >= n) Error("build zz_pXMultiplier: deg(b) >= deg(f)"); if (!F.UseFFT || db <= NTL_zz_pX_MOD_CROSSOVER) { x.UseFFT = 0; return; } x.UseFFT = 1; fftRep R1(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); TofftRep(R1, b, F.l); reduce(x.B2, R1, F.k); mul(R1, R1, F.HRep); FromfftRep(P1, R1, n-1, 2*n-3); TofftRep(x.B1, P1, F.l); } void MulMod(zz_pX& x, const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F) { long n = F.n; long da; da = deg(a); if (da >= n) Error(" bad args to MulMod(zz_pX,zz_pX,zz_pXMultiplier,zz_pXModulus)"); if (da < 0) { clear(x); return; } if (!B.UseFFT || !F.UseFFT || da <= NTL_zz_pX_MOD_CROSSOVER) { zz_pX P1; mul(P1, a, B.b); rem(x, P1, F); return; } zz_pX P1(INIT_SIZE, n), P2(INIT_SIZE, n); fftRep R1(INIT_SIZE, F.l), R2(INIT_SIZE, F.l); TofftRep(R1, a, F.l); mul(R2, R1, B.B1); FromfftRep(P1, R2, n-1, 2*n-3); reduce(R1, R1, F.k); mul(R1, R1, B.B2); TofftRep(R2, P1, F.k); mul(R2, R2, F.FRep); sub(R1, R1, R2); FromfftRep(x, R1, 0, n-1); } void PowerXMod(zz_pX& hh, const ZZ& e, const zz_pXModulus& F) { if (F.n < 0) Error("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; zz_pX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) MulByXMod(h, h, F.f); } if (e < 0) InvMod(h, h, F); hh = h; } void PowerXPlusAMod(zz_pX& hh, zz_p a, const ZZ& e, const zz_pXModulus& F) { if (F.n < 0) Error("PowerXPlusAMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } zz_pX t1(INIT_SIZE, F.n), t2(INIT_SIZE, F.n); long n = NumBits(e); long i; zz_pX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) { MulByXMod(t1, h, F.f); mul(t2, h, a); add(h, t1, t2); } } if (e < 0) InvMod(h, h, F); hh = h; } void PowerMod(zz_pX& h, const zz_pX& g, const ZZ& e, const zz_pXModulus& F) { if (deg(g) >= F.n) Error("PowerMod: bad args"); if (IsZero(e)) { set(h); return; } zz_pXMultiplier G; zz_pX res; long n = NumBits(e); long i; build(G, g, F); res.SetMaxLength(F.n); set(res); for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, G, F); } if (e < 0) InvMod(res, res, F); h = res; } void NewtonInvTrunc(zz_pX& x, const zz_pX& a, long m) { x.SetMaxLength(m); long i; long t; t = NextPowerOfTwo(2*m-1); fftRep R1(INIT_SIZE, t), R2(INIT_SIZE, t); zz_pX P1(INIT_SIZE, m); long log2_newton = NextPowerOfTwo(NTL_zz_pX_NEWTON_CROSSOVER)-1; PlainInvTrunc(x, a, 1L << log2_newton); long k = 1L << log2_newton; long a_len = min(m, a.rep.length()); while (k < m) { long l = min(2*k, m); t = NextPowerOfTwo(2*k); TofftRep(R1, x, t); mul(R1, R1, R1); FromfftRep(P1, R1, 0, l-1); t = NextPowerOfTwo(deg(P1) + min(l, a_len)); TofftRep(R1, P1, t); TofftRep(R2, a, t, 0, min(l, a_len)-1); mul(R1, R1, R2); FromfftRep(P1, R1, k, l-1); x.rep.SetLength(l); long y_len = P1.rep.length(); for (i = k; i < l; i++) { if (i-k >= y_len) clear(x.rep[i]); else negate(x.rep[i], P1.rep[i-k]); } x.normalize(); k = l; } } void FFTDivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b) { long n = deg(b); long m = deg(a); long k, l; if (m < n) { clear(q); r = a; return; } if (m >= 3*n) { zz_pXModulus B; build(B, b); DivRem(q, r, a, B); return; } zz_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); long k1 = NextPowerOfTwo(n); long mx = max(k1, k); fftRep R1(INIT_SIZE, mx), R2(INIT_SIZE, mx); TofftRep(R1, P1, k); TofftRep(R2, a, k, n, m); mul(R1, R1, R2); FromfftRep(P3, R1, m-n, 2*(m-n)); l = 1L << k1; TofftRep(R1, b, k1); TofftRep(R2, P3, k1); mul(R1, R1, R2); FromfftRep(P1, R1, 0, n-1); CyclicReduce(P2, a, l); trunc(r, P2, n); sub(r, r, P1); q = P3; } void FFTDiv(zz_pX& q, const zz_pX& a, const zz_pX& b) { long n = deg(b); long m = deg(a); long k; if (m < n) { clear(q); return; } if (m >= 3*n) { zz_pXModulus B; build(B, b); div(q, a, B); return; } zz_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(R1, P1, k); TofftRep(R2, a, k, n, m); mul(R1, R1, R2); FromfftRep(q, R1, m-n, 2*(m-n)); } void FFTRem(zz_pX& r, const zz_pX& a, const zz_pX& b) { long n = deg(b); long m = deg(a); long k, l; if (m < n) { r = a; return; } if (m >= 3*n) { zz_pXModulus B; build(B, b); rem(r, a, B); return; } zz_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); long k1 = NextPowerOfTwo(n); long mx = max(k, k1); fftRep R1(INIT_SIZE, mx), R2(INIT_SIZE, mx); TofftRep(R1, P1, k); TofftRep(R2, a, k, n, m); mul(R1, R1, R2); FromfftRep(P3, R1, m-n, 2*(m-n)); l = 1L << k1; TofftRep(R1, b, k1); TofftRep(R2, P3, k1); mul(R1, R1, R2); FromfftRep(P3, R1, 0, n-1); CyclicReduce(P2, a, l); trunc(r, P2, n); sub(r, r, P3); } void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b) { if (deg(b) > NTL_zz_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_zz_pX_DIV_CROSSOVER) FFTDivRem(q, r, a, b); else PlainDivRem(q, r, a, b); } void div(zz_pX& q, const zz_pX& a, const zz_pX& b) { if (deg(b) > NTL_zz_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_zz_pX_DIV_CROSSOVER) FFTDiv(q, a, b); else PlainDiv(q, a, b); } void div(zz_pX& q, const zz_pX& a, zz_p b) { zz_p t; inv(t, b); mul(q, a, t); } void rem(zz_pX& r, const zz_pX& a, const zz_pX& b) { if (deg(b) > NTL_zz_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_zz_pX_DIV_CROSSOVER) FFTRem(r, a, b); else PlainRem(r, a, b); } long operator==(const zz_pX& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); long da = deg(a); if (da > 0) return 0; zz_p bb; bb = b; if (da < 0) return IsZero(bb); return a.rep[0] == bb; } long operator==(const zz_pX& a, zz_p b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } void power(zz_pX& x, const zz_pX& a, long e) { if (e < 0) { Error("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) Error("overflow in power"); zz_pX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } void reverse(zz_pX& x, const zz_pX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) Error("overflow in reverse"); if (&x == &a) { zz_pX tmp; CopyReverse(tmp, a, 0, hi); x = tmp; } else CopyReverse(x, a, 0, hi); } NTL_END_IMPL ntl-6.2.1/src/lzz_pX1.c000644 000765 000024 00000104600 12377144456 015136 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL long divide(zz_pX& q, const zz_pX& a, const zz_pX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } zz_pX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const zz_pX& a, const zz_pX& b) { if (IsZero(b)) return IsZero(a); zz_pX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } void zz_pXMatrix::operator=(const zz_pXMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } void RightShift(zz_pX& x, const zz_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) Error("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(zz_pX& x, const zz_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void ShiftAdd(zz_pX& U, const zz_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) add(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void ShiftSub(zz_pX& U, const zz_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void mul(zz_pX& U, zz_pX& V, const zz_pXMatrix& M) // (U, V)^T = M*(U, V)^T { long d = deg(U) - deg(M(1,1)); long k = NextPowerOfTwo(d - 1); // When the GCD algorithm is run on polynomials of degree n, n-1, // where n is a power of two, then d-1 is likely to be a power of two. // It would be more natural to set k = NextPowerOfTwo(d+1), but this // would be much less efficient in this case. long n = (1L << k); long xx; zz_p a0, a1, b0, b1, c0, d0, u0, u1, v0, v1, nu0, nu1, nv0; zz_p t1, t2; if (n == d-1) xx = 1; else if (n == d) xx = 2; else xx = 3; switch (xx) { case 1: GetCoeff(a0, M(0,0), 0); GetCoeff(a1, M(0,0), 1); GetCoeff(b0, M(0,1), 0); GetCoeff(b1, M(0,1), 1); GetCoeff(c0, M(1,0), 0); GetCoeff(d0, M(1,1), 0); GetCoeff(u0, U, 0); GetCoeff(u1, U, 1); GetCoeff(v0, V, 0); GetCoeff(v1, V, 1); mul(t1, (a0), (u0)); mul(t2, (b0), (v0)); add(t1, t1, t2); nu0 = t1; mul(t1, (a1), (u0)); mul(t2, (a0), (u1)); add(t1, t1, t2); mul(t2, (b1), (v0)); add(t1, t1, t2); mul(t2, (b0), (v1)); add(t1, t1, t2); nu1 = t1; mul(t1, (c0), (u0)); mul(t2, (d0), (v0)); add (t1, t1, t2); nv0 = t1; break; case 2: GetCoeff(a0, M(0,0), 0); GetCoeff(b0, M(0,1), 0); GetCoeff(u0, U, 0); GetCoeff(v0, V, 0); mul(t1, (a0), (u0)); mul(t2, (b0), (v0)); add(t1, t1, t2); nu0 = t1; break; case 3: break; } fftRep RU(INIT_SIZE, k), RV(INIT_SIZE, k), R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(RU, U, k); TofftRep(RV, V, k); TofftRep(R1, M(0,0), k); mul(R1, R1, RU); TofftRep(R2, M(0,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromfftRep(U, R1, 0, d); TofftRep(R1, M(1,0), k); mul(R1, R1, RU); TofftRep(R2, M(1,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromfftRep(V, R1, 0, d-1); // now fix-up results switch (xx) { case 1: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d-1, u0); SetCoeff(U, 0, nu0); GetCoeff(u1, U, 1); sub(u1, u1, nu1); SetCoeff(U, d, u1); SetCoeff(U, 1, nu1); GetCoeff(v0, V, 0); sub(v0, v0, nv0); SetCoeff(V, d-1, v0); SetCoeff(V, 0, nv0); break; case 2: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d, u0); SetCoeff(U, 0, nu0); break; } } void mul(zz_pXMatrix& A, zz_pXMatrix& B, zz_pXMatrix& C) // A = B*C, B and C are destroyed { long db = deg(B(1,1)); long dc = deg(C(1,1)); long da = db + dc; long k = NextPowerOfTwo(da+1); fftRep B00, B01, B10, B11, C0, C1, T1, T2; TofftRep(B00, B(0,0), k); B(0,0).kill(); TofftRep(B01, B(0,1), k); B(0,1).kill(); TofftRep(B10, B(1,0), k); B(1,0).kill(); TofftRep(B11, B(1,1), k); B(1,1).kill(); TofftRep(C0, C(0,0), k); C(0,0).kill(); TofftRep(C1, C(1,0), k); C(1,0).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromfftRep(A(0,0), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromfftRep(A(1,0), T1, 0, da); TofftRep(C0, C(0,1), k); C(0,1).kill(); TofftRep(C1, C(1,1), k); C(1,1).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromfftRep(A(0,1), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromfftRep(A(1,1), T1, 0, da); } void IterHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; zz_pX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { PlainDivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } void HalfGCD(zz_pXMatrix& M_out, const zz_pX& U, const zz_pX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; zz_pX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_zz_pX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } zz_pX Q; zz_pXMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); zz_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_zz_pX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } zz_pX Q; zz_pXMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); zz_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void HalfGCD(zz_pX& U, zz_pX& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); zz_pX Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(zz_pX& d, const zz_pX& u, const zz_pX& v) { zz_pX u1, v1; u1 = u; v1 = v; if (deg(u1) == deg(v1)) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (deg(u1) < deg(v1)) { swap(u1, v1); } // deg(u1) > deg(v1) while (deg(u1) > NTL_zz_pX_GCD_CROSSOVER && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } } PlainGCD(d, u1, v1); } void XGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b) { zz_p w; if (IsZero(a) && IsZero(b)) { clear(d); set(s); clear(t); return; } zz_pX U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } zz_pXMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize inv(w, LeadCoeff(d)); mul(d, d, w); mul(s, s, w); mul(t, t, w); } void IterBuild(zz_p* a, long n) { long i, k; zz_p b, t; if (n <= 0) return; negate(a[0], a[0]); for (k = 1; k <= n-1; k++) { negate(b, a[k]); add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void mul(zz_p* x, const zz_p* a, const zz_p* b, long n) { zz_p t, accum; long i, j, jmin, jmax; long d = 2*n-1; for (i = 0; i <= d; i++) { jmin = max(0, i-(n-1)); jmax = min(n-1, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, (a[j]), (b[i-j])); add(accum, accum, t); } if (i >= n) { add(accum, accum, (a[i-n])); add(accum, accum, (b[i-n])); } x[i] = accum; } } void BuildFromRoots(zz_pX& x, const vec_zz_p& a) { long n = a.length(); if (n == 0) { set(x); return; } long k0 = NextPowerOfTwo(NTL_zz_pX_MUL_CROSSOVER)-1; long crossover = 1L << k0; if (n <= NTL_zz_pX_MUL_CROSSOVER) { x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); return; } long k = NextPowerOfTwo(n); long m = 1L << k; long i, j; long l, width; zz_pX b(INIT_SIZE, m+1); b.rep = a; b.rep.SetLength(m+1); for (i = n; i < m; i++) clear(b.rep[i]); set(b.rep[m]); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); zz_p t1, one; set(one); vec_zz_p G(INIT_SIZE, crossover), H(INIT_SIZE, crossover); zz_p *g = G.elts(); zz_p *h = H.elts(); zz_p *tmp; for (i = 0; i < m; i+= crossover) { for (j = 0; j < crossover; j++) negate(g[j], b.rep[i+j]); if (k0 > 0) { for (j = 0; j < crossover; j+=2) { mul(t1, g[j], g[j+1]); add(g[j+1], g[j], g[j+1]); g[j] = t1; } } for (l = 1; l < k0; l++) { width = 1L << l; for (j = 0; j < crossover; j += 2*width) mul(&h[j], &g[j], &g[j+width], width); tmp = g; g = h; h = tmp; } for (j = 0; j < crossover; j++) b.rep[i+j] = g[j]; } for (l = k0; l < k; l++) { width = 1L << l; for (i = 0; i < m; i += 2*width) { t1 = b.rep[i+width]; set(b.rep[i+width]); TofftRep(R1, b, l+1, i, i+width); b.rep[i+width] = t1; t1 = b.rep[i+2*width]; set(b.rep[i+2*width]); TofftRep(R2, b, l+1, i+width, i+2*width); b.rep[i+2*width] = t1; mul(R1, R1, R2); FromfftRep(&b.rep[i], R1, 0, 2*width-1); sub(b.rep[i], b.rep[i], one); } } x.rep.SetLength(n+1); long delta = m-n; for (i = 0; i <= n; i++) x.rep[i] = b.rep[i+delta]; // no need to normalize } void eval(zz_p& b, const zz_pX& f, zz_p a) // does a Horner evaluation { zz_p acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_zz_p& b, const zz_pX& f, const vec_zz_p& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_zz_p bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(zz_pX& f, const vec_zz_p& a, const vec_zz_p& b) { long m = a.length(); if (b.length() != m) Error("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_zz_p prod; prod = a; zz_p t1, t2; long k, i; vec_zz_p res; res.SetLength(m); for (k = 0; k < m; k++) { const zz_p& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(zz_pX& x, const vec_zz_p& v, long low, long high, const vec_zz_pX& H, long n, vec_zz_p& t) { zz_p s; long i, j; zz_p *tp = t.elts(); for (j = 0; j < n; j++) clear(tp[j]); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_zz_p& h = H[i-low].rep; long m = h.length(); zz_p w = (v[i]); long W = rep(w); mulmod_precon_t Wpinv = PrepMulModPrecon(W, p, pinv); // ((double) W)*pinv; const zz_p *hp = h.elts(); for (j = 0; j < m; j++) { long S = MulModPrecon(rep(hp[j]), W, p, Wpinv); S = AddMod(S, rep(tp[j]), p); tp[j].LoopHole() = S; } } x.rep = t; x.normalize(); } void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& A, const zz_pXModulus& F) { if (deg(g) <= 0) { x = g; return; } zz_pX s, t; vec_zz_p scratch(INIT_SIZE, F.n); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; zz_pXMultiplier M; build(M, A.H[m], F); InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(zz_pXArgument& A, const zz_pX& h, const zz_pXModulus& F, long m) { if (m <= 0 || deg(h) >= F.n) Error("build: bad args"); if (m > F.n) m = F.n; long i; if (zz_pXArgBound > 0) { double sz = 1; sz = sz*F.n; sz = sz+6; sz = sz*(sizeof (long)); sz = sz/1024; m = min(m, long(zz_pXArgBound/sz)); m = max(m, 1); } zz_pXMultiplier M; build(M, h, F); A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], M, F); } NTL_THREAD_LOCAL long zz_pXArgBound = 0; void CompMod(zz_pX& x, const zz_pX& g, const zz_pX& h, const zz_pXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } zz_pXArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(zz_pX& x1, zz_pX& x2, const zz_pX& g1, const zz_pX& g2, const zz_pX& h, const zz_pXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } zz_pXArgument A; build(A, h, F, m); zz_pX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(zz_pX& x1, zz_pX& x2, zz_pX& x3, const zz_pX& g1, const zz_pX& g2, const zz_pX& g3, const zz_pX& h, const zz_pXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } zz_pXArgument A; build(A, h, F, m); zz_pX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } static void StripZeroes(vec_zz_p& x) { long n = x.length(); while (n > 0 && IsZero(x[n-1])) n--; x.SetLength(n); } void PlainUpdateMap(vec_zz_p& xx, const vec_zz_p& a, const zz_pX& b, const zz_pX& f) { long n = deg(f); long i, m; if (IsZero(b)) { xx.SetLength(0); return; } m = n-1 - deg(b); vec_zz_p x(INIT_SIZE, n); for (i = 0; i <= m; i++) InnerProduct(x[i], a, b.rep, i); if (deg(b) != 0) { zz_pX c(INIT_SIZE, n); LeftShift(c, b, m); for (i = m+1; i < n; i++) { MulByXMod(c, c, f); InnerProduct(x[i], a, c.rep); } } xx = x; } void UpdateMap(vec_zz_p& x, const vec_zz_p& aa, const zz_pXMultiplier& B, const zz_pXModulus& F) { long n = F.n; vec_zz_p a; a = aa; StripZeroes(a); if (a.length() > n) Error("UpdateMap: bad args"); long i; if (!B.UseFFT) { PlainUpdateMap(x, a, B.b, F.f); StripZeroes(x); return; } fftRep R1(INIT_SIZE, F.k), R2(INIT_SIZE, F.l); vec_zz_p V1(INIT_SIZE, n); RevTofftRep(R1, a, F.k, 0, a.length()-1, 0); mul(R2, R1, F.FRep); RevFromfftRep(V1, R2, 0, n-2); for (i = 0; i <= n-2; i++) negate(V1[i], V1[i]); RevTofftRep(R2, V1, F.l, 0, n-2, n-1); mul(R2, R2, B.B1); mul(R1, R1, B.B2); AddExpand(R2, R1); RevFromfftRep(x, R2, 0, n-1); StripZeroes(x); } void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F) { long n = F.n; if (a.length() > n || k < 0 || NTL_OVERFLOW(k, 1, 0)) Error("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; zz_pXMultiplier M; build(M, H.H[m], F); vec_zz_p s(INIT_SIZE, n); s = a; StripZeroes(s); x.SetLength(k); for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); zz_p* w = &x[i*m]; for (long j = 0; j < m1; j++) InnerProduct(w[j], H.H[j].rep, s); if (i < l) UpdateMap(s, s, M, F); } } void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F) { if (a.length() > F.n || k < 0) Error("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); zz_pXArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void BerlekampMassey(zz_pX& h, const vec_zz_p& a, long m) { zz_pX Lambda, Sigma, Temp; long L; zz_p Delta, Delta1, t1; long shamt; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(Delta1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(t1, Lambda.rep[i], a[r-i-1]); add(Delta1, Delta1, t1); } if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftSub(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftSub(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void GCDMinPolySeq(zz_pX& h, const vec_zz_p& x, long m) { long i; zz_pX a, b; zz_pXMatrix M; zz_p t; a.rep.SetLength(2*m); for (i = 0; i < 2*m; i++) a.rep[i] = x[2*m-1-i]; a.normalize(); SetCoeff(b, 2*m); HalfGCD(M, b, a, m+1); /* make monic */ inv(t, LeadCoeff(M(1,1))); mul(h, M(1,1), t); } void MinPolySeq(zz_pX& h, const vec_zz_p& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) Error("MinPoly: bad args"); if (a.length() < 2*m) Error("MinPoly: sequence too short"); if (m > NTL_zz_pX_BERMASS_CROSSOVER) GCDMinPolySeq(h, a, m); else BerlekampMassey(h, a, m); } void DoMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m, const vec_zz_p& R) { vec_zz_p x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) Error("ProbMinPoly: bad args"); long i; vec_zz_p R(INIT_SIZE, n); for (i = 0; i < n; i++) random(R[i]); DoMinPolyMod(h, g, F, m, R); } void MinPolyMod(zz_pX& hh, const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX h, h1; long n = F.n; if (m < 1 || m > n) Error("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; zz_pX h2, h3; zz_pXMultiplier H1; vec_zz_p R(INIT_SIZE, n); for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, H1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m) { vec_zz_p R(INIT_SIZE, 1); if (m < 1 || m > F.n) Error("IrredPoly: bad args"); set(R[0]); DoMinPolyMod(h, g, F, m, R); } void diff(zz_pX& x, const zz_pX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void MakeMonic(zz_pX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; zz_p t; inv(t, LeadCoeff(x)); mul(x, x, t); } void PlainMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n) { zz_pX y; mul(y, a, b); trunc(x, y, n); } void FFTMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n) { if (IsZero(a) || IsZero(b)) { clear(x); return; } long d = deg(a) + deg(b); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(R1, a, k); TofftRep(R2, b, k); mul(R1, R1, R2); FromfftRep(x, R1, 0, n-1); } void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n) { if (n < 0) Error("MulTrunc: bad args"); if (deg(a) <= NTL_zz_pX_MUL_CROSSOVER || deg(b) <= NTL_zz_pX_MUL_CROSSOVER) PlainMulTrunc(x, a, b, n); else FFTMulTrunc(x, a, b, n); } void PlainSqrTrunc(zz_pX& x, const zz_pX& a, long n) { zz_pX y; sqr(y, a); trunc(x, y, n); } void FFTSqrTrunc(zz_pX& x, const zz_pX& a, long n) { if (IsZero(a)) { clear(x); return; } long d = 2*deg(a); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); fftRep R1(INIT_SIZE, k); TofftRep(R1, a, k); mul(R1, R1, R1); FromfftRep(x, R1, 0, n-1); } void SqrTrunc(zz_pX& x, const zz_pX& a, long n) { if (n < 0) Error("SqrTrunc: bad args"); if (deg(a) <= NTL_zz_pX_MUL_CROSSOVER) PlainSqrTrunc(x, a, n); else FFTSqrTrunc(x, a, n); } void FastTraceVec(vec_zz_p& S, const zz_pX& f) { long n = deg(f); if (n <= 0) Error("FastTraceVec: bad args"); if (n == 0) { S.SetLength(0); return; } if (n == 1) { S.SetLength(1); set(S[0]); return; } long i; zz_pX f1; f1.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) f1.rep[i] = f.rep[n-i]; f1.normalize(); zz_pX f2; f2.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) mul(f2.rep[i], f.rep[n-1-i], i+1); f2.normalize(); zz_pX f3; InvTrunc(f3, f1, n-1); MulTrunc(f3, f3, f2, n-1); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(f3, i-1)); } void PlainTraceVec(vec_zz_p& S, const zz_pX& ff) { if (deg(ff) <= 0) Error("TraceVec: bad args"); zz_pX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; zz_p acc, t; const zz_p *fp = f.rep.elts();; zz_p *sp = S.elts(); sp[0] = n; for (k = 1; k < n; k++) { mul(acc, fp[n-k], k); for (i = 1; i < k; i++) { mul(t, fp[n-i], rep(sp[k-i])); add(acc, acc, t); } negate(sp[k], acc); } } void TraceVec(vec_zz_p& S, const zz_pX& f) { if (deg(f) <= NTL_zz_pX_TRACE_CROSSOVER) PlainTraceVec(S, f); else FastTraceVec(S, f); } void ComputeTraceVec(const zz_pXModulus& F) { vec_zz_p& S = *((vec_zz_p *) &F.tracevec); if (S.length() > 0) return; if (!F.UseFFT) { PlainTraceVec(S, F.f); return; } long i; long n = F.n; fftRep R; zz_pX P, g; g.rep.SetLength(n-1); for (i = 1; i < n; i++) mul(g.rep[n-i-1], F.f.rep[n-i], i); g.normalize(); TofftRep(R, g, F.l); mul(R, R, F.HRep); FromfftRep(P, R, n-2, 2*n-4); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(P, n-1-i)); } void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F) { long n = F.n; if (deg(a) >= n) Error("trace: bad args"); // FIXME: thread-safe-imple: need mutex here if (F.tracevec.length() == 0) ComputeTraceVec(F); InnerProduct(x, a.rep, F.tracevec); } void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) Error("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(zz_p& rres, const zz_pX& a, const zz_pX& b) { zz_p res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; zz_p lc; set(res); long n = max(deg(a),deg(b)) + 1; zz_pX u(INIT_SIZE, n), v(INIT_SIZE, n); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } } rres = res; } void ResIterHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red, vec_zz_p& cvec, vec_long& dvec) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; zz_pX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { append(cvec, LeadCoeff(V)); append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V)); PlainDivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } void ResHalfGCD(zz_pXMatrix& M_out, const zz_pX& U, const zz_pX& V, long d_red, vec_zz_p& cvec, vec_long& dvec) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; zz_pX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_zz_pX_HalfGCD_CROSSOVER) { ResIterHalfGCD(M_out, U1, V1, d_red, cvec, dvec); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; ResHalfGCD(M1, U1, V1, d1, cvec, dvec); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } zz_pX Q; zz_pXMatrix M2; append(cvec, LeadCoeff(V1)); append(dvec, dvec[dvec.length()-1]-deg(U1)+deg(V1)); DivRem(Q, U1, U1, V1); swap(U1, V1); ResHalfGCD(M2, U1, V1, d2, cvec, dvec); zz_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void ResHalfGCD(zz_pX& U, zz_pX& V, vec_zz_p& cvec, vec_long& dvec) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; ResHalfGCD(M1, U, V, d1, cvec, dvec); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); zz_pX Q; append(cvec, LeadCoeff(V)); append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V)); DivRem(Q, U, U, V); swap(U, V); ResHalfGCD(M1, U, V, d2, cvec, dvec); mul(U, V, M1); } void resultant(zz_p& rres, const zz_pX& u, const zz_pX& v) { if (deg(u) <= NTL_zz_pX_GCD_CROSSOVER || deg(v) <= NTL_zz_pX_GCD_CROSSOVER) { PlainResultant(rres, u, v); return; } zz_pX u1, v1; u1 = u; v1 = v; zz_p res, t; set(res); if (deg(u1) == deg(v1)) { rem(u1, u1, v1); swap(u1, v1); if (IsZero(v1)) { clear(rres); return; } power(t, LeadCoeff(u1), deg(u1) - deg(v1)); mul(res, res, t); if (deg(u1) & 1) negate(res, res); } else if (deg(u1) < deg(v1)) { swap(u1, v1); if (deg(u1) & deg(v1) & 1) negate(res, res); } // deg(u1) > deg(v1) && v1 != 0 vec_zz_p cvec; vec_long dvec; cvec.SetMaxLength(deg(v1)+2); dvec.SetMaxLength(deg(v1)+2); append(cvec, LeadCoeff(u1)); append(dvec, deg(u1)); while (deg(u1) > NTL_zz_pX_GCD_CROSSOVER && !IsZero(v1)) { ResHalfGCD(u1, v1, cvec, dvec); if (!IsZero(v1)) { append(cvec, LeadCoeff(v1)); append(dvec, deg(v1)); rem(u1, u1, v1); swap(u1, v1); } } if (IsZero(v1) && deg(u1) > 0) { clear(rres); return; } long i, l; l = dvec.length(); if (deg(u1) == 0) { // we went all the way... for (i = 0; i <= l-3; i++) { power(t, cvec[i+1], dvec[i]-dvec[i+2]); mul(res, res, t); if (dvec[i] & dvec[i+1] & 1) negate(res, res); } power(t, cvec[l-1], dvec[l-2]); mul(res, res, t); } else { for (i = 0; i <= l-3; i++) { power(t, cvec[i+1], dvec[i]-dvec[i+2]); mul(res, res, t); if (dvec[i] & dvec[i+1] & 1) negate(res, res); } power(t, cvec[l-1], dvec[l-2]-deg(v1)); mul(res, res, t); if (dvec[l-2] & dvec[l-1] & 1) negate(res, res); PlainResultant(t, u1, v1); mul(res, res, t); } rres = res; } void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) Error("norm: bad args"); if (IsZero(a)) { clear(x); return; } zz_p t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { zz_p t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } NTL_END_IMPL ntl-6.2.1/src/lzz_pXCharPoly.c000644 000765 000024 00000002314 12377144456 016516 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL static void HessCharPoly(zz_pX& g, const zz_pX& a, const zz_pX& f) { long n = deg(f); if (n <= 0 || deg(a) >= n) Error("HessCharPoly: bad args"); mat_zz_p M; M.SetDims(n, n); long i, j; zz_pX t; t = a; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) M[i][j] = coeff(t, j); if (i < n-1) MulByXMod(t, t, f); } CharPoly(g, M); } void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& ff) { zz_pX f = ff; MakeMonic(f); long n = deg(f); if (n <= 0 || deg(a) >= n) Error("CharPoly: bad args"); if (IsZero(a)) { clear(g); SetCoeff(g, n); return; } if (n > 90 || (zz_p::PrimeCnt() <= 1 && n > 45)) { zz_pX h; MinPolyMod(h, a, f); if (deg(h) == n) { g = h; return; } } if (zz_p::modulus() < n+1) { HessCharPoly(g, a, f); return; } vec_zz_p u(INIT_SIZE, n+1), v(INIT_SIZE, n+1); zz_pX h, h1; negate(h, a); long i; for (i = 0; i <= n; i++) { u[i] = i; add(h1, h, u[i]); resultant(v[i], f, h1); } interpolate(g, u, v); } NTL_END_IMPL ntl-6.2.1/src/lzz_pXFactoring.c000644 000765 000024 00000103765 12377144456 016725 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL void SquareFreeDecomp(vec_pair_zz_pX_long& u, const zz_pX& ff) { zz_pX f = ff; if (!IsOne(LeadCoeff(f))) Error("SquareFreeDecomp: bad args"); zz_pX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long p, k, d; p = long(zz_p::modulus()); d = deg(r)/p; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) f.rep[k] = r.rep[k*p]; m = m*p; } } while (!finished); } static void NullSpace(long& r, vec_long& D, vec_vec_zz_p& M, long verbose) { long k, l, n; long i, j; long pos; zz_p t1, t2; zz_p *x, *y; n = M.length(); D.SetLength(n); for (j = 0; j < n; j++) D[j] = -1; long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); long T1, T2; mulmod_precon_t T1pinv; r = 0; l = 0; for (k = 0; k < n; k++) { if (verbose && k % 10 == 0) cerr << "+"; pos = -1; for (i = l; i < n; i++) { if (!IsZero(M[i][k])) { pos = i; break; } } if (pos != -1) { swap(M[pos], M[l]); // make M[l, k] == -1 mod p inv(t1, M[l][k]); negate(t1, t1); for (j = k+1; j < n; j++) { mul(M[l][j], M[l][j], t1); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] t1 = M[i][k]; T1 = rep(t1); T1pinv = PrepMulModPrecon(T1, p, pinv); // ((double) T1)*pinv; x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 T2 = MulModPrecon(rep(*y), T1, p, T1pinv); T2 = AddMod(T2, rep(*x), p); (*x).LoopHole() = T2; } } D[k] = l; // variable k is defined by row l l++; } else { r++; } } } static void BuildMatrix(vec_vec_zz_p& M, long n, const zz_pX& g, const zz_pXModulus& F, long verbose) { long i, j, m; zz_pXMultiplier G; zz_pX h; M.SetLength(n); for (i = 0; i < n; i++) M[i].SetLength(n); build(G, g, F); set(h); for (j = 0; j < n; j++) { if (verbose && j % 10 == 0) cerr << "+"; m = deg(h); for (i = 0; i < n; i++) { if (i <= m) M[i][j] = h.rep[i]; else clear(M[i][j]); } if (j < n-1) MulMod(h, h, G, F); } for (i = 0; i < n; i++) add(M[i][i], M[i][i], -1); } static void RecFindRoots(vec_zz_p& x, const zz_pX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } zz_pX h; zz_p r; long p1 = zz_p::modulus() >> 1; { zz_pXModulus F; build(F, f); do { random(r); PowerXPlusAMod(h, r, p1, F); add(h, h, -1); GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_zz_p& x, const zz_pX& ff) { zz_pX f = ff; x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } static void RandomBasisElt(zz_pX& g, const vec_long& D, const vec_vec_zz_p& M) { zz_p t1, t2; long n = D.length(); long i, j, s; g.rep.SetLength(n); vec_zz_p& v = g.rep; for (j = n-1; j >= 0; j--) { if (D[j] == -1) random(v[j]); else { i = D[j]; // v[j] = sum_{s=j+1}^{n-1} v[s]*M[i,s] clear(t1); for (s = j+1; s < n; s++) { mul(t2, v[s], M[i][s]); add(t1, t1, t2); } v[j] = t1; } } g.normalize(); } static void split(zz_pX& f1, zz_pX& g1, zz_pX& f2, zz_pX& g2, const zz_pX& f, const zz_pX& g, const vec_zz_p& roots, long lo, long mid) { long r = mid-lo+1; zz_pXModulus F; build(F, f); vec_zz_p lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; zz_pX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } static void RecFindFactors(vec_zz_pX& factors, const zz_pX& f, const zz_pX& g, const vec_zz_p& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } zz_pX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } static void FindFactors(vec_zz_pX& factors, const zz_pX& f, const zz_pX& g, const vec_zz_p& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } #if 0 static void IterFindFactors(vec_zz_pX& factors, const zz_pX& f, const zz_pX& g, const vec_zz_p& roots) { long r = roots.length(); long i; zz_pX h; factors.SetLength(r); for (i = 0; i < r; i++) { sub(h, g, roots[i]); GCD(factors[i], f, h); } } #endif void SFBerlekamp(vec_zz_pX& factors, const zz_pX& ff, long verbose) { zz_pX f = ff; if (!IsOne(LeadCoeff(f))) Error("SFBerlekamp: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } double t; long p; p = zz_p::modulus(); long n = deg(f); zz_pXModulus F; build(F, f); zz_pX g, h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(g, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_long D; long r; vec_vec_zz_p M; if (verbose) { cerr << "building matrix..."; t = GetTime(); } BuildMatrix(M, n, g, F, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "diagonalizing..."; t = GetTime(); } NullSpace(r, D, M, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) cerr << "number of factors = " << r << "\n"; if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (verbose) { cerr << "factor extraction..."; t = GetTime(); } vec_zz_p roots; RandomBasisElt(g, D, M); MinPolyMod(h, g, F, r); if (deg(h) == r) M.kill(); FindRoots(roots, h); FindFactors(factors, f, g, roots); zz_pX g1; vec_zz_pX S, S1; long i; while (factors.length() < r) { if (verbose) cerr << "+"; RandomBasisElt(g, D, M); S.kill(); for (i = 0; i < factors.length(); i++) { const zz_pX& f = factors[i]; if (deg(f) == 1) { append(S, f); continue; } build(F, f); rem(g1, g, F); if (deg(g1) <= 0) { append(S, f); continue; } MinPolyMod(h, g1, F, min(deg(f), r-factors.length()+1)); FindRoots(roots, h); S1.kill(); FindFactors(S1, f, g1, roots); append(S, S1); } swap(factors, S); } if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "degrees:"; long i; for (i = 0; i < factors.length(); i++) cerr << " " << deg(factors[i]); cerr << "\n"; } } void berlekamp(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose) { double t; vec_pair_zz_pX_long sfd; vec_zz_pX x; if (!IsOne(LeadCoeff(f))) Error("berlekamp: bad args"); if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFBerlekamp(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } static void AddFactor(vec_pair_zz_pX_long& factors, const zz_pX& g, long d, long verbose) { if (verbose) cerr << "degree=" << d << ", number=" << deg(g)/d << "\n"; append(factors, cons(g, d)); } static void ProcessTable(zz_pX& f, vec_pair_zz_pX_long& factors, const zz_pXModulus& F, long limit, const vec_zz_pX& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; zz_pX t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); zz_pX t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); } void TraceMap(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& b) { if (d < 0) Error("TraceMap: bad args"); zz_pX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(zz_pX& y, const zz_pX& h, long q, const zz_pXModulus& F) { if (q < 0) Error("PowerCompose: bad args"); zz_pX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const zz_pX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; long p; p = zz_p::modulus(); zz_pXModulus F; build(F, f); zz_pX b, r, s; PowerXMod(b, p, F); long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); if (deg(s) > 0) return 0; } if (p >= n) return 1; if (n % p != 0) return 1; PowerCompose(s, b, n/p, F); return !IsX(s); } NTL_THREAD_LOCAL long zz_pX_BlockingFactor = 10; void DDF(vec_pair_zz_pX_long& factors, const zz_pX& ff, const zz_pX& hh, long verbose) { zz_pX f = ff; zz_pX h = hh; if (!IsOne(LeadCoeff(f))) Error("DDF: bad args"); factors.SetLength(0); if (deg(f) == 0) return; if (deg(f) == 1) { AddFactor(factors, f, 1, verbose); return; } long CompTableSize = 2*SqrRoot(deg(f)); long GCDTableSize = zz_pX_BlockingFactor; zz_pXModulus F; build(F, f); zz_pXArgument H; build(H, h, F, min(CompTableSize, deg(f))); long i, d, limit, old_n; zz_pX g, X; vec_zz_pX tbl(INIT_SIZE, GCDTableSize); SetX(X); i = 0; g = h; d = 1; limit = GCDTableSize; while (2*d <= deg(f)) { old_n = deg(f); sub(tbl[i], g, X); i++; if (i == limit) { ProcessTable(f, factors, F, i, tbl, d, verbose); i = 0; } d = d + 1; if (2*d <= deg(f)) { // we need to go further if (deg(f) < old_n) { // f has changed build(F, f); rem(h, h, f); rem(g, g, f); build(H, h, F, min(CompTableSize, deg(f))); } CompMod(g, g, H, F); } } ProcessTable(f, factors, F, i, tbl, d-1, verbose); if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose); } void RootEDF(vec_zz_pX& factors, const zz_pX& f, long verbose) { vec_zz_p roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); sub(factors[j], factors[j], roots[j]); } } static void EDFSplit(vec_zz_pX& v, const zz_pX& f, const zz_pX& b, long d) { zz_pX a, g, h; zz_pXModulus F; vec_zz_p roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } static void RecEDF(vec_zz_pX& factors, const zz_pX& f, const zz_pX& b, long d, long verbose) { vec_zz_pX v; long i; zz_pX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { zz_pX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_zz_pX& factors, const zz_pX& ff, const zz_pX& bb, long d, long verbose) { zz_pX f = ff; zz_pX b = bb; if (!IsOne(LeadCoeff(f))) Error("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass1(vec_pair_zz_pX_long& u, zz_pX& h, const zz_pX& f, long verbose) { if (!IsOne(LeadCoeff(f)) || deg(f) == 0) Error("SFCanZass1: bad args"); double t; long p = zz_p::modulus(); zz_pXModulus F; build(F, f); if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(h, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } } void SFCanZass2(vec_zz_pX& factors, const vec_pair_zz_pX_long& u, const zz_pX& h, long verbose) { zz_pX hh; vec_zz_pX v; factors.SetLength(0); long i; for (i = 0; i < u.length(); i++) { const zz_pX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void SFCanZass(vec_zz_pX& factors, const zz_pX& ff, long verbose) { zz_pX f = ff; if (!IsOne(LeadCoeff(f))) Error("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; long p = zz_p::modulus(); zz_pXModulus F; build(F, f); zz_pX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(h, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_zz_pX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } zz_pX hh; vec_zz_pX v; long i; for (i = 0; i < u.length(); i++) { const zz_pX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose) { if (!IsOne(LeadCoeff(f))) Error("CanZass: bad args"); double t; vec_pair_zz_pX_long sfd; vec_zz_pX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(zz_pX& f, const vec_pair_zz_pX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); zz_pX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } static long BaseCase(const zz_pX& h, long q, long a, const zz_pXModulus& F) { long b, e; zz_pX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } void TandemPowerCompose(zz_pX& y1, zz_pX& y2, const zz_pX& h, long q1, long q2, const zz_pXModulus& F) { zz_pX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } long RecComputeDegree(long u, const zz_pX& h, const zz_pXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); zz_pX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long ComputeDegree(const zz_pX& h, const zz_pXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } long ProbComputeDegree(const zz_pX& h, const zz_pXModulus& F) { if (F.n == 1 || IsX(h)) return 1; long n = F.n; zz_pX P1, P2, P3; random(P1, n); TraceMap(P2, P1, n, F, h); ProbMinPolyMod(P3, P2, F, n/2); long r = deg(P3); if (r <= 0 || n % r != 0) return 0; else return n/r; } void FindRoot(zz_p& root, const zz_pX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { zz_pXModulus F; zz_pX h, h1, f; zz_p r; long p1; f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoot: bad args"); if (deg(f) == 0) Error("FindRoot: bad args"); p1 = zz_p::modulus() >> 1; h1 = 1; while (deg(f) > 1) { build(F, f); random(r); PowerXPlusAMod(h, r, p1, F); sub(h, h, h1); GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const zz_pX& h, long q, long a, const zz_pXModulus& F) { long e; zz_pX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); sub(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const zz_pX& h, const zz_pXModulus& F, const FacVec& fvec) { long q1, q2; zz_pX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const zz_pX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; zz_pXModulus F; build(F, f); zz_pX h; PowerXMod(h, zz_p::modulus(), F); zz_pX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const zz_pX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; zz_pXModulus F; build(F, f); zz_pX h; PowerXMod(h, zz_p::modulus(), F); long rootn = SqrRoot(deg(f)); long CompTableSize = 2*rootn; zz_pXArgument H; long UseModComp = 1; if (NumBits(zz_p::modulus()) < rootn/2) UseModComp = 0; if (UseModComp) build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; zz_pX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { sub(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { if (UseModComp) CompMod(g, g, H, F); else PowerMod(g, g, zz_p::modulus(), F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_zz_pX& h, const zz_pX& f, const zz_pX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { zz_pX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); sub(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); sub(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(zz_pX& x, const zz_pX& f, const zz_pX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_zz_pX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_zz_p a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(zz_pX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(zz_pX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { zz_pX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(zz_pX& f, long n) { if (n <= 0) Error("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } void BuildRandomIrred(zz_pX& f, const zz_pX& g) { zz_pXModulus G; zz_pX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_THREAD_LOCAL long zz_pX_GCDTableSize = 4; NTL_THREAD_LOCAL static vec_zz_pX *BabyStepFile = 0; NTL_THREAD_LOCAL static vec_zz_pX *GiantStepFile = 0; NTL_THREAD_LOCAL static zz_pXArgument *HHH = 0; NTL_THREAD_LOCAL static long OldN = 0; static void GenerateBabySteps(zz_pX& h1, const zz_pX& f, const zz_pX& h, long k, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } zz_pXModulus F; build(F, f); BabyStepFile = NTL_NEW_OP vec_zz_pX; (*BabyStepFile).SetLength(k-1); h1 = h; long i; long rootn = SqrRoot(F.n); if (NumBits(zz_p::modulus()) < rootn/2) { for (i = 1; i <= k-1; i++) { (*BabyStepFile)(i) = h1; PowerMod(h1, h1, zz_p::modulus(), F); if (verbose) cerr << "+"; } } else { zz_pXArgument H; build(H, h, F, 2*rootn); for (i = 1; i <= k-1; i++) { (*BabyStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const zz_pX& f, const zz_pX& h, long l, long verbose) { zz_pXModulus F; build(F, f); HHH = NTL_NEW_OP zz_pXArgument; build(*HHH, h, F, 2*SqrRoot(F.n)); OldN = F.n; GiantStepFile = NTL_NEW_OP vec_zz_pX; (*GiantStepFile).SetLength(1); (*GiantStepFile)(1) = h; } static void FileCleanup(long k, long l) { delete BabyStepFile; delete GiantStepFile; delete HHH; } static void NewAddFactor(vec_pair_zz_pX_long& u, const zz_pX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_zz_pX_long& u, zz_pX& f, const zz_pXModulus& F, vec_zz_pX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; zz_pX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(zz_pX& g, long gs, const zz_pXModulus& F) { long l = (*GiantStepFile).length(); zz_pX last; if (gs > l+1) Error("bad arg to FetchGiantStep"); if (gs == l+1) { last = (*GiantStepFile)(l); if (F.n < OldN) { rem(last, last, F); for (long i = 0; i < (*HHH).H.length(); i++) rem((*HHH).H[i], (*HHH).H[i], F); OldN = F.n; } (*GiantStepFile).SetLength(l+1); CompMod((*GiantStepFile)(l+1), last, *HHH, F); g = (*GiantStepFile)(l+1); } else if (deg((*GiantStepFile)(gs)) >= F.n) rem(g, (*GiantStepFile)(gs), F); else g = (*GiantStepFile)(gs); } static void FetchBabySteps(vec_zz_pX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { v[i] = (*BabyStepFile)(i); } } static void GiantRefine(vec_pair_zz_pX_long& u, const zz_pX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_zz_pX BabyStep; FetchBabySteps(BabyStep, k); vec_zz_pX buf(INIT_SIZE, zz_pX_GCDTableSize); zz_pX f; f = ff; zz_pXModulus F; build(F, f); zz_pX g; zz_pX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); sub(buf[size-1], g, BabyStep[bs]); } else { sub(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == zz_pX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_zz_pX_long& factors, const zz_pX& ff, long k, long gs, const vec_zz_pX& BabyStep, long verbose) { vec_zz_pX buf(INIT_SIZE, zz_pX_GCDTableSize); zz_pX f; f = ff; zz_pXModulus F; build(F, f); zz_pX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); sub(buf[size], buf[size], g); size++; if (size == zz_pX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_zz_pX_long& factors, const vec_pair_zz_pX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_zz_pX BabyStep; long i; for (i = 0; i < u.length(); i++) { const zz_pX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h, long verbose) { if (!IsOne(LeadCoeff(f))) Error("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; zz_pX h1; GenerateBabySteps(h1, f, h, k, verbose); GenerateGiantSteps(f, h1, l, verbose); vec_pair_zz_pX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); FileCleanup(k, l); } NTL_END_IMPL ntl-6.2.1/src/mach_desc.win000644 000765 000024 00000041745 12377144457 016063 0ustar00shoupstaff000000 000000 #ifndef NTL_mach_desc__H #define NTL_mach_desc__H #define NTL_BITS_PER_LONG (32) #define NTL_MAX_LONG (2147483647L) #define NTL_MAX_INT (2147483647) #define NTL_BITS_PER_INT (32) #define NTL_BITS_PER_SIZE_T (32) #define NTL_ARITH_RIGHT_SHIFT (1) #define NTL_NBITS_MAX (30) #define NTL_DOUBLE_PRECISION (53) #define NTL_FDOUBLE_PRECISION (((double)(1L<<30))*((double)(1L<<22))) #define NTL_QUAD_FLOAT_SPLIT ((((double)(1L<<27)))+1.0) #define NTL_EXT_DOUBLE (0) #define NTL_SINGLE_MUL_OK (1) #define NTL_DOUBLES_LOW_HIGH (1) #define NTL_BB_MUL_CODE0 \ _ntl_ulong hi, lo, t;\ _ntl_ulong A[8];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ lo = A[b & 7]; t = A[(b >> 3) & 7]; hi = t >> 29; lo ^= t << 3;\ t = A[(b >> 6) & 7]; hi ^= t >> 26; lo ^= t << 6;\ t = A[(b >> 9) & 7]; hi ^= t >> 23; lo ^= t << 9;\ t = A[(b >> 12) & 7]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 15) & 7]; hi ^= t >> 17; lo ^= t << 15;\ t = A[(b >> 18) & 7]; hi ^= t >> 14; lo ^= t << 18;\ t = A[(b >> 21) & 7]; hi ^= t >> 11; lo ^= t << 21;\ t = A[(b >> 24) & 7]; hi ^= t >> 8; lo ^= t << 24;\ t = A[(b >> 27) & 7]; hi ^= t >> 5; lo ^= t << 27;\ t = A[b >> 30]; hi ^= t >> 2; lo ^= t << 30;\ if (a >> 31) hi ^= ((b & 0xb6db6db6UL) >> 1);\ if ((a >> 30) & 1) hi ^= ((b & 0x24924924UL) >> 2);\ c[0] = lo; c[1] = hi;\ #define NTL_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ if (a >> 31) hi ^= ((b & 0xeeeeeeeeUL) >> 1);\ if ((a >> 30) & 1) hi ^= ((b & 0xccccccccUL) >> 2);\ if ((a >> 29) & 1) hi ^= ((b & 0x88888888UL) >> 3);\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_BB_MUL_CODE2 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ if (a >> 31) hi ^= ((b & 0xeeeeeeeeUL) >> 1);\ if ((a >> 30) & 1) hi ^= ((b & 0xccccccccUL) >> 2);\ if ((a >> 29) & 1) hi ^= ((b & 0x88888888UL) >> 3);\ cp[i] ^= (carry ^ lo); carry = hi;\ }\ cp[sb] ^= carry;\ #define NTL_SHORT_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_HALF_BB_MUL_CODE0 \ _ntl_ulong hi, lo, t;\ _ntl_ulong A[4];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ lo = A[b & 3]; t = A[(b >> 2) & 3]; hi = t >> 30; lo ^= t << 2;\ t = A[(b >> 4) & 3]; hi ^= t >> 28; lo ^= t << 4;\ t = A[(b >> 6) & 3]; hi ^= t >> 26; lo ^= t << 6;\ t = A[(b >> 8) & 3]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 10) & 3]; hi ^= t >> 22; lo ^= t << 10;\ t = A[(b >> 12) & 3]; hi ^= t >> 20; lo ^= t << 12;\ t = A[b >> 14]; hi ^= t >> 18; lo ^= t << 14;\ if (a >> 31) hi ^= ((b & 0xaaaaUL) >> 1);\ c[0] = lo; c[1] = hi;\ #define NTL_ALT_BB_MUL_CODE0 \ _ntl_ulong A[8];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ const _ntl_ulong t3 = A[(b >> 3) & 7]; \ const _ntl_ulong t6 = A[(b >> 6) & 7]; \ const _ntl_ulong t9 = A[(b >> 9) & 7]; \ const _ntl_ulong t12 = A[(b >> 12) & 7]; \ const _ntl_ulong t15 = A[(b >> 15) & 7]; \ const _ntl_ulong t18 = A[(b >> 18) & 7]; \ const _ntl_ulong t21 = A[(b >> 21) & 7]; \ const _ntl_ulong t24 = A[(b >> 24) & 7]; \ const _ntl_ulong t27 = A[(b >> 27) & 7]; \ const _ntl_ulong t30 = A[b >> 30]; \ const _ntl_ulong lo = A[b & 7] \ ^ (t3 << 3)\ ^ (t6 << 6)\ ^ (t9 << 9)\ ^ (t12 << 12)\ ^ (t15 << 15)\ ^ (t18 << 18)\ ^ (t21 << 21)\ ^ (t24 << 24)\ ^ (t27 << 27)\ ^ (t30 << 30);\ const _ntl_ulong hi = (t3 >> 29)\ ^ (t6 >> 26)\ ^ (t9 >> 23)\ ^ (t12 >> 20)\ ^ (t15 >> 17)\ ^ (t18 >> 14)\ ^ (t21 >> 11)\ ^ (t24 >> 8)\ ^ (t27 >> 5)\ ^ (t30 >> 2)\ ^ (((b & 0xb6db6db6UL) >> 1) & (-(a >> 31)))\ ^ (((b & 0x24924924UL) >> 2) & (-((a >> 30) & 1UL)));\ c[0] = lo; c[1] = hi;\ #define NTL_ALT_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ const _ntl_ulong b = bp[i];\ const _ntl_ulong t4 = A[(b >> 4) & 15]; \ const _ntl_ulong t8 = A[(b >> 8) & 15]; \ const _ntl_ulong t12 = A[(b >> 12) & 15]; \ const _ntl_ulong t16 = A[(b >> 16) & 15]; \ const _ntl_ulong t20 = A[(b >> 20) & 15]; \ const _ntl_ulong t24 = A[(b >> 24) & 15]; \ const _ntl_ulong t28 = A[b >> 28]; \ const _ntl_ulong lo = A[b & 15] \ ^ (t4 << 4)\ ^ (t8 << 8)\ ^ (t12 << 12)\ ^ (t16 << 16)\ ^ (t20 << 20)\ ^ (t24 << 24)\ ^ (t28 << 28);\ const _ntl_ulong hi = (t4 >> 28)\ ^ (t8 >> 24)\ ^ (t12 >> 20)\ ^ (t16 >> 16)\ ^ (t20 >> 12)\ ^ (t24 >> 8)\ ^ (t28 >> 4)\ ^ (((b & 0xeeeeeeeeUL) >> 1) & (-(a >> 31)))\ ^ (((b & 0xccccccccUL) >> 2) & (-((a >> 30) & 1UL)))\ ^ (((b & 0x88888888UL) >> 3) & (-((a >> 29) & 1UL)));\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_ALT_BB_MUL_CODE2 \ long i;\ _ntl_ulong carry = 0;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ const _ntl_ulong b = bp[i];\ const _ntl_ulong t4 = A[(b >> 4) & 15]; \ const _ntl_ulong t8 = A[(b >> 8) & 15]; \ const _ntl_ulong t12 = A[(b >> 12) & 15]; \ const _ntl_ulong t16 = A[(b >> 16) & 15]; \ const _ntl_ulong t20 = A[(b >> 20) & 15]; \ const _ntl_ulong t24 = A[(b >> 24) & 15]; \ const _ntl_ulong t28 = A[b >> 28]; \ const _ntl_ulong lo = A[b & 15] \ ^ (t4 << 4)\ ^ (t8 << 8)\ ^ (t12 << 12)\ ^ (t16 << 16)\ ^ (t20 << 20)\ ^ (t24 << 24)\ ^ (t28 << 28);\ const _ntl_ulong hi = (t4 >> 28)\ ^ (t8 >> 24)\ ^ (t12 >> 20)\ ^ (t16 >> 16)\ ^ (t20 >> 12)\ ^ (t24 >> 8)\ ^ (t28 >> 4)\ ^ (((b & 0xeeeeeeeeUL) >> 1) & (-(a >> 31)))\ ^ (((b & 0xccccccccUL) >> 2) & (-((a >> 30) & 1UL)))\ ^ (((b & 0x88888888UL) >> 3) & (-((a >> 29) & 1UL)));\ cp[i] ^= (carry ^ lo); carry = hi;\ }\ cp[sb] ^= carry;\ #define NTL_ALT_SHORT_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ const _ntl_ulong b = bp[i];\ const _ntl_ulong t4 = A[(b >> 4) & 15]; \ const _ntl_ulong t8 = A[(b >> 8) & 15]; \ const _ntl_ulong t12 = A[(b >> 12) & 15]; \ const _ntl_ulong t16 = A[(b >> 16) & 15]; \ const _ntl_ulong t20 = A[(b >> 20) & 15]; \ const _ntl_ulong t24 = A[(b >> 24) & 15]; \ const _ntl_ulong t28 = A[b >> 28]; \ const _ntl_ulong lo = A[b & 15] \ ^ (t4 << 4)\ ^ (t8 << 8)\ ^ (t12 << 12)\ ^ (t16 << 16)\ ^ (t20 << 20)\ ^ (t24 << 24)\ ^ (t28 << 28);\ const _ntl_ulong hi = (t4 >> 28)\ ^ (t8 >> 24)\ ^ (t12 >> 20)\ ^ (t16 >> 16)\ ^ (t20 >> 12)\ ^ (t24 >> 8)\ ^ (t28 >> 4);\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_ALT_HALF_BB_MUL_CODE0 \ _ntl_ulong A[4];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ const _ntl_ulong t2 = A[(b >> 2) & 3]; \ const _ntl_ulong t4 = A[(b >> 4) & 3]; \ const _ntl_ulong t6 = A[(b >> 6) & 3]; \ const _ntl_ulong t8 = A[(b >> 8) & 3]; \ const _ntl_ulong t10 = A[(b >> 10) & 3]; \ const _ntl_ulong t12 = A[(b >> 12) & 3]; \ const _ntl_ulong t14 = A[b >> 14]; \ const _ntl_ulong lo = A[b & 3] \ ^ (t2 << 2)\ ^ (t4 << 4)\ ^ (t6 << 6)\ ^ (t8 << 8)\ ^ (t10 << 10)\ ^ (t12 << 12)\ ^ (t14 << 14);\ const _ntl_ulong hi = (t2 >> 30)\ ^ (t4 >> 28)\ ^ (t6 >> 26)\ ^ (t8 >> 24)\ ^ (t10 >> 22)\ ^ (t12 >> 20)\ ^ (t14 >> 18)\ ^ (((b & 0xaaaaUL) >> 1) & (-(a >> 31)));\ c[0] = lo; c[1] = hi;\ #define NTL_ALT1_BB_MUL_CODE0 \ _ntl_ulong hi, lo, t;\ _ntl_ulong A[8];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ lo = A[b & 7]; t = A[(b >> 3) & 7]; hi = t >> 29; lo ^= t << 3;\ t = A[(b >> 6) & 7]; hi ^= t >> 26; lo ^= t << 6;\ t = A[(b >> 9) & 7]; hi ^= t >> 23; lo ^= t << 9;\ t = A[(b >> 12) & 7]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 15) & 7]; hi ^= t >> 17; lo ^= t << 15;\ t = A[(b >> 18) & 7]; hi ^= t >> 14; lo ^= t << 18;\ t = A[(b >> 21) & 7]; hi ^= t >> 11; lo ^= t << 21;\ t = A[(b >> 24) & 7]; hi ^= t >> 8; lo ^= t << 24;\ t = A[(b >> 27) & 7]; hi ^= t >> 5; lo ^= t << 27;\ t = A[b >> 30]; hi ^= t >> 2; lo ^= t << 30;\ hi ^= (((b & 0xb6db6db6UL) >> 1) & (-(a >> 31)))\ ^ (((b & 0x24924924UL) >> 2) & (-((a >> 30) & 1UL)));\ c[0] = lo; c[1] = hi;\ #define NTL_ALT1_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ hi ^= (((b & 0xeeeeeeeeUL) >> 1) & (-(a >> 31)))\ ^ (((b & 0xccccccccUL) >> 2) & (-((a >> 30) & 1UL)))\ ^ (((b & 0x88888888UL) >> 3) & (-((a >> 29) & 1UL)));\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_ALT1_BB_MUL_CODE2 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ hi ^= (((b & 0xeeeeeeeeUL) >> 1) & (-(a >> 31)))\ ^ (((b & 0xccccccccUL) >> 2) & (-((a >> 30) & 1UL)))\ ^ (((b & 0x88888888UL) >> 3) & (-((a >> 29) & 1UL)));\ cp[i] ^= (carry ^ lo); carry = hi;\ }\ cp[sb] ^= carry;\ #define NTL_ALT1_SHORT_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_ALT1_HALF_BB_MUL_CODE0 \ _ntl_ulong hi, lo, t;\ _ntl_ulong A[4];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ lo = A[b & 3]; t = A[(b >> 2) & 3]; hi = t >> 30; lo ^= t << 2;\ t = A[(b >> 4) & 3]; hi ^= t >> 28; lo ^= t << 4;\ t = A[(b >> 6) & 3]; hi ^= t >> 26; lo ^= t << 6;\ t = A[(b >> 8) & 3]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 10) & 3]; hi ^= t >> 22; lo ^= t << 10;\ t = A[(b >> 12) & 3]; hi ^= t >> 20; lo ^= t << 12;\ t = A[b >> 14]; hi ^= t >> 18; lo ^= t << 14;\ hi ^= (((b & 0xaaaaUL) >> 1) & (-(a >> 31)));\ c[0] = lo; c[1] = hi;\ #define NTL_BB_MUL1_BITS (4) #define NTL_BB_SQR_CODE \ lo=sqrtab[a&255];\ lo=lo|(sqrtab[(a>>8)&255]<<16);\ hi=sqrtab[(a>>16)&255];\ hi=hi|(sqrtab[(a>>24)&255]<<16);\ #define NTL_BB_REV_CODE (revtab[(a>>0)&255]<<24)\ |(revtab[(a>>8)&255]<<16)\ |(revtab[(a>>16)&255]<<8)\ |(revtab[(a>>24)&255]<<0) #define NTL_MIN_LONG (-NTL_MAX_LONG - 1L) #define NTL_MIN_INT (-NTL_MAX_INT - 1) #endif ntl-6.2.1/src/makefile000644 000765 000024 00000041752 12377144460 015126 0ustar00shoupstaff000000 000000 ############################################################### # # First, choose a C++ compiler, and set compiler flags. # This is done by setting the variables CXX and CXXFLAGS. # ############################################################### CXX=g++ # A C++ compiler, e.g., g++, CC, xlC CXXFLAGS=-O2 # Flags for the C++ compiler # Some useful flags: # -O2 -- recommended level of optimization # -m64 -- needed to get 64-bit longs on some platforms # -g -- debugging AR=ar # command to make a library ARFLAGS=ruv # arguments for AR RANLIB=ranlib # set to echo if you want to disable it completely LDFLAGS= # libraries for linking C++ programs LDLIBS=-lm # libraries for linking C++ programs CPPFLAGS= # arguments for the C preprocessor LIBTOOL=libtool # libtool command DEF_PREFIX=/usr/local PREFIX=$(DEF_PREFIX) LIBDIR=$(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include DOCDIR=$(PREFIX)/share/doc # where to install NTL ############################################################### # # Second, if you want to use GMP (the GNU Multi-Precision library), # define the variables GMP_OPT_INCDIR, GMP_OPT_LIBDIR, GMP_OPT_LIB below. # You also will have to set either NTL_GMP_LIP or NTL_GMP_HACK # in the config.h file. # # Using GMP can lead to significant performance gains on some # platforms. You can obtain GMP from http://www.swox.com/gmp. # Once you unpack it into a directory, just execute # ./configure; make # in that directory. # ############################################################### GMP_PREFIX=$(DEF_PREFIX) GMP_INCDIR=$(GMP_PREFIX)/include # directory containing gmp.h if using GMP GMP_LIBDIR=$(GMP_PREFIX)/lib # directory containing libgmp.a if using GMP GMP_OPT_INCDIR=# -I$(GMP_INCDIR) # GMPI GMP_OPT_LIBDIR=# -L$(GMP_LIBDIR) # GMPL GMP_OPT_LIB=# -lgmp # GMP # uncomment these if using GMP ############################################################### # # Third, if you want to use gf2x (a library for fast # multiplication over GF(2)[X]), you need to # define the variables GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, GF2X_OPT_LIB below. # You also will have to set NTL_GF2X_LIB # in the config.h file. # ############################################################### GF2X_PREFIX=$(DEF_PREFIX) GF2X_INCDIR=$(GF2X_PREFIX)/include # directory containing gf2x.h if using gf2x GF2X_LIBDIR=$(GF2X_PREFIX)/lib # directory containing libgf2x.a GF2X_OPT_INCDIR=# -I$(GF2X_INCDIR) # GF2X GF2X_OPT_LIBDIR=# -L$(GF2X_LIBDIR) # GF2X GF2X_OPT_LIB=# -lgf2x # GF2X # uncomment these if using gf2x ############################################################### # # Fourth, if you do not want to run the wizard that automagically # sets some performace related flags in config.h, set the flag below. # ############################################################### WIZARD=on # Set to off if you want to bypass the wizard; otherwise, set to on. ################################################################# # # That's it! You can ignore everything else in this file! # ################################################################# # object files O01=FFT.o FacVec.o GF2.o GF2E.o GF2EX.o GF2EXFactoring.o GF2X.o GF2X1.o O02=$(O01) GF2XFactoring.o GF2XVec.o GetTime.o HNF.o ctools.o LLL.o LLL_FP.o O03=$(O02) LLL_QP.o LLL_RR.o LLL_XD.o RR.o WordVector.o ZZ.o ZZVec.o O04=$(O03) ZZX.o ZZX1.o ZZXCharPoly.o ZZXFactoring.o ZZ_p.o ZZ_pE.o ZZ_pEX.o O05=$(O04) ZZ_pEXFactoring.o ZZ_pX.o ZZ_pX1.o ZZ_pXCharPoly.o ZZ_pXFactoring.o O06=$(O05) fileio.o lip.o lzz_p.o lzz_pE.o lzz_pEX.o lzz_pEXFactoring.o O07=$(O06) lzz_pX.o lzz_pX1.o lzz_pXCharPoly.o lzz_pXFactoring.o O08=$(O07) mat_GF2.o mat_GF2E.o mat_RR.o mat_ZZ.o mat_ZZ_p.o O09=$(O08) mat_ZZ_pE.o mat_lzz_p.o mat_lzz_pE.o mat_poly_ZZ.o O10=$(O09) mat_poly_ZZ_p.o mat_poly_lzz_p.o O11=$(O10) O12=$(O11) O13=$(O12) quad_float.o tools.o vec_GF2.o vec_GF2E.o O14=$(O13) vec_RR.o vec_ZZ.o vec_ZZ_p.o vec_ZZ_pE.o O15=$(O14) vec_lzz_p.o vec_lzz_pE.o O16=$(O15) O17=$(O16) O18=$(O17) xdouble.o O19=$(O18) G_LLL_FP.o G_LLL_QP.o G_LLL_XD.o G_LLL_RR.o OBJ=$(O19) # library source files S01=FFT.c FacVec.c GF2.c GF2E.c GF2EX.c GF2EXFactoring.c GF2X.c GF2X1.c S02=$(S01) GF2XFactoring.c GF2XVec.c HNF.c ctools.c LLL.c LLL_FP.c LLL_QP.c S03=$(S02) LLL_RR.c LLL_XD.c RR.c WordVector.c ZZ.c ZZVec.c ZZX.c ZZX1.c S04=$(S03) ZZXCharPoly.c ZZXFactoring.c ZZ_p.c ZZ_pE.c ZZ_pEX.c S05=$(S04) ZZ_pEXFactoring.c ZZ_pX.c ZZ_pX1.c ZZ_pXCharPoly.c S06=$(S05) ZZ_pXFactoring.c fileio.c lip.c lzz_p.c lzz_pE.c lzz_pEX.c S07=$(S06) lzz_pEXFactoring.c lzz_pX.c lzz_pX1.c S08=$(S07) lzz_pXCharPoly.c lzz_pXFactoring.c mat_GF2.c mat_GF2E.c S09=$(S08) mat_RR.c mat_ZZ.c mat_ZZ_p.c mat_ZZ_pE.c mat_lzz_p.c mat_lzz_pE.c S10=$(S09) mat_poly_ZZ.c mat_poly_ZZ_p.c mat_poly_lzz_p.c S11=$(S10) S12=$(S11) S13=$(S12) quad_float.c tools.c vec_GF2.c vec_GF2E.c vec_RR.c S14=$(S13) vec_ZZ.c vec_ZZ_p.c vec_ZZ_pE.c S15=$(S14) vec_lzz_p.c vec_lzz_pE.c S16=$(S15) S17=$(S16) S18=$(S17) xdouble.c S19=$(S18) G_LLL_FP.c G_LLL_QP.c G_LLL_XD.c G_LLL_RR.c SRC = $(S19) # library source files that are header files SINC = c_lip_impl.h g_lip_impl.h # library header files IN01= FFT.h FacVec.h GF2.h GF2E.h GF2EX.h GF2EXFactoring.h GF2X.h IN02=$(IN01) GF2XFactoring.h GF2XVec.h HNF.h ctools.h LLL.h IN03=$(IN02) RR.h SPMM_ASM.h WordVector.h ZZ.h ZZVec.h ZZX.h ZZXFactoring.h IN04=$(IN03) ZZ_p.h ZZ_pE.h ZZ_pEX.h ZZ_pEXFactoring.h ZZ_pX.h ZZ_pXFactoring.h IN05=$(IN04) fileio.h lip.h lzz_p.h lzz_pE.h lzz_pEX.h lzz_pEXFactoring.h IN06=$(IN05) lzz_pX.h lzz_pXFactoring.h mat_GF2.h mat_GF2E.h mat_RR.h IN07=$(IN06) mat_ZZ.h mat_ZZ_p.h mat_ZZ_pE.h mat_lzz_p.h mat_lzz_pE.h IN08=$(IN07) mat_poly_ZZ.h mat_poly_ZZ_p.h mat_poly_lzz_p.h matrix.h IN09=$(IN08) pair.h vector.h pair_GF2EX_long.h pair_GF2X_long.h IN10=$(IN09) pair_ZZX_long.h pair_ZZ_pEX_long.h pair_ZZ_pX_long.h IN11=$(IN10) pair_lzz_pEX_long.h pair_lzz_pX_long.h quad_float.h IN12=$(IN11) tools.h vec_GF2.h vec_GF2E.h vec_GF2XVec.h vec_RR.h IN13=$(IN12) vec_ZZ.h vec_ZZVec.h vec_ZZ_p.h vec_ZZ_pE.h vec_double.h IN14=$(IN13) vec_long.h vec_lzz_p.h vec_lzz_pE.h vec_quad_float.h IN15=$(IN14) vec_vec_GF2.h vec_vec_GF2E.h vec_vec_RR.h vec_vec_ZZ.h IN16=$(IN15) vec_vec_ZZ_p.h vec_vec_ZZ_pE.h vec_vec_long.h vec_vec_lzz_p.h IN17=$(IN16) vec_vec_lzz_pE.h vec_xdouble.h xdouble.h config.h version.h IN18=$(IN17) def_config.h new.h vec_ulong.h vec_vec_ulong.h c_lip.h g_lip.h INCL=$(IN18) # test data TD1=BerlekampTestIn BerlekampTestOut CanZassTestIn CanZassTestOut TD2=$(TD1) ZZXFacTestIn ZZXFacTestOut MoreFacTestIn LLLTestIn LLLTestOut RRTestIn RRTestOut TD3=$(TD2) MatrixTestIn MatrixTestOut CharPolyTestIn TD4=$(TD3) CharPolyTestOut QuadTestIn QuadTestOut TD = $(TD4) # test source files TS1=QuickTest.c BerlekampTest.c CanZassTest.c ZZXFacTest.c MoreFacTest.c LLLTest.c TS2=$(TS1) subset.c MatrixTest.c CharPolyTest.c RRTest.c QuadTest.c TS3=$(TS2) GF2XTest.c GF2EXTest.c BitMatTest.c ZZ_pEXTest.c lzz_pEXTest.c Timing.c TS = $(TS3) # scripts SCRIPTS1=MakeGetTime TestScript dosify unixify RemoveProg SCRIPTS2=$(SCRIPTS1) configure DoConfig mfile cfile ppscript SCRIPTS=$(SCRIPTS2) # auxilliary source MD=MakeDesc.c MakeDescAux.c newnames.c gen_gmp_aux.c GT=GetTime1.c GetTime2.c GetTime3.c GetTime4.c GetTime5.c TestGetTime.c # documentation D01=copying.txt GF2.txt GF2E.txt GF2EX.txt GF2EXFactoring.txt GF2X.txt D02=$(D01) GF2XFactoring.txt GF2XVec.txt HNF.txt LLL.txt RR.txt D03=$(D02) ZZ.txt ZZVec.txt ZZX.txt ZZXFactoring.txt ZZ_p.txt ZZ_pE.txt D04=$(D03) ZZ_pEX.txt ZZ_pEXFactoring.txt ZZ_pX.txt ZZ_pXFactoring.txt D05=$(D04) conversions.txt flags.txt lzz_p.txt lzz_pE.txt lzz_pEX.txt D06=$(D05) lzz_pEXFactoring.txt lzz_pX.txt lzz_pXFactoring.txt mat_GF2.txt D07=$(D06) mat_GF2E.txt mat_RR.txt mat_ZZ.txt mat_ZZ_p.txt mat_ZZ_pE.txt D08=$(D07) mat_lzz_p.txt mat_lzz_pE.txt mat_poly_ZZ.txt mat_poly_ZZ_p.txt D09=$(D08) mat_poly_lzz_p.txt matrix.txt pair.txt vector.txt D10=$(D09) quad_float.txt sedscript.txt tools.txt vec_GF2.txt D11=$(D10) vec_GF2E.txt vec_RR.txt vec_ZZ.txt vec_ZZ_p.txt vec_ZZ_pE.txt D12=$(D11) vec_lzz_p.txt vec_lzz_pE.txt xdouble.txt names.txt D13=$(D12) tour-ack.html tour-intro.html tour-time.html tour-changes.html D14=$(D13) tour-modules.html tour-stdcxx.html tour-unix.html tour-examples.html D15=$(D14) tour-roadmap.html tour-win.html tour-impl.html tour-struct.html D16=$(D15) tour.html tour-ex1.html tour-ex2.html tour-ex3.html tour-ex4.html D17=$(D16) tour-ex5.html tour-ex6.html arrow1.gif arrow2.gif arrow3.gif D18=$(D17) tour-gmp.html tour-gf2x.html tour-tips.html config.txt version.txt TX01=GF2.txt GF2E.txt GF2EX.txt GF2EXFactoring.txt GF2X.txt GF2XFactoring.txt TX02=GF2XVec.txt HNF.txt LLL.txt RR.txt ZZ.txt ZZVec.txt ZZX.txt ZZXFactoring.txt TX03=ZZ_p.txt ZZ_pE.txt ZZ_pEX.txt ZZ_pEXFactoring.txt ZZ_pX.txt ZZ_pXFactoring.txt TX04=lzz_p.txt lzz_pE.txt lzz_pEX.txt lzz_pEXFactoring.txt lzz_pX.txt TX05=lzz_pXFactoring.txt mat_GF2.txt mat_GF2E.txt mat_RR.txt mat_ZZ.txt mat_ZZ_p.txt TX06=mat_ZZ_pE.txt mat_lzz_p.txt mat_lzz_pE.txt mat_poly_ZZ.txt mat_poly_ZZ_p.txt TX07=mat_poly_lzz_p.txt matrix.txt pair.txt quad_float.txt tools.txt vec_GF2.txt TX08=vec_GF2E.txt vec_RR.txt vec_ZZ.txt vec_ZZ_p.txt vec_ZZ_pE.txt vec_lzz_p.txt TX09=vec_lzz_pE.txt vector.txt version.txt xdouble.txt TXFILES=$(TX01) $(TX02) $(TX03) $(TX04) $(TX05) $(TX06) $(TX07) $(TX08) $(TX09) HT01=GF2.cpp.html GF2E.cpp.html GF2EX.cpp.html GF2EXFactoring.cpp.html GF2X.cpp.html GF2XFactoring.cpp.html HT02=GF2XVec.cpp.html HNF.cpp.html LLL.cpp.html RR.cpp.html ZZ.cpp.html ZZVec.cpp.html ZZX.cpp.html ZZXFactoring.cpp.html HT03=ZZ_p.cpp.html ZZ_pE.cpp.html ZZ_pEX.cpp.html ZZ_pEXFactoring.cpp.html ZZ_pX.cpp.html ZZ_pXFactoring.cpp.html HT04=lzz_p.cpp.html lzz_pE.cpp.html lzz_pEX.cpp.html lzz_pEXFactoring.cpp.html lzz_pX.cpp.html HT05=lzz_pXFactoring.cpp.html mat_GF2.cpp.html mat_GF2E.cpp.html mat_RR.cpp.html mat_ZZ.cpp.html mat_ZZ_p.cpp.html HT06=mat_ZZ_pE.cpp.html mat_lzz_p.cpp.html mat_lzz_pE.cpp.html mat_poly_ZZ.cpp.html mat_poly_ZZ_p.cpp.html HT07=mat_poly_lzz_p.cpp.html matrix.cpp.html pair.cpp.html quad_float.cpp.html tools.cpp.html vec_GF2.cpp.html HT08=vec_GF2E.cpp.html vec_RR.cpp.html vec_ZZ.cpp.html vec_ZZ_p.cpp.html vec_ZZ_pE.cpp.html vec_lzz_p.cpp.html HT09=vec_lzz_pE.cpp.html vector.cpp.html version.cpp.html xdouble.cpp.html HTFILES=$(HT01) $(HT02) $(HT03) $(HT04) $(HT05) $(HT06) $(HT07) $(HT08) $(HT09) DOC = $(D18) $(HTFILES) # test program executables PROG1=QuickTest BerlekampTest CanZassTest ZZXFacTest MoreFacTest LLLTest BitMatTest PROG2=$(PROG1) MatrixTest CharPolyTest RRTest QuadTest PROG3=$(PROG2) GF2XTest GF2EXTest subset ZZ_pEXTest lzz_pEXTest Timing PROGS = $(PROG3) # things to save to a tar file SFI1=makefile $(SRC) $(SINC) $(SCRIPTS) $(MD) $(GT) $(TS) $(TD) mach_desc.win SFI2=$(SFI1) MulTimeTest.c PolyTimeTest.c Poly1TimeTest.c GF2XTimeTest.c SFI3=$(SFI2) InitSettings.c DispSettings.c WizardAux Wizard def_makefile SFILES=$(SFI3) ################################################################# # # Rules for compiling the library # ################################################################# NTL_INCLUDE = -I../include -I. # NTL needs this to find its include files COMPILE = $(CXX) $(NTL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) -c LINK = $(CXX) $(NTL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) # 'make all' does a complete make, including all setup. # It also creates the file 'all', which means you should # run 'make clobber' before running 'make' or 'make all' # again. all: make setup1 make setup2 make setup3 make setup4 make ntl.a touch all # setup1 generates the file ../incluse/NTL/mach_desc.h setup1: $(COMPILE) MakeDescAux.c $(LINK) -o MakeDesc MakeDesc.c MakeDescAux.o $(LDLIBS) ./MakeDesc mv mach_desc.h ../include/NTL/mach_desc.h # setup2 generates the file GetTime.c setup2: sh MakeGetTime "$(LINK)" "$(LDLIBS)" # setup3 generates the file ../include/NTL/gmp_aux.h # The file ../include/NTL/gmp_aux.h is included in ../include/NTL/lip.h # when NTL_GMP_LIP is set. # When this flag is not set, an empty files produced. setup3: $(LINK) $(GMP_OPT_INCDIR) -o gen_gmp_aux gen_gmp_aux.c $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) ./gen_gmp_aux > ../include/NTL/gmp_aux.h # setup4 runs the wizard setup4: sh Wizard $(WIZARD) ntl.a: $(OBJ) $(AR) $(ARFLAGS) ntl.a $(OBJ) #LSTAT - $(RANLIB) ntl.a #LSTAT # $(LIBTOOL) --mode=link $(LINK) -o libntl.la $(OBJ:.o=.lo) $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) -rpath $(LIBDIR) -version-info `cat VERSION_INFO` #LSHAR LCOMP= #LSTAT # LCOMP=$(LIBTOOL) --mode=compile #LSHAR lip.o: lip.c g_lip_impl.h c_lip_impl.h $(LCOMP) $(COMPILE) $(GMP_OPT_INCDIR) lip.c ctools.o: ctools.c $(LCOMP) $(COMPILE) ctools.c GetTime.o: GetTime.c $(LCOMP) $(COMPILE) GetTime.c .c.o: $(LCOMP) $(COMPILE) $(GF2X_OPT_INCDIR) $< .c: $(LINK) -o $@ $< ntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) #LSTAT # $(LIBTOOL) --mode=link $(LINK) -o $@ $< libntl.la #LSHAR ################################################################# # # Rule for running tests # make check runs a series of tests # ################################################################# check: sh RemoveProg $(PROGS) make QuickTest ./QuickTest sh RemoveProg QuickTest sh TestScript ################################################################# # # Rule for installing # make install just does a simple copy of the include file # and library. The -p option is used to preserve file attributes. # This helps avoid some problems (especially when copying ntl.a). # Also, an attempt is made to make everything that is # installed readable by everyone. # # make uninstall removes these files # ################################################################# install: mkdir -p -m 755 $(INCLUDEDIR) rm -rf $(INCLUDEDIR)/NTL mkdir -m 755 $(INCLUDEDIR)/NTL cp -p ../include/NTL/*.h $(INCLUDEDIR)/NTL - chmod -R a+r $(INCLUDEDIR)/NTL mkdir -p -m 755 $(DOCDIR) rm -rf $(DOCDIR)/NTL mkdir -m 755 $(DOCDIR)/NTL cp -p ../doc/*.txt $(DOCDIR)/NTL cp -p ../doc/*.html $(DOCDIR)/NTL cp -p ../doc/*.gif $(DOCDIR)/NTL - chmod -R a+r $(DOCDIR)/NTL mkdir -p -m 755 $(LIBDIR) cp -p ntl.a $(LIBDIR)/libntl.a #LSTAT - chmod a+r $(LIBDIR)/libntl.a #LSTAT # $(LIBTOOL) --mode=install cp -p libntl.la $(LIBDIR) #LSHAR uninstall: rm -f $(LIBDIR)/libntl.a #LSTAT # $(LIBTOOL) --mode=uninstall rm -f $(LIBDIR)/libntl.la #LSHAR rm -rf $(INCLUDEDIR)/NTL rm -rf $(DOCDIR)/NTL ################################################################# # # Rules for cleaning up # # make clobber removes *everything* created by make, # but it does not restore config.h to its default. # # make clean tidies up a bit # ################################################################# clobber: rm -f ntl.a mach_desc.h ../include/NTL/mach_desc.h GetTime.c rm -f ../include/NTL/gmp_aux.h sh RemoveProg $(PROGS) MakeDesc TestGetTime gen_gmp_aux rm -f *.o rm -rf small rm -f cfileout mfileout rm -rf .libs *.lo libntl.la rm -f all clean: sh RemoveProg MakeDesc TestGetTime gen_gmp_aux rm -f *.o rm -rf small # - $(LIBTOOL) --mode=clean rm -f libntl.la *.lo #LSHAR ################################################################# # # Rules for making tar and zip files # # make ppdoc creates pretty-printed versions of some documentation # - run before make package or make winpack # # make package creates a tar.gz file suitable for Unix # # make winpack creates a zip file suitable for Windows # ################################################################# ppdoc: sh ppscript "$(TXFILES)" package: sh unixify "$(SFILES) DIRNAME WINDIR VERSION_INFO NOTES" "$(INCL)" "$(DOC)" rm -rf `cat DIRNAME` rm -f `cat DIRNAME`.tar rm -f `cat DIRNAME`.tar.gz mv unix `cat DIRNAME` chmod -R a+rX `cat DIRNAME` tar -cvf `cat DIRNAME`.tar `cat DIRNAME` gzip `cat DIRNAME`.tar rm -rf `cat DIRNAME` winpack: sh dosify "$(SRC)" "$(INCL)" "$(DOC)" "$(TS)" "$(TD)" "$(SINC)" rm -rf `cat WINDIR` rm -f `cat WINDIR`.zip mv dos `cat WINDIR` chmod -R a+rX `cat WINDIR` find ./`cat WINDIR` '!' -name '*.gif' -print | zip -l `cat WINDIR` -@ find ./`cat WINDIR` -name '*.gif' -print | zip -u `cat WINDIR` -@ rm -rf `cat WINDIR` ###################################################################### # # config wizard related stuff # ###################################################################### WO1 = FFT.o GetTime.o ctools.o ZZ.o ZZVec.o ZZ_p.o ZZ_pX.o WO2 = $(WO1) ZZ_pX1.o lip.o tools.o vec_ZZ.o vec_ZZ_p.o WO3 = $(WO2) GF2.o WordVector.o vec_GF2.o GF2X.o GF2X1.o WOBJ = $(WO3) # wntl.a: LCOMP= #LSHAR wntl.a: $(WOBJ) $(AR) $(ARFLAGS) wntl.a $(WOBJ) - $(RANLIB) wntl.a MulTimeTest: $(LINK) -o MulTimeTest MulTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) PolyTimeTest: $(LINK) -o PolyTimeTest PolyTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) Poly1TimeTest: $(LINK) -o Poly1TimeTest Poly1TimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) GF2XTimeTest: $(LINK) -o GF2XTimeTest GF2XTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) InitSettings: $(LINK) -o InitSettings InitSettings.c $(LDLIBS) DispSettings: $(LINK) -o DispSettings DispSettings.c $(LDLIBS) ntl-6.2.1/src/mat_GF2.c000644 000765 000024 00000030534 12377144456 015012 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long mw = (m + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long i; for (i = 0; i < n; i++) { _ntl_ulong *xp = X[i].rep.elts(); const _ntl_ulong *ap = A[i].rep.elts(); const _ntl_ulong *bp = B[i].rep.elts(); long j; for (j = 0; j < mw; j++) xp[j] = ap[j] ^ bp[j]; } } static void mul_aux(vec_GF2& x, const mat_GF2& A, const vec_GF2& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) { x.put(i, A[i] * b); } } void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b) { if (&b == &x || A.position1(x) != -1) { vec_GF2 tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_GF2& x, const vec_GF2& a, const mat_GF2& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); clear(x); const _ntl_ulong *ap = a.rep.elts(); _ntl_ulong a_mask = 1; _ntl_ulong *xp = x.rep.elts(); long lw = (l + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long i; for (i = 0; i < n; i++) { if (*ap & a_mask) { const _ntl_ulong *bp = B[i].rep.elts(); long j; for (j = 0; j < lw; j++) xp[j] ^= bp[j]; } a_mask <<= 1; if (!a_mask) { a_mask = 1; ap++; } } } void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B) { if (&a == &x || B.position1(x) != -1) { vec_GF2 tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void mul_aux(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); long i; for (i = 1; i <= n; i++) { mul_aux(X(i), A(i), B); } } void mul(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { if (&X == &A || &X == &B) { mat_GF2 tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } void ident(mat_GF2& X, long n) { X.SetDims(n, n); clear(X); long i; for (i = 0; i < n; i++) X.put(i, i, to_GF2(1)); } void determinant(ref_GF2 d, const mat_GF2& M_in) { long k, n; long i, j; long pos; n = M_in.NumRows(); if (M_in.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } mat_GF2 M; M = M_in; long wn = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } set(d); return; } static long IsUnitVector(const vec_GF2& a, long i) { long wi = i/NTL_BITS_PER_LONG; long bi = i - wi*NTL_BITS_PER_LONG; const _ntl_ulong *p = a.rep.elts(); long wdlen = a.rep.length(); long j; for (j = 0; j < wi; j++) if (p[j] != 0) return 0; if (p[wi] != (1UL << bi)) return 0; for (j = wi+1; j < wdlen; j++) if (p[j] != 0) return 0; return 1; } long IsIdent(const mat_GF2& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; if (n == 0) return 1; long i; for (i = 0; i < n; i++) if (!IsUnitVector(A[i], i)) return 0; return 1; } void AddToCol(mat_GF2& x, long j, const vec_GF2& a) // add a to column j of x // ALIAS RESTRICTION: a should not alias any row of x { long n = x.NumRows(); long m = x.NumCols(); if (a.length() != n || j < 0 || j >= m) Error("AddToCol: bad args"); long wj = j/NTL_BITS_PER_LONG; long bj = j - wj*NTL_BITS_PER_LONG; _ntl_ulong j_mask = 1UL << bj; const _ntl_ulong *ap = a.rep.elts(); _ntl_ulong a_mask = 1; long i; for (i = 0; i < n; i++) { if (*ap & a_mask) x[i].rep.elts()[wj] ^= j_mask; a_mask <<= 1; if (!a_mask) { a_mask = 1; ap++; } } } void transpose_aux(mat_GF2& X, const mat_GF2& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(m, n); clear(X); long i; for (i = 0; i < n; i++) AddToCol(X, i, A[i]); } void transpose(mat_GF2& X, const mat_GF2& A) { if (&X == &A) { mat_GF2 tmp; transpose_aux(tmp, A); X = tmp; } else transpose_aux(X, A); } void solve(ref_GF2 d, vec_GF2& X, const mat_GF2& A, const vec_GF2& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { X.SetLength(0); set(d); return; } long i, j, k, pos; mat_GF2 M; M.SetDims(n, n+1); for (i = 0; i < n; i++) { AddToCol(M, i, A[i]); } AddToCol(M, n, b); long wn = ((n+1) + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } vec_GF2 XX; XX.SetLength(n+1); XX.put(n, 1); for (i = n-1; i >= 0; i--) { XX.put(i, XX*M[i]); } XX.SetLength(n); X = XX; set(d); return; } void inv(ref_GF2 d, mat_GF2& X, const mat_GF2& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (n == 0) { X.SetDims(0, 0); set(d); } long i, j, k, pos; mat_GF2 M; M.SetDims(n, 2*n); vec_GF2 aa; aa.SetLength(2*n); for (i = 0; i < n; i++) { aa = A[i]; aa.SetLength(2*n); aa.put(n+i, 1); M[i] = aa; } long wn = ((2*n) + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } vec_GF2 XX; XX.SetLength(2*n); X.SetDims(n, n); clear(X); for (j = 0; j < n; j++) { XX.SetLength(n+j+1); clear(XX); XX.put(n+j, to_GF2(1)); for (i = n-1; i >= 0; i--) { XX.put(i, XX*M[i]); } XX.SetLength(n); AddToCol(X, j, XX); } set(d); return; } long gauss(mat_GF2& M, long w) { long k, l; long i, j; long pos; long n = M.NumRows(); long m = M.NumCols(); if (w < 0 || w > m) Error("gauss: bad args"); long wm = (m + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; l = 0; for (k = 0; k < w && l < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = l; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (l != pos) swap(M[pos], M[l]); _ntl_ulong *y = M[l].rep.elts(); for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wm; j++) x[j] ^= y[j]; } } l++; } } return l; } long gauss(mat_GF2& M) { return gauss(M, M.NumCols()); } void image(mat_GF2& X, const mat_GF2& A) { mat_GF2 M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(mat_GF2& X, const mat_GF2& A) { long m = A.NumRows(); long n = A.NumCols(); mat_GF2 M; long r; transpose(M, A); r = gauss(M); X.SetDims(m-r, m); clear(X); long i, j, k; vec_long D; D.SetLength(m); for (j = 0; j < m; j++) D[j] = -1; j = -1; for (i = 0; i < r; i++) { do { j++; } while (M.get(i, j) == 0); D[j] = i; } for (k = 0; k < m-r; k++) { vec_GF2& v = X[k]; long pos = 0; for (j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) { v[j] = 1; // v.put(j, to_GF2(1)); } pos++; } else { v[j] = v*M[D[j]]; // v.put(j, v*M[D[j]]); } } } } void mul(mat_GF2& X, const mat_GF2& A, GF2 b) { X = A; if (b == 0) clear(X); } void diag(mat_GF2& X, long n, GF2 d) { if (d == 1) ident(X, n); else { X.SetDims(n, n); clear(X); } } long IsDiag(const mat_GF2& A, long n, GF2 d) { if (A.NumRows() != n || A.NumCols() != n) return 0; if (d == 1) return IsIdent(A, n); else return IsZero(A); } long IsZero(const mat_GF2& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_GF2& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_GF2 operator+(const mat_GF2& a, const mat_GF2& b) { mat_GF2 res; add(res, a, b); NTL_OPT_RETURN(mat_GF2, res); } mat_GF2 operator*(const mat_GF2& a, const mat_GF2& b) { mat_GF2 res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_GF2, res); } mat_GF2 operator-(const mat_GF2& a, const mat_GF2& b) { mat_GF2 res; add(res, a, b); NTL_OPT_RETURN(mat_GF2, res); } vec_GF2 operator*(const mat_GF2& a, const vec_GF2& b) { vec_GF2 res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_GF2, res); } vec_GF2 operator*(const vec_GF2& a, const mat_GF2& b) { vec_GF2 res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_GF2, res); } void inv(mat_GF2& X, const mat_GF2& A) { GF2 d; inv(d, X, A); if (d == 0) Error("inv: non-invertible matrix"); } void power(mat_GF2& X, const mat_GF2& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_GF2 T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } NTL_END_IMPL ntl-6.2.1/src/mat_GF2E.c000644 000765 000024 00000034522 12377144456 015120 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL void add(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void mul_aux(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); long i, j, k; GF2X acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { clear(acc); for(k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(B(k,j))); add(acc, acc, tmp); } conv(X(i,j), acc); } } } void mul(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B) { if (&X == &A || &X == &B) { mat_GF2E tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } static void mul_aux(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; GF2X acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(b(k))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b) { if (&b == &x || A.position1(x) != -1) { vec_GF2E tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; GF2X acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, rep(a(k)), rep(B(k,i))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B) { if (&a == &x) { vec_GF2E tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_GF2E& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } void determinant(GF2E& d, const mat_GF2E& M_in) { long k, n; long i, j; long pos; GF2X t1, t2; GF2X *x, *y; const GF2XModulus& p = GF2E::modulus(); n = M_in.NumRows(); if (M_in.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } vec_GF2XVec M; M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(n, 2*GF2E::WordLength()); for (j = 0; j < n; j++) M[i][j] = rep(M_in[i][j]); } GF2X det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); for (j = k+1; j < n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } conv(d, det); } long IsIdent(const mat_GF2E& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_GF2E& X, const mat_GF2E& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_GF2E tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void solve(GF2E& d, vec_GF2E& X, const mat_GF2E& A, const vec_GF2E& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } long i, j, k, pos; GF2X t1, t2; GF2X *x, *y; const GF2XModulus& p = GF2E::modulus(); vec_GF2XVec M; M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(n+1, 2*GF2E::WordLength()); for (j = 0; j < n; j++) M[i][j] = rep(A[j][i]); M[i][n] = rep(b[i]); } GF2X det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); for (j = k+1; j <= n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetLength(n); for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } add(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); } void inv(GF2E& d, mat_GF2E& X, const mat_GF2E& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } long i, j, k, pos; GF2X t1, t2; GF2X *x, *y; const GF2XModulus& p = GF2E::modulus(); vec_GF2XVec M; M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(2*n, 2*GF2E::WordLength()); for (j = 0; j < n; j++) { M[i][j] = rep(A[i][j]); clear(M[i][n+j]); } set(M[i][n+i]); } GF2X det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); for (j = k+1; j < 2*n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < 2*n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetDims(n, n); for (k = 0; k < n; k++) { for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j][k]), M[i][j]); add(t1, t1, t2); } add(t1, t1, M[i][n+k]); conv(X[i][k], t1); } } conv(d, det); } long gauss(mat_GF2E& M_in, long w) { long k, l; long i, j; long pos; GF2X t1, t2, t3; GF2X *x, *y; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) Error("gauss: bad args"); const GF2XModulus& p = GF2E::modulus(); vec_GF2XVec M; M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(m, 2*GF2E::WordLength()); for (j = 0; j < m; j++) { M[i][j] = rep(M_in[i][j]); } } l = 0; for (k = 0; k < w && l < n; k++) { pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(t3, M[l][k], p); for (j = k+1; j < m; j++) { rem(M[l][j], M[l][j], p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k]*t3 MulMod(t1, M[i][k], t3, p); clear(M[i][k]); x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } l++; } } for (i = 0; i < n; i++) for (j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); return l; } long gauss(mat_GF2E& M) { return gauss(M, M.NumCols()); } void image(mat_GF2E& X, const mat_GF2E& A) { mat_GF2E M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(mat_GF2E& X, const mat_GF2E& A) { long m = A.NumRows(); long n = A.NumCols(); mat_GF2E M; long r; transpose(M, A); r = gauss(M); X.SetDims(m-r, m); long i, j, k, s; GF2X t1, t2; GF2E T3; vec_long D; D.SetLength(m); for (j = 0; j < m; j++) D[j] = -1; vec_GF2E inverses; inverses.SetLength(m); j = -1; for (i = 0; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } for (k = 0; k < m-r; k++) { vec_GF2E& v = X[k]; long pos = 0; for (j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { i = D[j]; clear(t1); for (s = j+1; s < m; s++) { mul(t2, rep(v[s]), rep(M[i][s])); add(t1, t1, t2); } conv(T3, t1); mul(T3, T3, inverses[j]); v[j] = T3; } } } } void mul(mat_GF2E& X, const mat_GF2E& A, const GF2E& b_in) { GF2E b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_GF2E& X, const mat_GF2E& A, GF2 b) { X = A; if (b == 0) clear(X); } void diag(mat_GF2E& X, long n, const GF2E& d_in) { GF2E d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_GF2E& A, long n, const GF2E& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } long IsZero(const mat_GF2E& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_GF2E& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_GF2E operator+(const mat_GF2E& a, const mat_GF2E& b) { mat_GF2E res; add(res, a, b); NTL_OPT_RETURN(mat_GF2E, res); } mat_GF2E operator*(const mat_GF2E& a, const mat_GF2E& b) { mat_GF2E res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_GF2E, res); } mat_GF2E operator-(const mat_GF2E& a, const mat_GF2E& b) { mat_GF2E res; sub(res, a, b); NTL_OPT_RETURN(mat_GF2E, res); } mat_GF2E operator-(const mat_GF2E& a) { mat_GF2E res; negate(res, a); NTL_OPT_RETURN(mat_GF2E, res); } vec_GF2E operator*(const mat_GF2E& a, const vec_GF2E& b) { vec_GF2E res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_GF2E, res); } vec_GF2E operator*(const vec_GF2E& a, const mat_GF2E& b) { vec_GF2E res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_GF2E, res); } void inv(mat_GF2E& X, const mat_GF2E& A) { GF2E d; inv(d, X, A); if (d == 0) Error("inv: non-invertible matrix"); } void power(mat_GF2E& X, const mat_GF2E& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_GF2E T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } NTL_END_IMPL ntl-6.2.1/src/mat_RR.c000644 000765 000024 00000027336 12377144456 014765 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void add(mat_RR& X, const mat_RR& A, const mat_RR& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_RR& X, const mat_RR& A, const mat_RR& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void mul_aux(mat_RR& X, const mat_RR& A, const mat_RR& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); long i, j, k; RR acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { clear(acc); for(k = 1; k <= l; k++) { mul(tmp, A(i,k), B(k,j)); add(acc, acc, tmp); } X(i,j) = acc; } } } void mul(mat_RR& X, const mat_RR& A, const mat_RR& B) { if (&X == &A || &X == &B) { mat_RR tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } static void mul_aux(vec_RR& x, const mat_RR& A, const vec_RR& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; RR acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, A(i,k), b(k)); add(acc, acc, tmp); } x(i) = acc; } } void mul(vec_RR& x, const mat_RR& A, const vec_RR& b) { if (&b == &x || A.position1(x) != -1) { vec_RR tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_RR& x, const vec_RR& a, const mat_RR& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; RR acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, a(k), B(k,i)); add(acc, acc, tmp); } x(i) = acc; } } void mul(vec_RR& x, const vec_RR& a, const mat_RR& B) { if (&a == &x) { vec_RR tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_RR& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } void determinant(RR& d, const mat_RR& M_in) { long k, n; long i, j; long pos; RR t1, t2; RR *x, *y; n = M_in.NumRows(); if (M_in.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } mat_RR M; M = M_in; RR det; set(det); RR maxval; for (k = 0; k < n; k++) { pos = -1; clear(maxval); for (i = k; i < n; i++) { abs(t1, M[i][k]); if (t1 > maxval) { pos = i; maxval = t1; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); // make M[k, k] == -1 inv(t1, M[k][k]); negate(t1, t1); for (j = k+1; j < n; j++) { mul(M[k][j], M[k][j], t1); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } d = det; } RR determinant(const mat_RR& a) { RR x; determinant(x, a); NTL_OPT_RETURN(RR, x); } long IsIdent(const mat_RR& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_RR& X, const mat_RR& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_RR tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void solve(RR& d, vec_RR& X, const mat_RR& A, const vec_RR& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } long i, j, k, pos; RR t1, t2; RR *x, *y; mat_RR M; M.SetDims(n, n+1); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) M[i][j] = A[j][i]; M[i][n] = b[i]; } RR det; set(det); RR maxval; for (k = 0; k < n; k++) { pos = -1; clear(maxval); for (i = k; i < n; i++) { abs(t1, M[i][k]); if (t1 > maxval) { pos = i; maxval = t1; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); // make M[k, k] == -1 inv(t1, M[k][k]); negate(t1, t1); for (j = k+1; j <= n; j++) { mul(M[k][j], M[k][j], t1); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetLength(n); for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, X[j], M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); X[i] = t1; } d = det; } void inv(RR& d, mat_RR& X, const mat_RR& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } long i, j, k, pos; RR t1, t2; RR *x, *y; mat_RR M; M.SetDims(n, 2*n); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { M[i][j] = A[i][j]; clear(M[i][n+j]); } set(M[i][n+i]); } RR det; set(det); RR maxval; for (k = 0; k < n; k++) { pos = -1; clear(maxval); for (i = k; i < n; i++) { abs(t1, M[i][k]); if (t1 > maxval) { pos = i; maxval = t1; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); // make M[k, k] == -1 inv(t1, M[k][k]); negate(t1, t1); for (j = k+1; j < 2*n; j++) { mul(M[k][j], M[k][j], t1); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < 2*n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetDims(n, n); for (k = 0; k < n; k++) { for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, X[j][k], M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n+k]); X[i][k] = t1; } } d = det; } void mul(mat_RR& X, const mat_RR& A, const RR& b_in) { RR b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_RR& X, const mat_RR& A, double b_in) { RR b; b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void diag(mat_RR& X, long n, const RR& d_in) { RR d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_RR& A, long n, const RR& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } void negate(mat_RR& X, const mat_RR& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } long IsZero(const mat_RR& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_RR& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_RR operator+(const mat_RR& a, const mat_RR& b) { mat_RR res; add(res, a, b); NTL_OPT_RETURN(mat_RR, res); } mat_RR operator*(const mat_RR& a, const mat_RR& b) { mat_RR res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_RR, res); } mat_RR operator-(const mat_RR& a, const mat_RR& b) { mat_RR res; sub(res, a, b); NTL_OPT_RETURN(mat_RR, res); } mat_RR operator-(const mat_RR& a) { mat_RR res; negate(res, a); NTL_OPT_RETURN(mat_RR, res); } vec_RR operator*(const mat_RR& a, const vec_RR& b) { vec_RR res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_RR, res); } vec_RR operator*(const vec_RR& a, const mat_RR& b) { vec_RR res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_RR, res); } void inv(mat_RR& X, const mat_RR& A) { RR d; inv(d, X, A); if (d == 0) Error("inv: non-invertible matrix"); } void power(mat_RR& X, const mat_RR& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_RR T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } NTL_END_IMPL ntl-6.2.1/src/mat_ZZ.c000644 000765 000024 00000057652 12377144456 015011 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void add(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void mul_aux(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); long i, j, k; ZZ acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { clear(acc); for(k = 1; k <= l; k++) { mul(tmp, A(i,k), B(k,j)); add(acc, acc, tmp); } X(i,j) = acc; } } } void mul(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B) { if (&X == &A || &X == &B) { mat_ZZ tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } static void mul_aux(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; ZZ acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, A(i,k), b(k)); add(acc, acc, tmp); } x(i) = acc; } } void mul(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b) { if (&b == &x || A.position1(x) != -1) { vec_ZZ tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, a(k), B(k,i)); add(acc, acc, tmp); } x(i) = acc; } } void mul(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B) { if (&a == &x) { vec_ZZ tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_ZZ& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } static long DetBound(const mat_ZZ& a) { long n = a.NumRows(); long i; ZZ res, t1; set(res); for (i = 0; i < n; i++) { InnerProduct(t1, a[i], a[i]); if (t1 > 1) { SqrRoot(t1, t1); add(t1, t1, 1); } mul(res, res, t1); } return NumBits(res); } void determinant(ZZ& rres, const mat_ZZ& a, long deterministic) { long n = a.NumRows(); if (a.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(rres); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); long instable = 1; long gp_cnt = 0; long bound = 2+DetBound(a); ZZ res, prod; clear(res); set(prod); long i; for (i = 0; ; i++) { if (NumBits(prod) > bound) break; if (!deterministic && !instable && bound > 1000 && NumBits(prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(res))); GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p A; conv(A, a); ZZ_p t; determinant(t, A); if (CRT(res, prod, rep(t), P)) instable = 1; else break; } zz_p::FFTInit(i); long p = zz_p::modulus(); mat_zz_p A; conv(A, a); zz_p t; determinant(t, A); instable = CRT(res, prod, rep(t), p); } rres = res; zbak.restore(); Zbak.restore(); } void conv(mat_zz_p& x, const mat_ZZ& a) { long n = a.NumRows(); long m = a.NumCols(); long i; x.SetDims(n, m); for (i = 0; i < n; i++) conv(x[i], a[i]); } void conv(mat_ZZ_p& x, const mat_ZZ& a) { long n = a.NumRows(); long m = a.NumCols(); long i; x.SetDims(n, m); for (i = 0; i < n; i++) conv(x[i], a[i]); } long IsIdent(const mat_ZZ& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_ZZ& X, const mat_ZZ& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_ZZ tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } long CRT(mat_ZZ& gg, ZZ& a, const mat_zz_p& G) { long n = gg.NumRows(); long m = gg.NumCols(); if (G.NumRows() != n || G.NumCols() != m) Error("CRT: dimension mismatch"); long p = zz_p::modulus(); ZZ new_a; mul(new_a, a, p); long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long p1; p1 = p >> 1; ZZ a1; RightShift(a1, a, 1); long p_odd = (p & 1); long modified = 0; long h; ZZ g; long i, j; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { if (!CRTInRange(gg[i][j], a)) { modified = 1; rem(g, gg[i][j], a); if (g > a1) sub(g, g, a); } else g = gg[i][j]; h = rem(g, p); h = SubMod(rep(G[i][j]), h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!p_odd && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } gg[i][j] = g; } } a = new_a; return modified; } void mul(mat_ZZ& X, const mat_ZZ& A, const ZZ& b_in) { ZZ b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_ZZ& X, const mat_ZZ& A, long b) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } static void ExactDiv(vec_ZZ& x, const ZZ& d) { long n = x.length(); long i; for (i = 0; i < n; i++) if (!divide(x[i], x[i], d)) Error("inexact division"); } static void ExactDiv(mat_ZZ& x, const ZZ& d) { long n = x.NumRows(); long m = x.NumCols(); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) if (!divide(x[i][j], x[i][j], d)) Error("inexact division"); } void diag(mat_ZZ& X, long n, const ZZ& d_in) { ZZ d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_ZZ& A, long n, const ZZ& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } void solve(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b, long deterministic) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { set(d_out); x_out.SetLength(0); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); vec_ZZ x(INIT_SIZE, n); ZZ d, d1; ZZ d_prod, x_prod; set(d_prod); set(x_prod); long d_instable = 1; long x_instable = 1; long check = 0; long gp_cnt = 0; vec_ZZ y, b1; long i; long bound = 2+DetBound(A); for (i = 0; ; i++) { if ((check || IsZero(d)) && !d_instable) { if (NumBits(d_prod) > bound) { break; } else if (!deterministic && bound > 1000 && NumBits(d_prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(d))); GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p AA; conv(AA, A); ZZ_p dd; determinant(dd, AA); if (CRT(d, d_prod, rep(dd), P)) d_instable = 1; else break; } } zz_p::FFTInit(i); long p = zz_p::modulus(); mat_zz_p AA; conv(AA, A); if (!check) { vec_zz_p bb, xx; conv(bb, b); zz_p dd; solve(dd, xx, AA, bb); d_instable = CRT(d, d_prod, rep(dd), p); if (!IsZero(dd)) { mul(xx, xx, dd); x_instable = CRT(x, x_prod, xx); } else x_instable = 1; if (!d_instable && !x_instable) { mul(y, x, A); mul(b1, b, d); if (y == b1) { d1 = d; check = 1; } } } else { zz_p dd; determinant(dd, AA); d_instable = CRT(d, d_prod, rep(dd), p); } } if (check && d1 != d) { mul(x, x, d); ExactDiv(x, d1); } d_out = d; if (check) x_out = x; zbak.restore(); Zbak.restore(); } void inv(ZZ& d_out, mat_ZZ& x_out, const mat_ZZ& A, long deterministic) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (n == 0) { set(d_out); x_out.SetDims(0, 0); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); mat_ZZ x(INIT_SIZE, n, n); ZZ d, d1; ZZ d_prod, x_prod; set(d_prod); set(x_prod); long d_instable = 1; long x_instable = 1; long gp_cnt = 0; long check = 0; mat_ZZ y; long i; long bound = 2+DetBound(A); for (i = 0; ; i++) { if ((check || IsZero(d)) && !d_instable) { if (NumBits(d_prod) > bound) { break; } else if (!deterministic && bound > 1000 && NumBits(d_prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(d))); GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p AA; conv(AA, A); ZZ_p dd; determinant(dd, AA); if (CRT(d, d_prod, rep(dd), P)) d_instable = 1; else break; } } zz_p::FFTInit(i); long p = zz_p::modulus(); mat_zz_p AA; conv(AA, A); if (!check) { mat_zz_p xx; zz_p dd; inv(dd, xx, AA); d_instable = CRT(d, d_prod, rep(dd), p); if (!IsZero(dd)) { mul(xx, xx, dd); x_instable = CRT(x, x_prod, xx); } else x_instable = 1; if (!d_instable && !x_instable) { mul(y, x, A); if (IsDiag(y, n, d)) { d1 = d; check = 1; } } } else { zz_p dd; determinant(dd, AA); d_instable = CRT(d, d_prod, rep(dd), p); } } if (check && d1 != d) { mul(x, x, d); ExactDiv(x, d1); } d_out = d; if (check) x_out = x; zbak.restore(); Zbak.restore(); } void negate(mat_ZZ& X, const mat_ZZ& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } long IsZero(const mat_ZZ& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_ZZ& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_ZZ operator+(const mat_ZZ& a, const mat_ZZ& b) { mat_ZZ res; add(res, a, b); NTL_OPT_RETURN(mat_ZZ, res); } mat_ZZ operator*(const mat_ZZ& a, const mat_ZZ& b) { mat_ZZ res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_ZZ, res); } mat_ZZ operator-(const mat_ZZ& a, const mat_ZZ& b) { mat_ZZ res; sub(res, a, b); NTL_OPT_RETURN(mat_ZZ, res); } mat_ZZ operator-(const mat_ZZ& a) { mat_ZZ res; negate(res, a); NTL_OPT_RETURN(mat_ZZ, res); } vec_ZZ operator*(const mat_ZZ& a, const vec_ZZ& b) { vec_ZZ res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ, res); } vec_ZZ operator*(const vec_ZZ& a, const mat_ZZ& b) { vec_ZZ res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ, res); } void inv(mat_ZZ& X, const mat_ZZ& A) { ZZ d; inv(d, X, A); if (d == -1) negate(X, X); else if (d != 1) Error("inv: non-invertible matrix"); } void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_ZZ T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } /*********************************************************** routines for solving a linear system via Hensel lifting ************************************************************/ static long MaxBits(const mat_ZZ& A) { long m = 0; long i, j; for (i = 0; i < A.NumRows(); i++) for (j = 0; j < A.NumCols(); j++) m = max(m, NumBits(A[i][j])); return m; } // Computes an upper bound on the numerators and denominators // to the solution x*A = b using Hadamard's bound and Cramer's rule. // If A contains a zero row, then sets both bounds to zero. static void hadamard(ZZ& num_bound, ZZ& den_bound, const mat_ZZ& A, const vec_ZZ& b) { long n = A.NumRows(); if (n == 0) Error("internal error: hadamard with n = 0"); ZZ b_len, min_A_len, prod, t1; InnerProduct(min_A_len, A[0], A[0]); prod = min_A_len; long i; for (i = 1; i < n; i++) { InnerProduct(t1, A[i], A[i]); if (t1 < min_A_len) min_A_len = t1; mul(prod, prod, t1); } if (min_A_len == 0) { num_bound = 0; den_bound = 0; return; } InnerProduct(b_len, b, b); div(t1, prod, min_A_len); mul(t1, t1, b_len); SqrRoot(num_bound, t1); SqrRoot(den_bound, prod); } static void MixedMul(vec_ZZ& x, const vec_zz_p& a, const mat_ZZ& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, B(k, i), rep(a(k))); add(acc, acc, tmp); } x(i) = acc; } } static void SubDiv(vec_ZZ& e, const vec_ZZ& t, long p) { long n = e.length(); if (t.length() != n) Error("SubDiv: dimension mismatch"); ZZ s; long i; for (i = 0; i < n; i++) { sub(s, e[i], t[i]); div(e[i], s, p); } } static void MulAdd(vec_ZZ& x, const ZZ& prod, const vec_zz_p& h) { long n = x.length(); if (h.length() != n) Error("MulAdd: dimension mismatch"); ZZ t; long i; for (i = 0; i < n; i++) { mul(t, prod, rep(h[i])); add(x[i], x[i], t); } } static void double_MixedMul1(vec_ZZ& x, double *a, double **B, long n) { long i, k; double acc; for (i = 0; i < n; i++) { double *bp = B[i]; acc = 0; for (k = 0; k < n; k++) { acc += bp[k] * a[k]; } conv(x[i], acc); } } static void double_MixedMul2(vec_ZZ& x, double *a, double **B, long n, long limit) { long i, k; double acc; ZZ acc1, t; long j; for (i = 0; i < n; i++) { double *bp = B[i]; clear(acc1); acc = 0; j = 0; for (k = 0; k < n; k++) { acc += bp[k] * a[k]; j++; if (j == limit) { conv(t, acc); add(acc1, acc1, t); acc = 0; j = 0; } } if (j > 0) { conv(t, acc); add(acc1, acc1, t); } x[i] = acc1; } } static void long_MixedMul1(vec_ZZ& x, long *a, long **B, long n) { long i, k; long acc; for (i = 0; i < n; i++) { long *bp = B[i]; acc = 0; for (k = 0; k < n; k++) { acc += bp[k] * a[k]; } conv(x[i], acc); } } static void long_MixedMul2(vec_ZZ& x, long *a, long **B, long n, long limit) { long i, k; long acc; ZZ acc1, t; long j; for (i = 0; i < n; i++) { long *bp = B[i]; clear(acc1); acc = 0; j = 0; for (k = 0; k < n; k++) { acc += bp[k] * a[k]; j++; if (j == limit) { conv(t, acc); add(acc1, acc1, t); acc = 0; j = 0; } } if (j > 0) { conv(t, acc); add(acc1, acc1, t); } x[i] = acc1; } } void solve1(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve1: nonsquare matrix"); if (b.length() != n) Error("solve1: dimension mismatch"); if (n == 0) { set(d_out); x_out.SetLength(0); return; } ZZ num_bound, den_bound; hadamard(num_bound, den_bound, A, b); if (den_bound == 0) { clear(d_out); return; } zz_pBak zbak; zbak.save(); long i; long j; ZZ prod; prod = 1; mat_zz_p B; for (i = 0; ; i++) { zz_p::FFTInit(i); mat_zz_p AA, BB; zz_p dd; conv(AA, A); inv(dd, BB, AA); if (dd != 0) { transpose(B, BB); break; } mul(prod, prod, zz_p::modulus()); if (prod > den_bound) { d_out = 0; return; } } long max_A_len = MaxBits(A); long use_double_mul1 = 0; long use_double_mul2 = 0; long double_limit = 0; if (max_A_len + NTL_SP_NBITS + NumBits(n) <= NTL_DOUBLE_PRECISION-1) use_double_mul1 = 1; if (!use_double_mul1 && max_A_len+NTL_SP_NBITS+2 <= NTL_DOUBLE_PRECISION-1) { use_double_mul2 = 1; double_limit = (1L << (NTL_DOUBLE_PRECISION-1-max_A_len-NTL_SP_NBITS)); } long use_long_mul1 = 0; long use_long_mul2 = 0; long long_limit = 0; if (max_A_len + NTL_SP_NBITS + NumBits(n) <= NTL_BITS_PER_LONG-1) use_long_mul1 = 1; if (!use_long_mul1 && max_A_len+NTL_SP_NBITS+2 <= NTL_BITS_PER_LONG-1) { use_long_mul2 = 1; long_limit = (1L << (NTL_BITS_PER_LONG-1-max_A_len-NTL_SP_NBITS)); } if (use_double_mul1 && use_long_mul1) use_long_mul1 = 0; else if (use_double_mul1 && use_long_mul2) use_long_mul2 = 0; else if (use_double_mul2 && use_long_mul1) use_double_mul2 = 0; else if (use_double_mul2 && use_long_mul2) { if (long_limit > double_limit) use_double_mul2 = 0; else use_long_mul2 = 0; } double **double_A; double *double_h; typedef double *double_ptr; if (use_double_mul1 || use_double_mul2) { double_h = NTL_NEW_OP double[n]; double_A = NTL_NEW_OP double_ptr[n]; if (!double_h || !double_A) Error("solve1: out of mem"); for (i = 0; i < n; i++) { double_A[i] = NTL_NEW_OP double[n]; if (!double_A[i]) Error("solve1: out of mem"); } for (i = 0; i < n; i++) for (j = 0; j < n; j++) double_A[j][i] = to_double(A[i][j]); } long **long_A; long *long_h; typedef long *long_ptr; if (use_long_mul1 || use_long_mul2) { long_h = NTL_NEW_OP long[n]; long_A = NTL_NEW_OP long_ptr[n]; if (!long_h || !long_A) Error("solve1: out of mem"); for (i = 0; i < n; i++) { long_A[i] = NTL_NEW_OP long[n]; if (!long_A[i]) Error("solve1: out of mem"); } for (i = 0; i < n; i++) for (j = 0; j < n; j++) long_A[j][i] = to_long(A[i][j]); } vec_ZZ x; x.SetLength(n); vec_zz_p h; h.SetLength(n); vec_ZZ e; e = b; vec_zz_p ee; vec_ZZ t; t.SetLength(n); prod = 1; ZZ bound1; mul(bound1, num_bound, den_bound); mul(bound1, bound1, 2); while (prod <= bound1) { conv(ee, e); mul(h, B, ee); if (use_double_mul1) { for (i = 0; i < n; i++) double_h[i] = to_double(rep(h[i])); double_MixedMul1(t, double_h, double_A, n); } else if (use_double_mul2) { for (i = 0; i < n; i++) double_h[i] = to_double(rep(h[i])); double_MixedMul2(t, double_h, double_A, n, double_limit); } else if (use_long_mul1) { for (i = 0; i < n; i++) long_h[i] = to_long(rep(h[i])); long_MixedMul1(t, long_h, long_A, n); } else if (use_long_mul2) { for (i = 0; i < n; i++) long_h[i] = to_long(rep(h[i])); long_MixedMul2(t, long_h, long_A, n, long_limit); } else MixedMul(t, h, A); // t = h*A SubDiv(e, t, zz_p::modulus()); // e = (e-t)/p MulAdd(x, prod, h); // x = x + prod*h mul(prod, prod, zz_p::modulus()); } vec_ZZ num, denom; ZZ d, d_mod_prod, tmp1; num.SetLength(n); denom.SetLength(n); d = 1; d_mod_prod = 1; for (i = 0; i < n; i++) { rem(x[i], x[i], prod); MulMod(x[i], x[i], d_mod_prod, prod); if (!ReconstructRational(num[i], denom[i], x[i], prod, num_bound, den_bound)) Error("solve1 internal error: rat recon failed!"); mul(d, d, denom[i]); if (i != n-1) { if (denom[i] != 1) { div(den_bound, den_bound, denom[i]); mul(bound1, num_bound, den_bound); mul(bound1, bound1, 2); div(tmp1, prod, zz_p::modulus()); while (tmp1 > bound1) { prod = tmp1; div(tmp1, prod, zz_p::modulus()); } rem(tmp1, denom[i], prod); rem(d_mod_prod, d_mod_prod, prod); MulMod(d_mod_prod, d_mod_prod, tmp1, prod); } } } tmp1 = 1; for (i = n-1; i >= 0; i--) { mul(num[i], num[i], tmp1); mul(tmp1, tmp1, denom[i]); } x_out.SetLength(n); for (i = 0; i < n; i++) { x_out[i] = num[i]; } d_out = d; if (use_double_mul1 || use_double_mul2) { delete [] double_h; for (i = 0; i < n; i++) { delete [] double_A[i]; } delete [] double_A; } if (use_long_mul1 || use_long_mul2) { delete [] long_h; for (i = 0; i < n; i++) { delete [] long_A[i]; } delete [] long_A; } } NTL_END_IMPL ntl-6.2.1/src/mat_ZZ_p.c000644 000765 000024 00000036565 12377144456 015330 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL void add(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void negate(mat_ZZ_p& X, const mat_ZZ_p& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } void mul_aux(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); long i, j, k; ZZ acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { clear(acc); for(k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(B(k,j))); add(acc, acc, tmp); } conv(X(i,j), acc); } } } void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { if (&X == &A || &X == &B) { mat_ZZ_p tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } static void mul_aux(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; ZZ acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(b(k))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b) { if (&b == &x || A.position1(x) != -1) { vec_ZZ_p tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, rep(a(k)), rep(B(k,i))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B) { if (&a == &x) { vec_ZZ_p tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_ZZ_p& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } void determinant(ZZ_p& d, const mat_ZZ_p& M_in) { long k, n; long i, j; long pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); n = M_in.NumRows(); if (M_in.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } vec_ZZVec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(n, t1.size()); for (j = 0; j < n; j++) M[i][j] = rep(M_in[i][j]); } ZZ det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); NegateMod(t1, t1, p); for (j = k+1; j < n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } conv(d, det); } long IsIdent(const mat_ZZ_p& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_ZZ_p& X, const mat_ZZ_p& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_ZZ_p tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void solve(ZZ_p& d, vec_ZZ_p& X, const mat_ZZ_p& A, const vec_ZZ_p& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } long i, j, k, pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); vec_ZZVec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(n+1, t1.size()); for (j = 0; j < n; j++) M[i][j] = rep(A[j][i]); M[i][n] = rep(b[i]); } ZZ det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); NegateMod(t1, t1, p); for (j = k+1; j <= n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetLength(n); for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); } void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } long i, j, k, pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); vec_ZZVec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(2*n, t1.size()); for (j = 0; j < n; j++) { M[i][j] = rep(A[i][j]); clear(M[i][n+j]); } set(M[i][n+i]); } ZZ det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); NegateMod(t1, t1, p); for (j = k+1; j < 2*n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < 2*n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetDims(n, n); for (k = 0; k < n; k++) { for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j][k]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n+k]); conv(X[i][k], t1); } } conv(d, det); } long gauss(mat_ZZ_p& M_in, long w) { long k, l; long i, j; long pos; ZZ t1, t2, t3; ZZ *x, *y; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) Error("gauss: bad args"); const ZZ& p = ZZ_p::modulus(); vec_ZZVec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(m, t1.size()); for (j = 0; j < m; j++) { M[i][j] = rep(M_in[i][j]); } } l = 0; for (k = 0; k < w && l < n; k++) { pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(t3, M[l][k], p); NegateMod(t3, t3, p); for (j = k+1; j < m; j++) { rem(M[l][j], M[l][j], p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k]*t3 MulMod(t1, M[i][k], t3, p); clear(M[i][k]); x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } l++; } } for (i = 0; i < n; i++) for (j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); return l; } long gauss(mat_ZZ_p& M) { return gauss(M, M.NumCols()); } void image(mat_ZZ_p& X, const mat_ZZ_p& A) { mat_ZZ_p M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(mat_ZZ_p& X, const mat_ZZ_p& A) { long m = A.NumRows(); long n = A.NumCols(); mat_ZZ_p M; long r; transpose(M, A); r = gauss(M); X.SetDims(m-r, m); long i, j, k, s; ZZ t1, t2; ZZ_p T3; vec_long D; D.SetLength(m); for (j = 0; j < m; j++) D[j] = -1; vec_ZZ_p inverses; inverses.SetLength(m); j = -1; for (i = 0; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } for (k = 0; k < m-r; k++) { vec_ZZ_p& v = X[k]; long pos = 0; for (j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { i = D[j]; clear(t1); for (s = j+1; s < m; s++) { mul(t2, rep(v[s]), rep(M[i][s])); add(t1, t1, t2); } conv(T3, t1); mul(T3, T3, inverses[j]); negate(v[j], T3); } } } } void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ_p& b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_ZZ_p& X, const mat_ZZ_p& A, long b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void diag(mat_ZZ_p& X, long n, const ZZ_p& d_in) { ZZ_p d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_ZZ_p& A, long n, const ZZ_p& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } long IsZero(const mat_ZZ_p& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_ZZ_p& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_ZZ_p operator+(const mat_ZZ_p& a, const mat_ZZ_p& b) { mat_ZZ_p res; add(res, a, b); NTL_OPT_RETURN(mat_ZZ_p, res); } mat_ZZ_p operator*(const mat_ZZ_p& a, const mat_ZZ_p& b) { mat_ZZ_p res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_ZZ_p, res); } mat_ZZ_p operator-(const mat_ZZ_p& a, const mat_ZZ_p& b) { mat_ZZ_p res; sub(res, a, b); NTL_OPT_RETURN(mat_ZZ_p, res); } mat_ZZ_p operator-(const mat_ZZ_p& a) { mat_ZZ_p res; negate(res, a); NTL_OPT_RETURN(mat_ZZ_p, res); } vec_ZZ_p operator*(const mat_ZZ_p& a, const vec_ZZ_p& b) { vec_ZZ_p res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ_p, res); } vec_ZZ_p operator*(const vec_ZZ_p& a, const mat_ZZ_p& b) { vec_ZZ_p res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ_p, res); } void inv(mat_ZZ_p& X, const mat_ZZ_p& A) { ZZ_p d; inv(d, X, A); if (d == 0) Error("inv: non-invertible matrix"); } void power(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_ZZ_p T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } NTL_END_IMPL ntl-6.2.1/src/mat_ZZ_pE.c000644 000765 000024 00000037754 12377144456 015436 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void add(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void negate(mat_ZZ_pE& X, const mat_ZZ_pE& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } void mul_aux(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); long i, j, k; ZZ_pX acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { clear(acc); for(k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(B(k,j))); add(acc, acc, tmp); } conv(X(i,j), acc); } } } void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B) { if (&X == &A || &X == &B) { mat_ZZ_pE tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } static void mul_aux(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; ZZ_pX acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(b(k))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b) { if (&b == &x || A.position1(x) != -1) { vec_ZZ_pE tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ_pX acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, rep(a(k)), rep(B(k,i))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B) { if (&a == &x) { vec_ZZ_pE tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_ZZ_pE& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } void determinant(ZZ_pE& d, const mat_ZZ_pE& M_in) { long k, n; long i, j; long pos; ZZ_pX t1, t2; ZZ_pX *x, *y; const ZZ_pXModulus& p = ZZ_pE::modulus(); n = M_in.NumRows(); if (M_in.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } vec_ZZ_pX *M = NTL_NEW_OP vec_ZZ_pX[n]; for (i = 0; i < n; i++) { M[i].SetLength(n); for (j = 0; j < n; j++) { M[i][j].rep.SetMaxLength(2*deg(p)-1); M[i][j] = rep(M_in[i][j]); } } ZZ_pX det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); negate(t1, t1); for (j = k+1; j < n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); goto done; } } conv(d, det); done: delete[] M; } long IsIdent(const mat_ZZ_pE& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_ZZ_pE& X, const mat_ZZ_pE& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_ZZ_pE tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void solve(ZZ_pE& d, vec_ZZ_pE& X, const mat_ZZ_pE& A, const vec_ZZ_pE& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } long i, j, k, pos; ZZ_pX t1, t2; ZZ_pX *x, *y; const ZZ_pXModulus& p = ZZ_pE::modulus(); vec_ZZ_pX *M = NTL_NEW_OP vec_ZZ_pX[n]; for (i = 0; i < n; i++) { M[i].SetLength(n+1); for (j = 0; j < n; j++) { M[i][j].rep.SetMaxLength(2*deg(p)-1); M[i][j] = rep(A[j][i]); } M[i][n].rep.SetMaxLength(2*deg(p)-1); M[i][n] = rep(b[i]); } ZZ_pX det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); negate(t1, t1); for (j = k+1; j <= n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); goto done; } } X.SetLength(n); for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); done: delete[] M; } void inv(ZZ_pE& d, mat_ZZ_pE& X, const mat_ZZ_pE& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } long i, j, k, pos; ZZ_pX t1, t2; ZZ_pX *x, *y; const ZZ_pXModulus& p = ZZ_pE::modulus(); vec_ZZ_pX *M = NTL_NEW_OP vec_ZZ_pX[n]; for (i = 0; i < n; i++) { M[i].SetLength(2*n); for (j = 0; j < n; j++) { M[i][j].rep.SetMaxLength(2*deg(p)-1); M[i][j] = rep(A[i][j]); M[i][n+j].rep.SetMaxLength(2*deg(p)-1); clear(M[i][n+j]); } set(M[i][n+i]); } ZZ_pX det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); negate(t1, t1); for (j = k+1; j < 2*n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < 2*n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); goto done; } } X.SetDims(n, n); for (k = 0; k < n; k++) { for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j][k]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n+k]); conv(X[i][k], t1); } } conv(d, det); done: delete[] M; } long gauss(mat_ZZ_pE& M_in, long w) { long k, l; long i, j; long pos; ZZ_pX t1, t2, t3; ZZ_pX *x, *y; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) Error("gauss: bad args"); const ZZ_pXModulus& p = ZZ_pE::modulus(); vec_ZZ_pX *M = NTL_NEW_OP vec_ZZ_pX[n]; for (i = 0; i < n; i++) { M[i].SetLength(m); for (j = 0; j < m; j++) { M[i][j].rep.SetMaxLength(2*deg(p)-1); M[i][j] = rep(M_in[i][j]); } } l = 0; for (k = 0; k < w && l < n; k++) { pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(t3, M[l][k], p); negate(t3, t3); for (j = k+1; j < m; j++) { rem(M[l][j], M[l][j], p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k]*t3 MulMod(t1, M[i][k], t3, p); clear(M[i][k]); x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } l++; } } for (i = 0; i < n; i++) for (j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); delete [] M; return l; } long gauss(mat_ZZ_pE& M) { return gauss(M, M.NumCols()); } void image(mat_ZZ_pE& X, const mat_ZZ_pE& A) { mat_ZZ_pE M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(mat_ZZ_pE& X, const mat_ZZ_pE& A) { long m = A.NumRows(); long n = A.NumCols(); mat_ZZ_pE M; long r; transpose(M, A); r = gauss(M); X.SetDims(m-r, m); long i, j, k, s; ZZ_pX t1, t2; ZZ_pE T3; vec_long D; D.SetLength(m); for (j = 0; j < m; j++) D[j] = -1; vec_ZZ_pE inverses; inverses.SetLength(m); j = -1; for (i = 0; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } for (k = 0; k < m-r; k++) { vec_ZZ_pE& v = X[k]; long pos = 0; for (j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { i = D[j]; clear(t1); for (s = j+1; s < m; s++) { mul(t2, rep(v[s]), rep(M[i][s])); add(t1, t1, t2); } conv(T3, t1); mul(T3, T3, inverses[j]); negate(v[j], T3); } } } } void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_pE& b_in) { ZZ_pE b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_p& b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, long b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void diag(mat_ZZ_pE& X, long n, const ZZ_pE& d_in) { ZZ_pE d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_ZZ_pE& A, long n, const ZZ_pE& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } long IsZero(const mat_ZZ_pE& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_ZZ_pE& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_ZZ_pE operator+(const mat_ZZ_pE& a, const mat_ZZ_pE& b) { mat_ZZ_pE res; add(res, a, b); NTL_OPT_RETURN(mat_ZZ_pE, res); } mat_ZZ_pE operator*(const mat_ZZ_pE& a, const mat_ZZ_pE& b) { mat_ZZ_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_ZZ_pE, res); } mat_ZZ_pE operator-(const mat_ZZ_pE& a, const mat_ZZ_pE& b) { mat_ZZ_pE res; sub(res, a, b); NTL_OPT_RETURN(mat_ZZ_pE, res); } mat_ZZ_pE operator-(const mat_ZZ_pE& a) { mat_ZZ_pE res; negate(res, a); NTL_OPT_RETURN(mat_ZZ_pE, res); } vec_ZZ_pE operator*(const mat_ZZ_pE& a, const vec_ZZ_pE& b) { vec_ZZ_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ_pE, res); } vec_ZZ_pE operator*(const vec_ZZ_pE& a, const mat_ZZ_pE& b) { vec_ZZ_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ_pE, res); } void inv(mat_ZZ_pE& X, const mat_ZZ_pE& A) { ZZ_pE d; inv(d, X, A); if (d == 0) Error("inv: non-invertible matrix"); } void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_ZZ_pE T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } NTL_END_IMPL ntl-6.2.1/src/mat_lzz_p.c000644 000765 000024 00000043171 12377144456 015573 0ustar00shoupstaff000000 000000 #include #include #include #include #include NTL_START_IMPL void add(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } // some local buffers NTL_THREAD_LOCAL static vec_long mul_aux_vec; NTL_THREAD_LOCAL static NTL_SPMM_VEC_T precon_vec; static void mul_aux(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); if (m > 1) { // new preconditioning code long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); mul_aux_vec.SetLength(m); long *acc = mul_aux_vec.elts(); long i, j, k; for (i = 0; i < n; i++) { const zz_p* ap = A[i].elts(); for (j = 0; j < m; j++) acc[j] = 0; for (k = 0; k < l; k++) { long aa = rep(ap[k]); if (aa != 0) { const zz_p* bp = B[k].elts(); long T1; mulmod_precon_t aapinv = PrepMulModPrecon(aa, p, pinv); for (j = 0; j < m; j++) { T1 = MulModPrecon(rep(bp[j]), aa, p, aapinv); acc[j] = AddMod(acc[j], T1, p); } } } zz_p *xp = X[i].elts(); for (j = 0; j < m; j++) xp[j].LoopHole() = acc[j]; } if (mul_aux_vec.length() > NTL_RELEASE_THRESH) mul_aux_vec.kill(); } else { // just use the old code, w/o preconditioning long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); long i, j, k; long acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { acc = 0; for(k = 1; k <= l; k++) { tmp = MulMod(rep(A(i,k)), rep(B(k,j)), p, pinv); acc = AddMod(acc, tmp, p); } X(i,j).LoopHole() = acc; } } } } void mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { if (&X == &A || &X == &B) { mat_zz_p tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } void mul(vec_zz_p& x, const vec_zz_p& a, const mat_zz_p& B) { long l = a.length(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); if (m == 0) { x.SetLength(0); } else if (m == 1) { long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); long acc, tmp; long k; acc = 0; for(k = 1; k <= l; k++) { tmp = MulMod(rep(a(k)), rep(B(k,1)), p, pinv); acc = AddMod(acc, tmp, p); } x.SetLength(1); x(1).LoopHole() = acc; } else { // m > 1. precondition long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); mul_aux_vec.SetLength(m); long *acc = mul_aux_vec.elts(); long j, k; const zz_p* ap = a.elts(); for (j = 0; j < m; j++) acc[j] = 0; for (k = 0; k < l; k++) { long aa = rep(ap[k]); if (aa != 0) { const zz_p* bp = B[k].elts(); long T1; mulmod_precon_t aapinv = PrepMulModPrecon(aa, p, pinv); for (j = 0; j < m; j++) { T1 = MulModPrecon(rep(bp[j]), aa, p, aapinv); acc[j] = AddMod(acc[j], T1, p); } } } x.SetLength(m); zz_p *xp = x.elts(); for (j = 0; j < m; j++) xp[j].LoopHole() = acc[j]; if (mul_aux_vec.length() > NTL_RELEASE_THRESH) mul_aux_vec.kill(); } } void mul_aux(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); zz_p* xp = x.elts(); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); long i, k; long acc, tmp; const zz_p* bp = b.elts(); if (n <= 1) { for (i = 0; i < n; i++) { acc = 0; const zz_p* ap = A[i].elts(); for (k = 0; k < l; k++) { tmp = MulMod(rep(ap[k]), rep(bp[k]), p, pinv); acc = AddMod(acc, tmp, p); } xp[i].LoopHole() = acc; } } else { precon_vec.SetLength(l); mulmod_precon_t *bpinv = precon_vec.elts(); for (k = 0; k < l; k++) bpinv[k] = PrepMulModPrecon(rep(bp[k]), p, pinv); for (i = 0; i < n; i++) { acc = 0; const zz_p* ap = A[i].elts(); for (k = 0; k < l; k++) { tmp = MulModPrecon(rep(ap[k]), rep(bp[k]), p, bpinv[k]); acc = AddMod(acc, tmp, p); } xp[i].LoopHole() = acc; } if (precon_vec.length() > NTL_RELEASE_THRESH) precon_vec.kill(); } } void mul(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b) { if (&b == &x || A.position1(x) != -1) { vec_zz_p tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } void mul(mat_zz_p& X, const mat_zz_p& A, zz_p b) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; if (n == 0 || m == 0 || (n == 1 && m == 1)) { for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } else { long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); long bb = rep(b); mulmod_precon_t bpinv = PrepMulModPrecon(bb, p, pinv); for (i = 0; i < n; i++) { const zz_p *ap = A[i].elts(); zz_p *xp = X[i].elts(); for (j = 0; j < m; j++) xp[j].LoopHole() = MulModPrecon(rep(ap[j]), bb, p, bpinv); } } } void mul(mat_zz_p& X, const mat_zz_p& A, long b_in) { zz_p b; b = b_in; mul(X, A, b); } void ident(mat_zz_p& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } void determinant(zz_p& d, const mat_zz_p& M_in) { long k, n; long i, j; long pos; zz_p t1, t2, t3; zz_p *x, *y; mat_zz_p M; M = M_in; n = M.NumRows(); if (M.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } zz_p det; set(det); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { if (!IsZero(M[i][k])) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); inv(t3, M[k][k]); for (i = k+1; i < n; i++) { // M[i] = M[i] - M[k]*M[i,k]*t3 mul(t1, M[i][k], t3); negate(t1, t1); x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); long T1 = rep(t1); mulmod_precon_t t1pinv = PrepMulModPrecon(T1, p, pinv); // T1*pinv; long T2; for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 T2 = MulModPrecon(rep(*y), T1, p, t1pinv); x->LoopHole() = AddMod(rep(*x), T2, p); } } } else { clear(d); return; } } d = det; } long IsIdent(const mat_zz_p& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_zz_p& X, const mat_zz_p& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_zz_p tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void solve(zz_p& d, vec_zz_p& X, const mat_zz_p& A, const vec_zz_p& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } long i, j, k, pos; zz_p t1, t2, t3; zz_p *x, *y; mat_zz_p M; M.SetDims(n, n+1); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) M[i][j] = A[j][i]; M[i][n] = b[i]; } zz_p det; set(det); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { if (!IsZero(M[i][k])) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); inv(t3, M[k][k]); M[k][k] = t3; for (i = k+1; i < n; i++) { // M[i] = M[i] - M[k]*M[i,k]*t3 mul(t1, M[i][k], t3); negate(t1, t1); x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); long T1 = rep(t1); mulmod_precon_t t1pinv = PrepMulModPrecon(T1, p, pinv); // T1*pinv; long T2; for (j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 T2 = MulModPrecon(rep(*y), T1, p, t1pinv); x->LoopHole() = AddMod(rep(*x), T2, p); } } } else { clear(d); return; } } X.SetLength(n); for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, X[j], M[i][j]); add(t1, t1, t2); } sub(t1, M[i][n], t1); mul(X[i], t1, M[i][i]); } d = det; } void inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } long i, j, k, pos; zz_p t1, t2, t3; zz_p *x, *y; mat_zz_p M; M.SetDims(n, 2*n); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { M[i][j] = A[i][j]; clear(M[i][n+j]); } set(M[i][n+i]); } zz_p det; set(det); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { if (!IsZero(M[i][k])) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); inv(t3, M[k][k]); M[k][k] = t3; for (i = k+1; i < n; i++) { // M[i] = M[i] - M[k]*M[i,k]*t3 mul(t1, M[i][k], t3); negate(t1, t1); x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); long T1 = rep(t1); mulmod_precon_t t1pinv = PrepMulModPrecon(T1, p, pinv); // T1*pinv; long T2; for (j = k+1; j < 2*n; j++, x++, y++) { // *x = *x + (*y)*t1 T2 = MulModPrecon(rep(*y), T1, p, t1pinv); x->LoopHole() = AddMod(rep(*x), T2, p); } } } else { clear(d); return; } } X.SetDims(n, n); for (k = 0; k < n; k++) { for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, X[j][k], M[i][j]); add(t1, t1, t2); } sub(t1, M[i][n+k], t1); mul(X[i][k], t1, M[i][i]); } } d = det; } long gauss(mat_zz_p& M, long w) { long k, l; long i, j; long pos; zz_p t1, t2, t3; zz_p *x, *y; long n = M.NumRows(); long m = M.NumCols(); if (w < 0 || w > m) Error("gauss: bad args"); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); long T1, T2; l = 0; for (k = 0; k < w && l < n; k++) { pos = -1; for (i = l; i < n; i++) { if (!IsZero(M[i][k])) { pos = i; break; } } if (pos != -1) { swap(M[pos], M[l]); inv(t3, M[l][k]); negate(t3, t3); for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k]*t3 mul(t1, M[i][k], t3); T1 = rep(t1); mulmod_precon_t T1pinv = PrepMulModPrecon(T1, p, pinv); // ((double) T1)*pinv; clear(M[i][k]); x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 T2 = MulModPrecon(rep(*y), T1, p, T1pinv); T2 = AddMod(T2, rep(*x), p); (*x).LoopHole() = T2; } } l++; } } return l; } long gauss(mat_zz_p& M) { return gauss(M, M.NumCols()); } void image(mat_zz_p& X, const mat_zz_p& A) { mat_zz_p M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(mat_zz_p& X, const mat_zz_p& A) { long m = A.NumRows(); long n = A.NumCols(); mat_zz_p M; long r; transpose(M, A); r = gauss(M); X.SetDims(m-r, m); long i, j, k, s; zz_p t1, t2; vec_long D; D.SetLength(m); for (j = 0; j < m; j++) D[j] = -1; vec_zz_p inverses; inverses.SetLength(m); j = -1; for (i = 0; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } for (k = 0; k < m-r; k++) { vec_zz_p& v = X[k]; long pos = 0; for (j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { i = D[j]; clear(t1); for (s = j+1; s < m; s++) { mul(t2, v[s], M[i][s]); add(t1, t1, t2); } mul(t1, t1, inverses[j]); negate(v[j], t1); } } } } void diag(mat_zz_p& X, long n, zz_p d) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_zz_p& A, long n, zz_p d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } void negate(mat_zz_p& X, const mat_zz_p& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } long IsZero(const mat_zz_p& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_zz_p& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_zz_p operator+(const mat_zz_p& a, const mat_zz_p& b) { mat_zz_p res; add(res, a, b); NTL_OPT_RETURN(mat_zz_p, res); } mat_zz_p operator*(const mat_zz_p& a, const mat_zz_p& b) { mat_zz_p res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_zz_p, res); } mat_zz_p operator-(const mat_zz_p& a, const mat_zz_p& b) { mat_zz_p res; sub(res, a, b); NTL_OPT_RETURN(mat_zz_p, res); } mat_zz_p operator-(const mat_zz_p& a) { mat_zz_p res; negate(res, a); NTL_OPT_RETURN(mat_zz_p, res); } vec_zz_p operator*(const mat_zz_p& a, const vec_zz_p& b) { vec_zz_p res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_zz_p, res); } vec_zz_p operator*(const vec_zz_p& a, const mat_zz_p& b) { vec_zz_p res; mul(res, a, b); NTL_OPT_RETURN(vec_zz_p, res); } void inv(mat_zz_p& X, const mat_zz_p& A) { zz_p d; inv(d, X, A); if (d == 0) Error("inv: non-invertible matrix"); } void power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_zz_p T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } NTL_END_IMPL ntl-6.2.1/src/mat_lzz_pE.c000644 000765 000024 00000037755 12377144456 015713 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void negate(mat_zz_pE& X, const mat_zz_pE& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } void mul_aux(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); long i, j, k; zz_pX acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { clear(acc); for(k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(B(k,j))); add(acc, acc, tmp); } conv(X(i,j), acc); } } } void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B) { if (&X == &A || &X == &B) { mat_zz_pE tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } static void mul_aux(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; zz_pX acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(b(k))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b) { if (&b == &x || A.position1(x) != -1) { vec_zz_pE tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; zz_pX acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, rep(a(k)), rep(B(k,i))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B) { if (&a == &x) { vec_zz_pE tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_zz_pE& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } void determinant(zz_pE& d, const mat_zz_pE& M_in) { long k, n; long i, j; long pos; zz_pX t1, t2; zz_pX *x, *y; const zz_pXModulus& p = zz_pE::modulus(); n = M_in.NumRows(); if (M_in.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } vec_zz_pX *M = NTL_NEW_OP vec_zz_pX[n]; for (i = 0; i < n; i++) { M[i].SetLength(n); for (j = 0; j < n; j++) { M[i][j].rep.SetMaxLength(2*deg(p)-1); M[i][j] = rep(M_in[i][j]); } } zz_pX det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); negate(t1, t1); for (j = k+1; j < n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); goto done; } } conv(d, det); done: delete[] M; } long IsIdent(const mat_zz_pE& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_zz_pE& X, const mat_zz_pE& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_zz_pE tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void solve(zz_pE& d, vec_zz_pE& X, const mat_zz_pE& A, const vec_zz_pE& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } long i, j, k, pos; zz_pX t1, t2; zz_pX *x, *y; const zz_pXModulus& p = zz_pE::modulus(); vec_zz_pX *M = NTL_NEW_OP vec_zz_pX[n]; for (i = 0; i < n; i++) { M[i].SetLength(n+1); for (j = 0; j < n; j++) { M[i][j].rep.SetMaxLength(2*deg(p)-1); M[i][j] = rep(A[j][i]); } M[i][n].rep.SetMaxLength(2*deg(p)-1); M[i][n] = rep(b[i]); } zz_pX det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); negate(t1, t1); for (j = k+1; j <= n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); goto done; } } X.SetLength(n); for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); done: delete[] M; } void inv(zz_pE& d, mat_zz_pE& X, const mat_zz_pE& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } long i, j, k, pos; zz_pX t1, t2; zz_pX *x, *y; const zz_pXModulus& p = zz_pE::modulus(); vec_zz_pX *M = NTL_NEW_OP vec_zz_pX[n]; for (i = 0; i < n; i++) { M[i].SetLength(2*n); for (j = 0; j < n; j++) { M[i][j].rep.SetMaxLength(2*deg(p)-1); M[i][j] = rep(A[i][j]); M[i][n+j].rep.SetMaxLength(2*deg(p)-1); clear(M[i][n+j]); } set(M[i][n+i]); } zz_pX det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); negate(t1, t1); for (j = k+1; j < 2*n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < 2*n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); goto done; } } X.SetDims(n, n); for (k = 0; k < n; k++) { for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j][k]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n+k]); conv(X[i][k], t1); } } conv(d, det); done: delete[] M; } long gauss(mat_zz_pE& M_in, long w) { long k, l; long i, j; long pos; zz_pX t1, t2, t3; zz_pX *x, *y; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) Error("gauss: bad args"); const zz_pXModulus& p = zz_pE::modulus(); vec_zz_pX *M = NTL_NEW_OP vec_zz_pX[n]; for (i = 0; i < n; i++) { M[i].SetLength(m); for (j = 0; j < m; j++) { M[i][j].rep.SetMaxLength(2*deg(p)-1); M[i][j] = rep(M_in[i][j]); } } l = 0; for (k = 0; k < w && l < n; k++) { pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(t3, M[l][k], p); negate(t3, t3); for (j = k+1; j < m; j++) { rem(M[l][j], M[l][j], p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k]*t3 MulMod(t1, M[i][k], t3, p); clear(M[i][k]); x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } l++; } } for (i = 0; i < n; i++) for (j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); delete [] M; return l; } long gauss(mat_zz_pE& M) { return gauss(M, M.NumCols()); } void image(mat_zz_pE& X, const mat_zz_pE& A) { mat_zz_pE M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(mat_zz_pE& X, const mat_zz_pE& A) { long m = A.NumRows(); long n = A.NumCols(); mat_zz_pE M; long r; transpose(M, A); r = gauss(M); X.SetDims(m-r, m); long i, j, k, s; zz_pX t1, t2; zz_pE T3; vec_long D; D.SetLength(m); for (j = 0; j < m; j++) D[j] = -1; vec_zz_pE inverses; inverses.SetLength(m); j = -1; for (i = 0; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } for (k = 0; k < m-r; k++) { vec_zz_pE& v = X[k]; long pos = 0; for (j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { i = D[j]; clear(t1); for (s = j+1; s < m; s++) { mul(t2, rep(v[s]), rep(M[i][s])); add(t1, t1, t2); } conv(T3, t1); mul(T3, T3, inverses[j]); negate(v[j], T3); } } } } void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b_in) { zz_pE b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b_in) { NTL_zz_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_zz_pE& X, const mat_zz_pE& A, long b_in) { NTL_zz_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void diag(mat_zz_pE& X, long n, const zz_pE& d_in) { zz_pE d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } long IsZero(const mat_zz_pE& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_zz_pE& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b) { mat_zz_pE res; add(res, a, b); NTL_OPT_RETURN(mat_zz_pE, res); } mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b) { mat_zz_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_zz_pE, res); } mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b) { mat_zz_pE res; sub(res, a, b); NTL_OPT_RETURN(mat_zz_pE, res); } mat_zz_pE operator-(const mat_zz_pE& a) { mat_zz_pE res; negate(res, a); NTL_OPT_RETURN(mat_zz_pE, res); } vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b) { vec_zz_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_zz_pE, res); } vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b) { vec_zz_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_zz_pE, res); } void inv(mat_zz_pE& X, const mat_zz_pE& A) { zz_pE d; inv(d, X, A); if (d == 0) Error("inv: non-invertible matrix"); } void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_zz_pE T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } NTL_END_IMPL ntl-6.2.1/src/mat_poly_ZZ.c000644 000765 000024 00000003516 12377144456 016042 0ustar00shoupstaff000000 000000 #include #include #include #include NTL_START_IMPL static long CharPolyBound(const mat_ZZ& a) // This bound is computed via interpolation // through complex roots of unity. { long n = a.NumRows(); long i; ZZ res, t1, t2; set(res); for (i = 0; i < n; i++) { InnerProduct(t1, a[i], a[i]); abs(t2, a[i][i]); mul(t2, t2, 2); add(t2, t2, 1); add(t1, t1, t2); if (t1 > 1) { SqrRoot(t1, t1); add(t1, t1, 1); } mul(res, res, t1); } return NumBits(res); } void CharPoly(ZZX& gg, const mat_ZZ& a, long deterministic) { long n = a.NumRows(); if (a.NumCols() != n) Error("CharPoly: nonsquare matrix"); if (n == 0) { set(gg); return; } if (n == 1) { ZZ t; SetX(gg); negate(t, a(1, 1)); SetCoeff(gg, 0, t); return; } long bound = 2 + CharPolyBound(a); zz_pBak bak; bak.save(); ZZ_pBak bak1; bak1.save(); ZZX g; ZZ prod; clear(g); set(prod); long i; long instable = 1; long gp_cnt = 0; for (i = 0; ; i++) { if (NumBits(prod) > bound) break; if (!deterministic && !instable && bound > 1000 && NumBits(prod) < 0.25*bound) { long plen = 90 + NumBits(max(bound, MaxBits(g))); ZZ P; GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p A; ZZ_pX G; conv(A, a); CharPoly(G, A); if (CRT(g, prod, G)) instable = 1; else break; } zz_p::FFTInit(i); mat_zz_p A; zz_pX G; conv(A, a); CharPoly(G, A); instable = CRT(g, prod, G); } gg = g; bak.restore(); bak1.restore(); } NTL_END_IMPL ntl-6.2.1/src/mat_poly_ZZ_p.c000644 000765 000024 00000003013 12377144456 016351 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void CharPoly(ZZ_pX& f, const mat_ZZ_p& M) { long n = M.NumRows(); if (M.NumCols() != n) Error("CharPoly: nonsquare matrix"); if (n == 0) { set(f); return; } ZZ_p t; if (n == 1) { SetX(f); negate(t, M(1, 1)); SetCoeff(f, 0, t); return; } mat_ZZ_p H; H = M; long i, j, m; ZZ_p u, t1; for (m = 2; m <= n-1; m++) { i = m; while (i <= n && IsZero(H(i, m-1))) i++; if (i <= n) { t = H(i, m-1); if (i > m) { swap(H(i), H(m)); // swap columns i and m for (j = 1; j <= n; j++) swap(H(j, i), H(j, m)); } for (i = m+1; i <= n; i++) { div(u, H(i, m-1), t); for (j = m; j <= n; j++) { mul(t1, u, H(m, j)); sub(H(i, j), H(i, j), t1); } for (j = 1; j <= n; j++) { mul(t1, u, H(j, i)); add(H(j, m), H(j, m), t1); } } } } vec_ZZ_pX F; F.SetLength(n+1); ZZ_pX T; T.SetMaxLength(n); set(F[0]); for (m = 1; m <= n; m++) { LeftShift(F[m], F[m-1], 1); mul(T, F[m-1], H(m, m)); sub(F[m], F[m], T); set(t); for (i = 1; i <= m-1; i++) { mul(t, t, H(m-i+1, m-i)); mul(t1, t, H(m-i, m)); mul(T, F[m-i-1], t1); sub(F[m], F[m], T); } } f = F[n]; } NTL_END_IMPL ntl-6.2.1/src/mat_poly_lzz_p.c000644 000765 000024 00000003013 12377144456 016625 0ustar00shoupstaff000000 000000 #include #include NTL_START_IMPL void CharPoly(zz_pX& f, const mat_zz_p& M) { long n = M.NumRows(); if (M.NumCols() != n) Error("CharPoly: nonsquare matrix"); if (n == 0) { set(f); return; } zz_p t; if (n == 1) { SetX(f); negate(t, M(1, 1)); SetCoeff(f, 0, t); return; } mat_zz_p H; H = M; long i, j, m; zz_p u, t1; for (m = 2; m <= n-1; m++) { i = m; while (i <= n && IsZero(H(i, m-1))) i++; if (i <= n) { t = H(i, m-1); if (i > m) { swap(H(i), H(m)); // swap columns i and m for (j = 1; j <= n; j++) swap(H(j, i), H(j, m)); } for (i = m+1; i <= n; i++) { div(u, H(i, m-1), t); for (j = m; j <= n; j++) { mul(t1, u, H(m, j)); sub(H(i, j), H(i, j), t1); } for (j = 1; j <= n; j++) { mul(t1, u, H(j, i)); add(H(j, m), H(j, m), t1); } } } } vec_zz_pX F; F.SetLength(n+1); zz_pX T; T.SetMaxLength(n); set(F[0]); for (m = 1; m <= n; m++) { LeftShift(F[m], F[m-1], 1); mul(T, F[m-1], H(m, m)); sub(F[m], F[m], T); set(t); for (i = 1; i <= m-1; i++) { mul(t, t, H(m-i+1, m-i)); mul(t1, t, H(m-i, m)); mul(T, F[m-i-1], t1); sub(F[m], F[m], T); } } f = F[n]; } NTL_END_IMPL ntl-6.2.1/src/mfile000644 000765 000024 00000042176 12377144456 014453 0ustar00shoupstaff000000 000000 ############################################################### # # First, choose a C++ compiler, and set compiler flags. # This is done by setting the variables CXX and CXXFLAGS. # ############################################################### CXX=@{CXX} # A C++ compiler, e.g., g++, CC, xlC CXXFLAGS=@{CXXFLAGS} # Flags for the C++ compiler # Some useful flags: # -O2 -- recommended level of optimization # -m64 -- needed to get 64-bit longs on some platforms # -g -- debugging AR=@{AR} # command to make a library ARFLAGS=@{ARFLAGS} # arguments for AR RANLIB=@{RANLIB} # set to echo if you want to disable it completely LDFLAGS=@{LDFLAGS} # libraries for linking C++ programs LDLIBS=@{LDLIBS} # libraries for linking C++ programs CPPFLAGS=@{CPPFLAGS} # arguments for the C preprocessor LIBTOOL=@{LIBTOOL} # libtool command DEF_PREFIX=@{DEF_PREFIX} PREFIX=@{PREFIX} LIBDIR=@{LIBDIR} INCLUDEDIR=@{INCLUDEDIR} DOCDIR=@{DOCDIR} # where to install NTL ############################################################### # # Second, if you want to use GMP (the GNU Multi-Precision library), # define the variables GMP_OPT_INCDIR, GMP_OPT_LIBDIR, GMP_OPT_LIB below. # You also will have to set either NTL_GMP_LIP or NTL_GMP_HACK # in the config.h file. # # Using GMP can lead to significant performance gains on some # platforms. You can obtain GMP from http://www.swox.com/gmp. # Once you unpack it into a directory, just execute # ./configure; make # in that directory. # ############################################################### GMP_PREFIX=@{GMP_PREFIX} GMP_INCDIR=@{GMP_INCDIR} # directory containing gmp.h if using GMP GMP_LIBDIR=@{GMP_LIBDIR} # directory containing libgmp.a if using GMP GMP_OPT_INCDIR=@{GMPI}-I$(GMP_INCDIR) # GMPI GMP_OPT_LIBDIR=@{GMPL}-L$(GMP_LIBDIR) # GMPL GMP_OPT_LIB=@{GMP}-lgmp # GMP # uncomment these if using GMP ############################################################### # # Third, if you want to use gf2x (a library for fast # multiplication over GF(2)[X]), you need to # define the variables GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, GF2X_OPT_LIB below. # You also will have to set NTL_GF2X_LIB # in the config.h file. # ############################################################### GF2X_PREFIX=@{GF2X_PREFIX} GF2X_INCDIR=@{GF2X_INCDIR} # directory containing gf2x.h if using gf2x GF2X_LIBDIR=@{GF2X_LIBDIR} # directory containing libgf2x.a GF2X_OPT_INCDIR=@{GF2XI}-I$(GF2X_INCDIR) # GF2X GF2X_OPT_LIBDIR=@{GF2XL}-L$(GF2X_LIBDIR) # GF2X GF2X_OPT_LIB=@{GF2X}-lgf2x # GF2X # uncomment these if using gf2x ############################################################### # # Fourth, if you do not want to run the wizard that automagically # sets some performace related flags in config.h, set the flag below. # ############################################################### WIZARD=@{WIZARD} # Set to off if you want to bypass the wizard; otherwise, set to on. ################################################################# # # That's it! You can ignore everything else in this file! # ################################################################# # object files O01=FFT.o FacVec.o GF2.o GF2E.o GF2EX.o GF2EXFactoring.o GF2X.o GF2X1.o O02=$(O01) GF2XFactoring.o GF2XVec.o GetTime.o HNF.o ctools.o LLL.o LLL_FP.o O03=$(O02) LLL_QP.o LLL_RR.o LLL_XD.o RR.o WordVector.o ZZ.o ZZVec.o O04=$(O03) ZZX.o ZZX1.o ZZXCharPoly.o ZZXFactoring.o ZZ_p.o ZZ_pE.o ZZ_pEX.o O05=$(O04) ZZ_pEXFactoring.o ZZ_pX.o ZZ_pX1.o ZZ_pXCharPoly.o ZZ_pXFactoring.o O06=$(O05) fileio.o lip.o lzz_p.o lzz_pE.o lzz_pEX.o lzz_pEXFactoring.o O07=$(O06) lzz_pX.o lzz_pX1.o lzz_pXCharPoly.o lzz_pXFactoring.o O08=$(O07) mat_GF2.o mat_GF2E.o mat_RR.o mat_ZZ.o mat_ZZ_p.o O09=$(O08) mat_ZZ_pE.o mat_lzz_p.o mat_lzz_pE.o mat_poly_ZZ.o O10=$(O09) mat_poly_ZZ_p.o mat_poly_lzz_p.o O11=$(O10) O12=$(O11) O13=$(O12) quad_float.o tools.o vec_GF2.o vec_GF2E.o O14=$(O13) vec_RR.o vec_ZZ.o vec_ZZ_p.o vec_ZZ_pE.o O15=$(O14) vec_lzz_p.o vec_lzz_pE.o O16=$(O15) O17=$(O16) O18=$(O17) xdouble.o O19=$(O18) G_LLL_FP.o G_LLL_QP.o G_LLL_XD.o G_LLL_RR.o OBJ=$(O19) # library source files S01=FFT.c FacVec.c GF2.c GF2E.c GF2EX.c GF2EXFactoring.c GF2X.c GF2X1.c S02=$(S01) GF2XFactoring.c GF2XVec.c HNF.c ctools.c LLL.c LLL_FP.c LLL_QP.c S03=$(S02) LLL_RR.c LLL_XD.c RR.c WordVector.c ZZ.c ZZVec.c ZZX.c ZZX1.c S04=$(S03) ZZXCharPoly.c ZZXFactoring.c ZZ_p.c ZZ_pE.c ZZ_pEX.c S05=$(S04) ZZ_pEXFactoring.c ZZ_pX.c ZZ_pX1.c ZZ_pXCharPoly.c S06=$(S05) ZZ_pXFactoring.c fileio.c lip.c lzz_p.c lzz_pE.c lzz_pEX.c S07=$(S06) lzz_pEXFactoring.c lzz_pX.c lzz_pX1.c S08=$(S07) lzz_pXCharPoly.c lzz_pXFactoring.c mat_GF2.c mat_GF2E.c S09=$(S08) mat_RR.c mat_ZZ.c mat_ZZ_p.c mat_ZZ_pE.c mat_lzz_p.c mat_lzz_pE.c S10=$(S09) mat_poly_ZZ.c mat_poly_ZZ_p.c mat_poly_lzz_p.c S11=$(S10) S12=$(S11) S13=$(S12) quad_float.c tools.c vec_GF2.c vec_GF2E.c vec_RR.c S14=$(S13) vec_ZZ.c vec_ZZ_p.c vec_ZZ_pE.c S15=$(S14) vec_lzz_p.c vec_lzz_pE.c S16=$(S15) S17=$(S16) S18=$(S17) xdouble.c S19=$(S18) G_LLL_FP.c G_LLL_QP.c G_LLL_XD.c G_LLL_RR.c SRC = $(S19) # library source files that are header files SINC = c_lip_impl.h g_lip_impl.h # library header files IN01= FFT.h FacVec.h GF2.h GF2E.h GF2EX.h GF2EXFactoring.h GF2X.h IN02=$(IN01) GF2XFactoring.h GF2XVec.h HNF.h ctools.h LLL.h IN03=$(IN02) RR.h SPMM_ASM.h WordVector.h ZZ.h ZZVec.h ZZX.h ZZXFactoring.h IN04=$(IN03) ZZ_p.h ZZ_pE.h ZZ_pEX.h ZZ_pEXFactoring.h ZZ_pX.h ZZ_pXFactoring.h IN05=$(IN04) fileio.h lip.h lzz_p.h lzz_pE.h lzz_pEX.h lzz_pEXFactoring.h IN06=$(IN05) lzz_pX.h lzz_pXFactoring.h mat_GF2.h mat_GF2E.h mat_RR.h IN07=$(IN06) mat_ZZ.h mat_ZZ_p.h mat_ZZ_pE.h mat_lzz_p.h mat_lzz_pE.h IN08=$(IN07) mat_poly_ZZ.h mat_poly_ZZ_p.h mat_poly_lzz_p.h matrix.h IN09=$(IN08) pair.h vector.h pair_GF2EX_long.h pair_GF2X_long.h IN10=$(IN09) pair_ZZX_long.h pair_ZZ_pEX_long.h pair_ZZ_pX_long.h IN11=$(IN10) pair_lzz_pEX_long.h pair_lzz_pX_long.h quad_float.h IN12=$(IN11) tools.h vec_GF2.h vec_GF2E.h vec_GF2XVec.h vec_RR.h IN13=$(IN12) vec_ZZ.h vec_ZZVec.h vec_ZZ_p.h vec_ZZ_pE.h vec_double.h IN14=$(IN13) vec_long.h vec_lzz_p.h vec_lzz_pE.h vec_quad_float.h IN15=$(IN14) vec_vec_GF2.h vec_vec_GF2E.h vec_vec_RR.h vec_vec_ZZ.h IN16=$(IN15) vec_vec_ZZ_p.h vec_vec_ZZ_pE.h vec_vec_long.h vec_vec_lzz_p.h IN17=$(IN16) vec_vec_lzz_pE.h vec_xdouble.h xdouble.h config.h version.h IN18=$(IN17) def_config.h new.h vec_ulong.h vec_vec_ulong.h c_lip.h g_lip.h INCL=$(IN18) # test data TD1=BerlekampTestIn BerlekampTestOut CanZassTestIn CanZassTestOut TD2=$(TD1) ZZXFacTestIn ZZXFacTestOut MoreFacTestIn LLLTestIn LLLTestOut RRTestIn RRTestOut TD3=$(TD2) MatrixTestIn MatrixTestOut CharPolyTestIn TD4=$(TD3) CharPolyTestOut QuadTestIn QuadTestOut TD = $(TD4) # test source files TS1=QuickTest.c BerlekampTest.c CanZassTest.c ZZXFacTest.c MoreFacTest.c LLLTest.c TS2=$(TS1) subset.c MatrixTest.c CharPolyTest.c RRTest.c QuadTest.c TS3=$(TS2) GF2XTest.c GF2EXTest.c BitMatTest.c ZZ_pEXTest.c lzz_pEXTest.c Timing.c TS = $(TS3) # scripts SCRIPTS1=MakeGetTime TestScript dosify unixify RemoveProg SCRIPTS2=$(SCRIPTS1) configure DoConfig mfile cfile ppscript SCRIPTS=$(SCRIPTS2) # auxilliary source MD=MakeDesc.c MakeDescAux.c newnames.c gen_gmp_aux.c GT=GetTime1.c GetTime2.c GetTime3.c GetTime4.c GetTime5.c TestGetTime.c # documentation D01=copying.txt GF2.txt GF2E.txt GF2EX.txt GF2EXFactoring.txt GF2X.txt D02=$(D01) GF2XFactoring.txt GF2XVec.txt HNF.txt LLL.txt RR.txt D03=$(D02) ZZ.txt ZZVec.txt ZZX.txt ZZXFactoring.txt ZZ_p.txt ZZ_pE.txt D04=$(D03) ZZ_pEX.txt ZZ_pEXFactoring.txt ZZ_pX.txt ZZ_pXFactoring.txt D05=$(D04) conversions.txt flags.txt lzz_p.txt lzz_pE.txt lzz_pEX.txt D06=$(D05) lzz_pEXFactoring.txt lzz_pX.txt lzz_pXFactoring.txt mat_GF2.txt D07=$(D06) mat_GF2E.txt mat_RR.txt mat_ZZ.txt mat_ZZ_p.txt mat_ZZ_pE.txt D08=$(D07) mat_lzz_p.txt mat_lzz_pE.txt mat_poly_ZZ.txt mat_poly_ZZ_p.txt D09=$(D08) mat_poly_lzz_p.txt matrix.txt pair.txt vector.txt D10=$(D09) quad_float.txt sedscript.txt tools.txt vec_GF2.txt D11=$(D10) vec_GF2E.txt vec_RR.txt vec_ZZ.txt vec_ZZ_p.txt vec_ZZ_pE.txt D12=$(D11) vec_lzz_p.txt vec_lzz_pE.txt xdouble.txt names.txt D13=$(D12) tour-ack.html tour-intro.html tour-time.html tour-changes.html D14=$(D13) tour-modules.html tour-stdcxx.html tour-unix.html tour-examples.html D15=$(D14) tour-roadmap.html tour-win.html tour-impl.html tour-struct.html D16=$(D15) tour.html tour-ex1.html tour-ex2.html tour-ex3.html tour-ex4.html D17=$(D16) tour-ex5.html tour-ex6.html arrow1.gif arrow2.gif arrow3.gif D18=$(D17) tour-gmp.html tour-gf2x.html tour-tips.html config.txt version.txt TX01=GF2.txt GF2E.txt GF2EX.txt GF2EXFactoring.txt GF2X.txt GF2XFactoring.txt TX02=GF2XVec.txt HNF.txt LLL.txt RR.txt ZZ.txt ZZVec.txt ZZX.txt ZZXFactoring.txt TX03=ZZ_p.txt ZZ_pE.txt ZZ_pEX.txt ZZ_pEXFactoring.txt ZZ_pX.txt ZZ_pXFactoring.txt TX04=lzz_p.txt lzz_pE.txt lzz_pEX.txt lzz_pEXFactoring.txt lzz_pX.txt TX05=lzz_pXFactoring.txt mat_GF2.txt mat_GF2E.txt mat_RR.txt mat_ZZ.txt mat_ZZ_p.txt TX06=mat_ZZ_pE.txt mat_lzz_p.txt mat_lzz_pE.txt mat_poly_ZZ.txt mat_poly_ZZ_p.txt TX07=mat_poly_lzz_p.txt matrix.txt pair.txt quad_float.txt tools.txt vec_GF2.txt TX08=vec_GF2E.txt vec_RR.txt vec_ZZ.txt vec_ZZ_p.txt vec_ZZ_pE.txt vec_lzz_p.txt TX09=vec_lzz_pE.txt vector.txt version.txt xdouble.txt TXFILES=$(TX01) $(TX02) $(TX03) $(TX04) $(TX05) $(TX06) $(TX07) $(TX08) $(TX09) HT01=GF2.cpp.html GF2E.cpp.html GF2EX.cpp.html GF2EXFactoring.cpp.html GF2X.cpp.html GF2XFactoring.cpp.html HT02=GF2XVec.cpp.html HNF.cpp.html LLL.cpp.html RR.cpp.html ZZ.cpp.html ZZVec.cpp.html ZZX.cpp.html ZZXFactoring.cpp.html HT03=ZZ_p.cpp.html ZZ_pE.cpp.html ZZ_pEX.cpp.html ZZ_pEXFactoring.cpp.html ZZ_pX.cpp.html ZZ_pXFactoring.cpp.html HT04=lzz_p.cpp.html lzz_pE.cpp.html lzz_pEX.cpp.html lzz_pEXFactoring.cpp.html lzz_pX.cpp.html HT05=lzz_pXFactoring.cpp.html mat_GF2.cpp.html mat_GF2E.cpp.html mat_RR.cpp.html mat_ZZ.cpp.html mat_ZZ_p.cpp.html HT06=mat_ZZ_pE.cpp.html mat_lzz_p.cpp.html mat_lzz_pE.cpp.html mat_poly_ZZ.cpp.html mat_poly_ZZ_p.cpp.html HT07=mat_poly_lzz_p.cpp.html matrix.cpp.html pair.cpp.html quad_float.cpp.html tools.cpp.html vec_GF2.cpp.html HT08=vec_GF2E.cpp.html vec_RR.cpp.html vec_ZZ.cpp.html vec_ZZ_p.cpp.html vec_ZZ_pE.cpp.html vec_lzz_p.cpp.html HT09=vec_lzz_pE.cpp.html vector.cpp.html version.cpp.html xdouble.cpp.html HTFILES=$(HT01) $(HT02) $(HT03) $(HT04) $(HT05) $(HT06) $(HT07) $(HT08) $(HT09) DOC = $(D18) $(HTFILES) # test program executables PROG1=QuickTest BerlekampTest CanZassTest ZZXFacTest MoreFacTest LLLTest BitMatTest PROG2=$(PROG1) MatrixTest CharPolyTest RRTest QuadTest PROG3=$(PROG2) GF2XTest GF2EXTest subset ZZ_pEXTest lzz_pEXTest Timing PROGS = $(PROG3) # things to save to a tar file SFI1=makefile $(SRC) $(SINC) $(SCRIPTS) $(MD) $(GT) $(TS) $(TD) mach_desc.win SFI2=$(SFI1) MulTimeTest.c PolyTimeTest.c Poly1TimeTest.c GF2XTimeTest.c SFI3=$(SFI2) InitSettings.c DispSettings.c WizardAux Wizard def_makefile SFILES=$(SFI3) ################################################################# # # Rules for compiling the library # ################################################################# NTL_INCLUDE = -I../include -I. # NTL needs this to find its include files COMPILE = $(CXX) $(NTL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) -c LINK = $(CXX) $(NTL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) # 'make all' does a complete make, including all setup. # It also creates the file 'all', which means you should # run 'make clobber' before running 'make' or 'make all' # again. all: make setup1 make setup2 make setup3 make setup4 make ntl.a touch all # setup1 generates the file ../incluse/NTL/mach_desc.h setup1: $(COMPILE) MakeDescAux.c $(LINK) -o MakeDesc MakeDesc.c MakeDescAux.o $(LDLIBS) ./MakeDesc mv mach_desc.h ../include/NTL/mach_desc.h # setup2 generates the file GetTime.c setup2: sh MakeGetTime "$(LINK)" "$(LDLIBS)" # setup3 generates the file ../include/NTL/gmp_aux.h # The file ../include/NTL/gmp_aux.h is included in ../include/NTL/lip.h # when NTL_GMP_LIP is set. # When this flag is not set, an empty files produced. setup3: $(LINK) $(GMP_OPT_INCDIR) -o gen_gmp_aux gen_gmp_aux.c $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) ./gen_gmp_aux > ../include/NTL/gmp_aux.h # setup4 runs the wizard setup4: sh Wizard $(WIZARD) ntl.a: $(OBJ) @{LSTAT} $(AR) $(ARFLAGS) ntl.a $(OBJ) #LSTAT @{LSTAT} - $(RANLIB) ntl.a #LSTAT @{LSHAR} $(LIBTOOL) --mode=link $(LINK) -o libntl.la $(OBJ:.o=.lo) $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) -rpath $(LIBDIR) -version-info `cat VERSION_INFO` #LSHAR @{LSTAT}LCOMP= #LSTAT @{LSHAR}LCOMP=$(LIBTOOL) --mode=compile #LSHAR lip.o: lip.c g_lip_impl.h c_lip_impl.h $(LCOMP) $(COMPILE) $(GMP_OPT_INCDIR) lip.c ctools.o: ctools.c $(LCOMP) $(COMPILE) ctools.c GetTime.o: GetTime.c $(LCOMP) $(COMPILE) GetTime.c .c.o: $(LCOMP) $(COMPILE) $(GF2X_OPT_INCDIR) $< .c: @{LSTAT} $(LINK) -o $@ $< ntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) #LSTAT @{LSHAR} $(LIBTOOL) --mode=link $(LINK) -o $@ $< libntl.la #LSHAR ################################################################# # # Rule for running tests # make check runs a series of tests # ################################################################# check: sh RemoveProg $(PROGS) make QuickTest ./QuickTest sh RemoveProg QuickTest sh TestScript ################################################################# # # Rule for installing # make install just does a simple copy of the include file # and library. The -p option is used to preserve file attributes. # This helps avoid some problems (especially when copying ntl.a). # Also, an attempt is made to make everything that is # installed readable by everyone. # # make uninstall removes these files # ################################################################# install: mkdir -p -m 755 $(INCLUDEDIR) rm -rf $(INCLUDEDIR)/NTL mkdir -m 755 $(INCLUDEDIR)/NTL cp -p ../include/NTL/*.h $(INCLUDEDIR)/NTL - chmod -R a+r $(INCLUDEDIR)/NTL mkdir -p -m 755 $(DOCDIR) rm -rf $(DOCDIR)/NTL mkdir -m 755 $(DOCDIR)/NTL cp -p ../doc/*.txt $(DOCDIR)/NTL cp -p ../doc/*.html $(DOCDIR)/NTL cp -p ../doc/*.gif $(DOCDIR)/NTL - chmod -R a+r $(DOCDIR)/NTL mkdir -p -m 755 $(LIBDIR) @{LSTAT} cp -p ntl.a $(LIBDIR)/libntl.a #LSTAT @{LSTAT} - chmod a+r $(LIBDIR)/libntl.a #LSTAT @{LSHAR} $(LIBTOOL) --mode=install cp -p libntl.la $(LIBDIR) #LSHAR uninstall: @{LSTAT} rm -f $(LIBDIR)/libntl.a #LSTAT @{LSHAR} $(LIBTOOL) --mode=uninstall rm -f $(LIBDIR)/libntl.la #LSHAR rm -rf $(INCLUDEDIR)/NTL rm -rf $(DOCDIR)/NTL ################################################################# # # Rules for cleaning up # # make clobber removes *everything* created by make, # but it does not restore config.h to its default. # # make clean tidies up a bit # ################################################################# clobber: rm -f ntl.a mach_desc.h ../include/NTL/mach_desc.h GetTime.c rm -f ../include/NTL/gmp_aux.h sh RemoveProg $(PROGS) MakeDesc TestGetTime gen_gmp_aux rm -f *.o rm -rf small rm -f cfileout mfileout rm -rf .libs *.lo libntl.la rm -f all clean: sh RemoveProg MakeDesc TestGetTime gen_gmp_aux rm -f *.o rm -rf small @{LSHAR} - $(LIBTOOL) --mode=clean rm -f libntl.la *.lo #LSHAR ################################################################# # # Rules for making tar and zip files # # make ppdoc creates pretty-printed versions of some documentation # - run before make package or make winpack # # make package creates a tar.gz file suitable for Unix # # make winpack creates a zip file suitable for Windows # ################################################################# ppdoc: sh ppscript "$(TXFILES)" package: sh unixify "$(SFILES) DIRNAME WINDIR VERSION_INFO NOTES" "$(INCL)" "$(DOC)" rm -rf `cat DIRNAME` rm -f `cat DIRNAME`.tar rm -f `cat DIRNAME`.tar.gz mv unix `cat DIRNAME` chmod -R a+rX `cat DIRNAME` tar -cvf `cat DIRNAME`.tar `cat DIRNAME` gzip `cat DIRNAME`.tar rm -rf `cat DIRNAME` winpack: sh dosify "$(SRC)" "$(INCL)" "$(DOC)" "$(TS)" "$(TD)" "$(SINC)" rm -rf `cat WINDIR` rm -f `cat WINDIR`.zip mv dos `cat WINDIR` chmod -R a+rX `cat WINDIR` find ./`cat WINDIR` '!' -name '*.gif' -print | zip -l `cat WINDIR` -@ find ./`cat WINDIR` -name '*.gif' -print | zip -u `cat WINDIR` -@ rm -rf `cat WINDIR` ###################################################################### # # config wizard related stuff # ###################################################################### WO1 = FFT.o GetTime.o ctools.o ZZ.o ZZVec.o ZZ_p.o ZZ_pX.o WO2 = $(WO1) ZZ_pX1.o lip.o tools.o vec_ZZ.o vec_ZZ_p.o WO3 = $(WO2) GF2.o WordVector.o vec_GF2.o GF2X.o GF2X1.o WOBJ = $(WO3) @{LSHAR}wntl.a: LCOMP= #LSHAR wntl.a: $(WOBJ) $(AR) $(ARFLAGS) wntl.a $(WOBJ) - $(RANLIB) wntl.a MulTimeTest: $(LINK) -o MulTimeTest MulTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) PolyTimeTest: $(LINK) -o PolyTimeTest PolyTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) Poly1TimeTest: $(LINK) -o Poly1TimeTest Poly1TimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) GF2XTimeTest: $(LINK) -o GF2XTimeTest GF2XTimeTest.c wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) InitSettings: $(LINK) -o InitSettings InitSettings.c $(LDLIBS) DispSettings: $(LINK) -o DispSettings DispSettings.c $(LDLIBS) ntl-6.2.1/src/newnames.c000644 000765 000024 00000012076 12377144456 015411 0ustar00shoupstaff000000 000000 /************************************************************************ This program can be compiled under either C or C++. It copies its input to its output, substituting all old NTL macro names by new NTL macro names. This is intended to automate the transition from NTL 3.1 to 3.5. Each maximal length alphanumeric substring in the input is looked up in a table, and if there is a match, the substring is replaced. *************************************************************************/ #include #include #define NumNames (79) const char *names[NumNames][2] = { { "BB_HALF_MUL_CODE", "NTL_BB_HALF_MUL_CODE" }, { "BB_MUL_CODE", "NTL_BB_MUL_CODE" }, { "BB_REV_CODE", "NTL_BB_REV_CODE" }, { "BB_SQR_CODE", "NTL_BB_SQR_CODE" }, { "FFTFudge", "NTL_FFTFudge" }, { "FFTMaxRoot", "NTL_FFTMaxRoot" }, { "FFTMaxRootBnd", "NTL_FFTMaxRootBnd" }, { "QUAD_FLOAT_SPLIT", "NTL_QUAD_FLOAT_SPLIT" }, { "WV_NTL_RANGE_CHECK_CODE", "NTL_WV_RANGE_CHECK_CODE" }, { "WordVectorExpansionRatio", "NTL_WordVectorExpansionRatio" }, { "WordVectorInputBlock", "NTL_WordVectorInputBlock" }, { "WordVectorMinAlloc", "NTL_WordVectorMinAlloc" }, { "XD_BOUND", "NTL_XD_BOUND" }, { "XD_BOUND_INV", "NTL_XD_BOUND_INV" }, { "XD_HBOUND", "NTL_XD_HBOUND" }, { "XD_HBOUND_INV", "NTL_XD_HBOUND_INV" }, { "ZZ_ARITH_RIGHT_SHIFT", "NTL_ARITH_RIGHT_SHIFT" }, { "ZZ_BITS_PER_INT", "NTL_BITS_PER_INT" }, { "ZZ_BITS_PER_LONG", "NTL_BITS_PER_LONG" }, { "ZZ_DOUBLES_LOW_HIGH", "NTL_DOUBLES_LOW_HIGH" }, { "ZZ_DOUBLE_PRECISION", "NTL_DOUBLE_PRECISION" }, { "ZZ_EXT_DOUBLE", "NTL_EXT_DOUBLE" }, { "ZZ_FDOUBLE_PRECISION", "NTL_FDOUBLE_PRECISION" }, { "ZZ_FRADIX", "NTL_FRADIX" }, { "ZZ_FRADIX_INV", "NTL_FRADIX_INV" }, { "ZZ_FetchHiLo", "NTL_FetchHiLo" }, { "ZZ_FetchLo", "NTL_FetchLo" }, { "ZZ_HI_WD", "NTL_HI_WD" }, { "ZZ_LO_WD", "NTL_LO_WD" }, { "ZZ_MAX_INT", "NTL_MAX_INT" }, { "ZZ_MAX_LONG", "NTL_MAX_LONG" }, { "ZZ_MIN_INT", "NTL_MIN_INT" }, { "ZZ_MIN_LONG", "NTL_MIN_LONG" }, { "ZZ_NBITS", "NTL_NBITS" }, { "ZZ_NBITSH", "NTL_NBITSH" }, { "ZZ_NBITS_MAX", "NTL_NBITS_MAX" }, { "ZZ_NTL_SINGLE_MUL_OK", "NTL_SINGLE_MUL_OK" }, { "ZZ_PRIME_BND", "NTL_PRIME_BND" }, { "ZZ_RADIX", "NTL_RADIX" }, { "ZZ_RADIXM", "NTL_RADIXM" }, { "ZZ_RADIXROOT", "NTL_RADIXROOT" }, { "ZZ_RADIXROOTM", "NTL_RADIXROOTM" }, { "ZZ_pRegister", "NTL_ZZ_pRegister" }, { "ZZ_pX_BERMASS_CROSSOVER", "NTL_ZZ_pX_BERMASS_CROSSOVER" }, { "ZZ_pX_DIV_CROSSOVER", "NTL_ZZ_pX_DIV_CROSSOVER" }, { "ZZ_pX_FFT_CROSSOVER", "NTL_ZZ_pX_FFT_CROSSOVER" }, { "ZZ_pX_GCD_CROSSOVER", "NTL_ZZ_pX_GCD_CROSSOVER" }, { "ZZ_pX_HalfGCD_CROSSOVER", "NTL_ZZ_pX_HalfGCD_CROSSOVER" }, { "ZZ_pX_NEWTON_CROSSOVER", "NTL_ZZ_pX_NEWTON_CROSSOVER" }, { "ZZ_pX_TRACE_CROSSOVER", "NTL_ZZ_pX_TRACE_CROSSOVER" }, { "ntl_eq_matrix_decl", "NTL_eq_matrix_decl" }, { "ntl_eq_matrix_impl", "NTL_eq_matrix_impl" }, { "ntl_eq_vector_decl", "NTL_eq_vector_decl" }, { "ntl_eq_vector_impl", "NTL_eq_vector_impl" }, { "ntl_io_matrix_decl", "NTL_io_matrix_decl" }, { "ntl_io_matrix_impl", "NTL_io_matrix_impl" }, { "ntl_io_vector_decl", "NTL_io_vector_decl" }, { "ntl_io_vector_impl", "NTL_io_vector_impl" }, { "ntl_matrix_decl", "NTL_matrix_decl" }, { "ntl_matrix_impl", "NTL_matrix_impl" }, { "ntl_pair_decl", "NTL_pair_decl" }, { "ntl_pair_eq_decl", "NTL_pair_eq_decl" }, { "ntl_pair_eq_impl", "NTL_pair_eq_impl" }, { "ntl_pair_impl", "NTL_pair_impl" }, { "ntl_pair_io_decl", "NTL_pair_io_decl" }, { "ntl_pair_io_impl", "NTL_pair_io_impl" }, { "ntl_vector_decl", "NTL_vector_decl" }, { "ntl_vector_default", "NTL_vector_default" }, { "ntl_vector_impl", "NTL_vector_impl" }, { "ntl_vector_impl_plain", "NTL_vector_impl_plain" }, { "zz_pRegister", "NTL_zz_pRegister" }, { "zz_pX_BERMASS_CROSSOVER", "NTL_zz_pX_BERMASS_CROSSOVER" }, { "zz_pX_DIV_CROSSOVER", "NTL_zz_pX_DIV_CROSSOVER" }, { "zz_pX_GCD_CROSSOVER", "NTL_zz_pX_GCD_CROSSOVER" }, { "zz_pX_HalfGCD_CROSSOVER", "NTL_zz_pX_HalfGCD_CROSSOVER" }, { "zz_pX_MOD_CROSSOVER", "NTL_zz_pX_MOD_CROSSOVER" }, { "zz_pX_MUL_CROSSOVER", "NTL_zz_pX_MUL_CROSSOVER" }, { "zz_pX_NEWTON_CROSSOVER", "NTL_zz_pX_NEWTON_CROSSOVER" }, { "zz_pX_TRACE_CROSSOVER", "NTL_zz_pX_TRACE_CROSSOVER" }, }; void PrintName(const char *name) { int i; i = 0; while (i < NumNames && strcmp(name, names[i][0])) i++; if (i >= NumNames) printf("%s", name); else printf("%s", names[i][1]); } int IsAlphaNum(int c) { return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= '0' && c <= '9')); } char buf[10000]; int main() { int c; int state; int len; state = 0; len = 0; do { c = getchar(); switch (state) { case 0: if (IsAlphaNum(c)) { buf[len] = c; len++; state = 1; } else { if (c != EOF) putchar(c); } break; case 1: if (IsAlphaNum(c)) { buf[len] = c; len++; } else { buf[len] = '\0'; PrintName(buf); len = 0; if (c != EOF) putchar(c); state = 0; } break; } } while (c != EOF); return 0; } ntl-6.2.1/src/ppscript000644 000765 000024 00000000275 12377144456 015215 0ustar00shoupstaff000000 000000 #!/bin/bash VIM=$HOME/Applications/MacVim/mvim cd ../doc for i in $* do name=`basename $i .txt` cp $name.txt $name.cpp $VIM $name.cpp '+set nu!' '+TOhtml' '+w' '+qa!' done ntl-6.2.1/src/quad_float.c000644 000765 000024 00000041523 12377144456 015712 0ustar00shoupstaff000000 000000 /* Copyright (C) 1997, 1998, 1999, 2000 Victor Shoup This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ***************************************************** The quad_float package is derived from the doubledouble package of Keith Briggs. However, the version employed in NTL has been extensively modified. Below, I attach the copyright notice from the original doubledouble package, which is currently available at http://www.labs.bt.com/people/briggsk2 ***************************************************** Copyright (C) 1997 Keith Martin Briggs Except where otherwise indicated, this program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include NTL_START_IMPL #if (defined(__GNUC__) && NTL_EXT_DOUBLE && (defined(__i386__) || defined(__i486__) || defined(__i586__))) #if (!defined(NTL_X86_FIX) && !defined(NTL_NO_X86_FIX)) #define NTL_X86_FIX #endif #endif #if (NTL_EXT_DOUBLE && !defined(NTL_X86_FIX)) #define DOUBLE volatile double #else #define DOUBLE double #endif #ifdef NTL_X86_FIX #define START_FIX \ volatile unsigned short __old_cw, __new_cw; \ asm volatile ("fnstcw %0":"=m" (__old_cw)); \ __new_cw = (__old_cw & ~0x300) | 0x200; \ asm volatile ("fldcw %0": :"m" (__new_cw)); #define END_FIX asm volatile ("fldcw %0": :"m" (__old_cw)); #else #define START_FIX #define END_FIX #endif static void normalize(quad_float& z, const double& xhi, const double& xlo) { START_FIX DOUBLE u, v; u = xhi + xlo; v = xhi - u; v = v + xlo; z.hi = u; z.lo = v; END_FIX } #if (NTL_BITS_PER_LONG >= NTL_DOUBLE_PRECISION) quad_float to_quad_float(long n) { START_FIX DOUBLE xhi, xlo; DOUBLE u, v; xhi = double(n); // Because we are assuming 2's compliment integer // arithmetic, the following prevents long(xhi) from overflowing. if (n > 0) xlo = double(n+long(-xhi)); else xlo = double(n-long(xhi)); // renormalize...just to be safe u = xhi + xlo; v = xhi - u; v = v + xlo; END_FIX return quad_float(u, v); } quad_float to_quad_float(unsigned long n) { START_FIX DOUBLE xhi, xlo, t; DOUBLE u, v; const double bnd = double(1L << (NTL_BITS_PER_LONG-2))*4.0; xhi = double(n); if (xhi >= bnd) t = xhi - bnd; else t = xhi; // we use the "to_long" function here to be as portable as possible. long llo = to_long(n - (unsigned long)(t)); xlo = double(llo); // renormalize...just to be safe u = xhi + xlo; v = xhi - u; v = v + xlo; END_FIX return quad_float(u, v); } #endif long quad_float::oprec = 10; void quad_float::SetOutputPrecision(long p) { if (p < 1) p = 1; if (NTL_OVERFLOW(p, 1, 0)) Error("quad_float: output precision too big"); oprec = p; } quad_float operator +(const quad_float& x, const quad_float& y ) { START_FIX DOUBLE H, h, T, t, S, s, e, f; DOUBLE t1; S = x.hi + y.hi; T = x.lo + y.lo; e = S - x.hi; f = T - x.lo; t1 = S-e; t1 = x.hi-t1; s = y.hi-e; s = s + t1; t1 = T-f; t1 = x.lo-t1; t = y.lo-f; t = t + t1; s = s + T; H = S + s; h = S - H; h = h + s; h = h + t; e = H + h; f = H - e; f = f + h; END_FIX return quad_float(e, f); } quad_float& operator +=(quad_float& x, const quad_float& y ) { START_FIX DOUBLE H, h, T, t, S, s, e, f; DOUBLE t1; S = x.hi + y.hi; T = x.lo + y.lo; e = S - x.hi; f = T - x.lo; t1 = S-e; t1 = x.hi-t1; s = y.hi-e; s = s + t1; t1 = T-f; t1 = x.lo-t1; t = y.lo-f; t = t + t1; s = s + T; H = S + s; h = S - H; h = h + s; h = h + t; e = H + h; f = H - e; f = f + h; x.hi = e; x.lo = f; END_FIX return x; } quad_float operator -(const quad_float& x, const quad_float& y ) { START_FIX DOUBLE H, h, T, t, S, s, e, f; DOUBLE t1, yhi, ylo; yhi = -y.hi; ylo = -y.lo; S = x.hi + yhi; T = x.lo + ylo; e = S - x.hi; f = T - x.lo; t1 = S-e; t1 = x.hi-t1; s = yhi-e; s = s + t1; t1 = T-f; t1 = x.lo-t1; t = ylo-f; t = t + t1; s = s + T; H = S + s; h = S - H; h = h + s; h = h + t; e = H + h; f = H - e; f = f + h; END_FIX return quad_float(e, f); } quad_float& operator -=(quad_float& x, const quad_float& y ) { START_FIX DOUBLE H, h, T, t, S, s, e, f; DOUBLE t1, yhi, ylo; yhi = -y.hi; ylo = -y.lo; S = x.hi + yhi; T = x.lo + ylo; e = S - x.hi; f = T - x.lo; t1 = S-e; t1 = x.hi-t1; s = yhi-e; s = s + t1; t1 = T-f; t1 = x.lo-t1; t = ylo-f; t = t + t1; s = s + T; H = S + s; h = S - H; h = h + s; h = h + t; e = H + h; f = H - e; f = f + h; x.hi = e; x.lo = f; END_FIX return x; } quad_float operator -(const quad_float& x) { START_FIX DOUBLE xhi, xlo, u, v; xhi = -x.hi; xlo = -x.lo; // it is a good idea to renormalize here, just in case // the rounding rule depends on sign, and thus we will // maintain the "normal form" for quad_float's. u = xhi + xlo; v = xhi - u; v = v + xlo; END_FIX return quad_float(u, v); } quad_float operator *(const quad_float& x,const quad_float& y ) { START_FIX DOUBLE hx, tx, hy, ty, C, c; DOUBLE t1, t2; C = NTL_QUAD_FLOAT_SPLIT*x.hi; hx = C-x.hi; c = NTL_QUAD_FLOAT_SPLIT*y.hi; hx = C-hx; tx = x.hi-hx; hy = c-y.hi; C = x.hi*y.hi; hy = c-hy; ty = y.hi-hy; // c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(x.hi*y.lo+x.lo*y.hi); t1 = hx*hy; t1 = t1-C; t2 = hx*ty; t1 = t1+t2; t2 = tx*hy; t1 = t1+t2; t2 = tx*ty; c = t1+t2; t1 = x.hi*y.lo; t2 = x.lo*y.hi; t1 = t1+t2; c = c + t1; hx = C+c; tx = C-hx; tx = tx+c; END_FIX return quad_float(hx, tx); } quad_float& operator *=(quad_float& x,const quad_float& y ) { START_FIX DOUBLE hx, tx, hy, ty, C, c; DOUBLE t1, t2; C = NTL_QUAD_FLOAT_SPLIT*x.hi; hx = C-x.hi; c = NTL_QUAD_FLOAT_SPLIT*y.hi; hx = C-hx; tx = x.hi-hx; hy = c-y.hi; C = x.hi*y.hi; hy = c-hy; ty = y.hi-hy; // c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(x.hi*y.lo+x.lo*y.hi); t1 = hx*hy; t1 = t1-C; t2 = hx*ty; t1 = t1+t2; t2 = tx*hy; t1 = t1+t2; t2 = tx*ty; c = t1+t2; t1 = x.hi*y.lo; t2 = x.lo*y.hi; t1 = t1+t2; c = c + t1; hx = C+c; tx = C-hx; tx = tx+c; x.hi = hx; x.lo = tx; END_FIX return x; } quad_float operator /(const quad_float& x, const quad_float& y ) { START_FIX DOUBLE hc, tc, hy, ty, C, c, U, u; DOUBLE t1; C = x.hi/y.hi; c = NTL_QUAD_FLOAT_SPLIT*C; hc = c-C; u = NTL_QUAD_FLOAT_SPLIT*y.hi; hc = c-hc; tc = C-hc; hy = u-y.hi; U = C * y.hi; hy = u-hy; ty = y.hi-hy; // u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; u = hc*hy; u = u-U; t1 = hc*ty; u = u+t1; t1 = tc*hy; u = u+t1; t1 = tc*ty; u = u+t1; // c = ((((x.hi-U)-u)+x.lo)-C*y.lo)/y.hi; c = x.hi-U; c = c-u; c = c+x.lo; t1 = C*y.lo; c = c - t1; c = c/y.hi; hy = C+c; ty = C-hy; ty = ty+c; END_FIX return quad_float(hy, ty); } quad_float& operator /=(quad_float& x, const quad_float& y ) { START_FIX DOUBLE hc, tc, hy, ty, C, c, U, u; DOUBLE t1; C = x.hi/y.hi; c = NTL_QUAD_FLOAT_SPLIT*C; hc = c-C; u = NTL_QUAD_FLOAT_SPLIT*y.hi; hc = c-hc; tc = C-hc; hy = u-y.hi; U = C * y.hi; hy = u-hy; ty = y.hi-hy; // u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; u = hc*hy; u = u-U; t1 = hc*ty; u = u+t1; t1 = tc*hy; u = u+t1; t1 = tc*ty; u = u+t1; // c = ((((x.hi-U)-u)+x.lo)-C*y.lo)/y.hi; c = x.hi-U; c = c-u; c = c+x.lo; t1 = C*y.lo; c = c - t1; c = c/y.hi; hy = C+c; ty = C-hy; ty = ty+c; x.hi = hy; x.lo = ty; END_FIX return x; } quad_float sqrt(const quad_float& y) { if (y.hi < 0.0) Error("Quad: attempto to take square root of negative number"); if (y.hi == 0.0) return quad_float(0.0,0.0); double c; c = sqrt(y.hi); ForceToMem(&c); // This is fairly paranoid, but it doesn't cost too much. START_FIX DOUBLE p,q,hx,tx,u,uu,cc; DOUBLE t1; p = NTL_QUAD_FLOAT_SPLIT*c; hx = (c-p); hx = hx+p; tx = c-hx; p = hx*hx; q = hx*tx; q = q+q; u = p+q; uu = p-u; uu = uu+q; t1 = tx*tx; uu = uu+t1; cc = y.hi-u; cc = cc-uu; cc = cc+y.lo; t1 = c+c; cc = cc/t1; hx = c+cc; tx = c-hx; tx = tx+cc; END_FIX return quad_float(hx, tx); } void power(quad_float& z, const quad_float& a, long e) { quad_float res, u; unsigned long k; if (e < 0) k = -((unsigned long) e); else k = e; res = 1.0; u = a; while (k) { if (k & 1) res = res * u; k = k >> 1; if (k) u = u * u; } if (e < 0) z = 1.0/res; else z = res; } void power2(quad_float& z, long e) { z.hi = _ntl_ldexp(1.0, e); z.lo = 0; } long to_long(const quad_float& x) { double fhi, flo; fhi = floor(x.hi); if (fhi == x.hi) flo = floor(x.lo); else flo = 0; // the following code helps to prevent unnecessary integer overflow, // and guarantees that to_long(to_quad_float(a)) == a, for all long a, // provided long's are not too wide. if (fhi > 0) return long(flo) - long(-fhi); else return long(fhi) + long(flo); } // This version of ZZ to quad_float coversion relies on the // precise rounding rules implemented by the ZZ to double conversion. void conv(quad_float& z, const ZZ& a) { double xhi, xlo; conv(xhi, a); if (!IsFinite(&xhi)) { z.hi = xhi; z.lo = 0; return; } NTL_ZZRegister(t); conv(t, xhi); sub(t, a, t); conv(xlo, t); normalize(z, xhi, xlo); // The following is just paranoia. if (fabs(z.hi) < NTL_FDOUBLE_PRECISION && z.lo != 0) Error("internal error: ZZ to quad_float conversion"); } void conv(ZZ& z, const quad_float& x) { NTL_ZZRegister(t1); NTL_ZZRegister(t2); NTL_ZZRegister(t3); double fhi, flo; fhi = floor(x.hi); if (fhi == x.hi) { flo = floor(x.lo); conv(t1, fhi); conv(t2, flo); add(z, t1, t2); } else conv(z, fhi); } ostream& operator<<(ostream& s, const quad_float& a) { quad_float aa = a; if (!IsFinite(&aa)) { s << "NaN"; return s; } long old_p = RR::precision(); long old_op = RR::OutputPrecision(); RR::SetPrecision(long(3.33*quad_float::oprec) + 10); RR::SetOutputPrecision(quad_float::oprec); NTL_THREAD_LOCAL static RR t; conv(t, a); s << t; RR::SetPrecision(old_p); RR::SetOutputPrecision(old_op); return s; } istream& operator>>(istream& s, quad_float& x) { long old_p = RR::precision(); RR::SetPrecision(4*NTL_DOUBLE_PRECISION); NTL_THREAD_LOCAL static RR t; s >> t; conv(x, t); RR::SetPrecision(old_p); return s; } void random(quad_float& x) { long old_p = RR::precision(); RR::SetPrecision(4*NTL_DOUBLE_PRECISION); NTL_THREAD_LOCAL static RR t; random(t); conv(x, t); RR::SetPrecision(old_p); } quad_float random_quad_float() { quad_float x; random(x); return x; } long IsFinite(quad_float *x) { return IsFinite(&x->hi) && IsFinite(&x->lo); } long PrecisionOK() { START_FIX long k; DOUBLE l1 = (double)1; DOUBLE lh = 1/(double)2; DOUBLE epsilon; DOUBLE fudge, oldfudge; epsilon = l1; fudge = l1+l1; k = 0; do { k++; epsilon = epsilon * lh; oldfudge = fudge; fudge = l1 + epsilon; } while (fudge > l1 && fudge < oldfudge); END_FIX return k == NTL_DOUBLE_PRECISION; } quad_float floor(const quad_float& x) { double fhi = floor(x.hi); if (fhi != x.hi) return quad_float(fhi, 0.0); else { double flo = floor(x.lo); quad_float z; normalize(z, fhi, flo); return z; } } quad_float ceil(const quad_float& x) { return -floor(-x); } quad_float trunc(const quad_float& x) { if (x>=0.0) return floor(x); else return -floor(-x); } long compare(const quad_float& x, const quad_float& y) { if (x.hi > y.hi) return 1; else if (x.hi < y.hi) return -1; else if (x.lo > y.lo) return 1; else if (x.lo < y.lo) return -1; else return 0; } quad_float fabs(const quad_float& x) { if (x.hi>=0.0) return x; else return -x; } quad_float to_quad_float(const char *s) { quad_float x; long old_p = RR::precision(); RR::SetPrecision(4*NTL_DOUBLE_PRECISION); NTL_THREAD_LOCAL static RR t; conv(t, s); conv(x, t); RR::SetPrecision(old_p); return x; } quad_float ldexp(const quad_float& x, long exp) { // x*2^exp double xhi, xlo; quad_float z; xhi = _ntl_ldexp(x.hi, exp); xlo = _ntl_ldexp(x.lo, exp); normalize(z, xhi, xlo); return z; } quad_float exp(const quad_float& x) { // New version 97 Aug 05 /* ! Calculate a quadruple-precision exponential ! Method: ! x x.log2(e) nint[x.log2(e)] + frac[x.log2(e)] ! e = 2 = 2 ! ! iy fy ! = 2 . 2 ! Then ! fy y.loge(2) ! 2 = e ! ! Now y.loge(2) will be less than 0.3466 in absolute value. ! This is halved and a Pade aproximation is used to approximate e^x over ! the region (-0.1733, +0.1733). This approximation is then squared. */ if (x.hiDBL_MAX_10_EXP*2.302585092994045684017991) { Error("exp(quad_float): overflow"); } // changed this from "const" to "static" in v5.3, since "const" // causes the initialization to be performed with *every* invocation. NTL_THREAD_LOCAL static quad_float Log2 = to_quad_float("0.6931471805599453094172321214581765680755"); quad_float y,temp,ysq,sum1,sum2; long iy; y=x/Log2; temp = floor(y+0.5); iy = to_long(temp); y=(y-temp)*Log2; y=ldexp(y,-1L); ysq=y*y; sum1=y*((((ysq+3960.0)*ysq+2162160.0)*ysq+302702400.0)*ysq+8821612800.0); sum2=(((90.0*ysq+110880.0)*ysq+30270240.0)*ysq+2075673600.0)*ysq+17643225600.0; /* ! sum2 + sum1 2.sum1 ! Now approximation = ----------- = 1 + ----------- = 1 + 2.temp ! sum2 - sum1 sum2 - sum1 ! ! Then (1 + 2.temp)^2 = 4.temp.(1 + temp) + 1 */ temp=sum1/(sum2-sum1); y=temp*(temp+1); y=ldexp(y,2L); return ldexp(y+1,iy); } quad_float log(const quad_float& t) { // Newton method. See Bailey, MPFUN if (t.hi <= 0.0) { Error("log(quad_float): argument must be positive"); } double s1 = log(t.hi); ForceToMem(&s1); // Again, this is fairly paranoid. quad_float s; s = s1; quad_float e; e=exp(s); return s+(t-e)/e; // Newton step } long operator> (const quad_float& x, const quad_float& y) { return (x.hi> y.hi) || (x.hi==y.hi && x.lo> y.lo); } long operator>=(const quad_float& x, const quad_float& y) { return (x.hi>y.hi) || (x.hi==y.hi && x.lo>=y.lo); } long operator< (const quad_float& x, const quad_float& y) { return (x.hi< y.hi) || (x.hi==y.hi && x.lo< y.lo); } long operator<=(const quad_float& x, const quad_float& y) { return (x.hi NTL_CLIENT long SubsetSumSolution(const vec_ZZ& z) { long n = z.length()-3; long j; if (z(n+1) != 0) return 0; if (z(n+2) != -1 && z(n+2) != 1) return 0; for (j = 1; j <= n; j++) if (z(j) != -1 && z(j) != 1) return 0; return 1; } int main() { RR::SetPrecision(150); long n, b, size; cerr << "n: "; cin >> n; cerr << "b: "; cin >> b; cerr << "size: "; cin >> size; cerr << "prune: "; long prune; cin >> prune; ZZ seed; cerr << "seed: "; cin >> seed; if (seed != 0) SetSeed(seed); char alg; cerr << "alg [fqQxr]: "; cin >> alg; double TotalTime = 0; long TotalSucc = 0; long iter; for (iter = 1; iter <= 20; iter++) { vec_ZZ a; a.SetLength(n); ZZ bound; LeftShift(bound, to_ZZ(1), b); long i; for (i = 1; i <= n; i++) { RandomBnd(a(i), bound); a(i) += 1; } ZZ S; do { RandomLen(S, n+1); } while (weight(S) != n/2+1); ZZ s; clear(s); for (i = 1; i <= n; i++) if (bit(S, i-1)) s += a(i); mat_ZZ B(INIT_SIZE, n+1, n+3); for (i = 1; i <= n; i++) { B(i, i) = 2; B(i, n+1) = a(i) * n; B(i, n+3) = n; } for (i = 1; i <= n; i++) B(n+1, i) = 1; B(n+1, n+1) = s * n; B(n+1, n+2) = 1; B(n+1, n+3) = n; B(n+1, n+3) *= n/2; swap(B(1), B(n+1)); for (i = 2; i <= n; i++) { long j = RandomBnd(n-i+2) + i; swap(B(i), B(j)); } double t; LLLStatusInterval = 10; t = GetTime(); switch (alg) { case 'f': BKZ_FP(B, 0.99, size, prune, SubsetSumSolution); break; case 'q': BKZ_QP(B, 0.99, size, prune, SubsetSumSolution); break; case 'Q': BKZ_QP1(B, 0.99, size, prune, SubsetSumSolution); break; case 'x': BKZ_XD(B, 0.99, size, prune, SubsetSumSolution); break; case 'r': BKZ_RR(B, 0.99, size, prune, SubsetSumSolution); break; default: Error("invalid algorithm"); } t = GetTime()-t; long succ = 0; for (i = 1; i <= n+1; i++) if (SubsetSumSolution(B(i))) succ = 1; TotalTime += t; TotalSucc += succ; if (succ) cerr << "+"; else cerr << "-"; } cerr << "\n"; cerr << "number of success: " << TotalSucc << "\n"; cerr << "average time: " << TotalTime/20 << "\n"; return 0; } ntl-6.2.1/src/tools.c000644 000765 000024 00000004651 12377144456 014734 0ustar00shoupstaff000000 000000 #include #include #include #include void _ntl_abort_cxx_callback() { if (NTL_NNS ErrorCallback) (*NTL_NNS ErrorCallback)(); } NTL_START_IMPL NTL_THREAD_LOCAL void (*ErrorCallback)() = 0; void Error(const char *s) { cerr << s << "\n"; _ntl_abort(); } // The following implementation of CharToIntVal is completely portable. long CharToIntVal(long a) { switch (a) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': return 10; case 'B': return 11; case 'C': return 12; case 'D': return 13; case 'E': return 14; case 'F': return 15; case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15; default: return -1; } } // The following implementation of IntValToChar is completely portable. char IntValToChar(long a) { switch (a) { case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4'; case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9'; case 10: return 'a'; case 11: return 'b'; case 12: return 'c'; case 13: return 'd'; case 14: return 'e'; case 15: return 'f'; default: Error("IntValToChar: bad arg"); } return 0; // to supress warnings } long IsWhiteSpace(long a) { if (a > NTL_MAX_INT || a < NTL_MIN_INT) return 0; int b = (int) a; if (isspace(b)) return 1; else return 0; } long SkipWhiteSpace(istream& s) { long c; c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c == EOF) return 0; else return 1; } long IsEOFChar(long c) { return c == EOF; } void PrintTime(ostream& s, double t) { long hh, mm, ss; ss = long(t + 0.5); hh = ss/3600; ss = ss - hh*3600; mm = ss/60; ss = ss - mm*60; if (hh > 0) s << hh << ":"; if (hh > 0 || mm > 0) { if (hh > 0 && mm < 10) s << "0"; s << mm << ":"; } if ((hh > 0 || mm > 0) && ss < 10) s << "0"; s << ss; } NTL_END_IMPL ntl-6.2.1/src/unixify000644 000765 000024 00000000562 12377144456 015043 0ustar00shoupstaff000000 000000 rm -r unix mkdir unix mkdir unix/src mkdir unix/include mkdir unix/include/NTL mkdir unix/doc cp ../README unix/README for i in $1 do cp $i unix/src/$i done for i in $2 do cp ../include/NTL/$i unix/include/NTL/$i done for i in $3 do cp ../doc/$i unix/doc/$i done cp ../include/NTL/def_config.h unix/include/NTL/config.h cp def_makefile unix/src/makefile ntl-6.2.1/src/vec_GF2.c000644 000765 000024 00000030101 12377144456 014774 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL // FIXME: why do vec_GF2 and GF2X use different strategies for // keeping high order bits cleared? I don't think it matters // much, but it is strange. void vec_GF2::SetLength(long n) { long len = length(); if (n == len) return; if (n < 0) Error("negative length in vec_GF2::SetLength"); if (NTL_OVERFLOW(n, 1, 0)) Error("vec_GF2::SetLength: excessive length"); if (fixed()) Error("SetLength: can't change this vector's length"); long wdlen = (n+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; if (n < len) { // have to clear bits n..len-1 long q = n/NTL_BITS_PER_LONG; long p = n - q*NTL_BITS_PER_LONG; _ntl_ulong *x = rep.elts(); x[q] &= (1UL << p) - 1UL; long q1 = (len-1)/NTL_BITS_PER_LONG; long i; for (i = q+1; i <= q1; i++) x[i] = 0; _len = n; rep.QuickSetLength(wdlen); return; } long maxlen = MaxLength(); if (n <= maxlen) { _len = n; rep.QuickSetLength(wdlen); return; } long alloc = rep.MaxLength(); if (wdlen <= alloc) { _len = n; _maxlen = (n << 1); rep.QuickSetLength(wdlen); return; } // have to grow vector and initialize to zero rep.SetLength(wdlen); wdlen = rep.MaxLength(); // careful! rep.MaxLength() may exceed the // old value of wdlen...this is due to // the awkward semantics of WordVector. _ntl_ulong *x = rep.elts(); long i; for (i = alloc; i < wdlen; i++) x[i] = 0; _len = n; _maxlen = (n << 1); } void vec_GF2::SetLength(long n, GF2 a) { long old_len = length(); SetLength(n); if (!IsZero(a) && old_len < n) { long i; for (i = old_len; i < n; i++) put(i, a); } } vec_GF2& vec_GF2::operator=(const vec_GF2& a) { if (this == &a) return *this; long n = a.length(); SetLength(n); long wdlen = (n+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; _ntl_ulong *x = rep.elts(); const _ntl_ulong *y = a.rep.elts(); long i; for (i = 0; i < wdlen; i++) x[i] = y[i]; return *this; } void vec_GF2::kill() { if (fixed()) Error("can't kill this vec_GF2"); rep.kill(); _len = _maxlen = 0; } void vec_GF2::SetMaxLength(long n) { long oldlen = length(); if (n > oldlen) { SetLength(n); SetLength(oldlen); } } void vec_GF2::FixLength(long n) { if (MaxLength() > 0 || fixed()) Error("can't fix this vector"); SetLength(n); _maxlen |= 1; } const GF2 vec_GF2::get(long i) const { const vec_GF2& v = *this; if (i < 0 || i >= v.length()) Error("vec_GF2: subscript out of range"); long q = i/NTL_BITS_PER_LONG; long p = i - q*NTL_BITS_PER_LONG; if (v.rep[q] & (1UL << p)) return to_GF2(1); else return to_GF2(0); } ref_GF2 vec_GF2::operator[](long i) { vec_GF2& v = *this; if (i < 0 || i >= v.length()) Error("vec_GF2: subscript out of range"); long q = i/NTL_BITS_PER_LONG; long p = i - q*NTL_BITS_PER_LONG; return ref_GF2(INIT_LOOP_HOLE, &v.rep[q], p); } static void SetBit(vec_GF2& v, long i) { if (i < 0 || i >= v.length()) Error("vec_GF2: subscript out of range"); long q = i/NTL_BITS_PER_LONG; long p = i - q*NTL_BITS_PER_LONG; v.rep[q] |= (1UL << p); } static void ClearBit(vec_GF2& v, long i) { if (i < 0 || i >= v.length()) Error("vec_GF2: subscript out of range"); long q = i/NTL_BITS_PER_LONG; long p = i - q*NTL_BITS_PER_LONG; v.rep[q] &= ~(1UL << p); } void vec_GF2::put(long i, GF2 a) { if (a == 1) SetBit(*this, i); else ClearBit(*this, i); } void vec_GF2::swap(vec_GF2& y) { long xf = fixed(); long yf = y.fixed(); if (xf != yf || (xf && length() != y.length())) Error("swap: can't swap these vec_GF2s"); ::swap(rep, y.rep); ::swap(_len, y._len); ::swap(_maxlen, y._maxlen); } void vec_GF2::append(GF2 a) { long n = length(); SetLength(n+1); put(n, a); } void vec_GF2::append(const vec_GF2& a) { long a_len = a.length(); long x_len = length(); if (a_len == 0) return; if (x_len == 0) { *this = a; return; } SetLength(x_len + a_len); // new bits are guaranteed zero ShiftAdd(rep.elts(), a.rep.elts(), a.rep.length(), x_len); } long operator==(const vec_GF2& a, const vec_GF2& b) { return a.length() == b.length() && a.rep == b.rep; } istream & operator>>(istream& s, vec_GF2& a) { NTL_ZZRegister(ival); long c; if (!s) Error("bad vec_GF2 input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != '[') { Error("bad vec_GF2 input"); } vec_GF2 ibuf; ibuf.SetLength(0); s.get(); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } while (c != ']' && c != EOF) { if (!(s >> ival)) Error("bad vec_GF2 input"); append(ibuf, to_GF2(ival)); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } } if (c == EOF) Error("bad vec_GF2 input"); s.get(); a = ibuf; return s; } ostream& operator<<(ostream& s, const vec_GF2& a) { long i, n; GF2 c; n = a.length(); s << '['; for (i = 0; i < n; i++) { c = a.get(i); if (c == 0) s << "0"; else s << "1"; if (i < n-1) s << " "; } s << ']'; return s; } // math operations: void mul(vec_GF2& x, const vec_GF2& a, GF2 b) { x = a; if (b == 0) clear(x); } void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b) { long blen = a.length(); if (b.length() != blen) Error("vec_GF2 add: length mismatch"); x.SetLength(blen); long wlen = a.rep.length(); long i; _ntl_ulong *xp = x.rep.elts(); const _ntl_ulong *ap = a.rep.elts(); const _ntl_ulong *bp = b.rep.elts(); for (i = 0; i < wlen; i++) xp[i] = ap[i] ^ bp[i]; } void clear(vec_GF2& x) { long wlen = x.rep.length(); long i; _ntl_ulong *xp = x.rep.elts(); for (i = 0; i < wlen; i++) xp[i] = 0; } long IsZero(const vec_GF2& x) { long wlen = x.rep.length(); long i; const _ntl_ulong *xp = x.rep.elts(); for (i = 0; i < wlen; i++) if (xp[i] != 0) return 0; return 1; } vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b) { vec_GF2 res; add(res, a, b); NTL_OPT_RETURN(vec_GF2, res); } vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b) { vec_GF2 res; add(res, a, b); NTL_OPT_RETURN(vec_GF2, res); } static void ShiftToHigh(vec_GF2& x, const vec_GF2& a, long n) // assumes 0 <= n < a.length() { long l = a.length(); x.SetLength(l); _ntl_ulong *xp = x.rep.elts(); const _ntl_ulong *ap = a.rep.elts(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long sa = a.rep.length(); long i; if (bn == 0) { for (i = sa-1; i >= wn; i--) xp[i] = ap[i-wn]; for (i = wn-1; i >= 0; i--) xp[i] = 0; } else { for (i = sa-1; i >= wn+1; i--) xp[i] = (ap[i-wn] << bn) | (ap[i-wn-1] >> (NTL_BITS_PER_LONG-bn)); xp[wn] = ap[0] << bn; for (i = wn-1; i >= 0; i--) xp[i] = 0; } long p = l % NTL_BITS_PER_LONG; if (p != 0) xp[sa-1] &= (1UL << p) - 1UL; } static void ShiftToLow(vec_GF2& x, const vec_GF2& a, long n) // assumes 0 <= n < a.length() { long l = a.length(); x.SetLength(l); _ntl_ulong *xp = x.rep.elts(); const _ntl_ulong *ap = a.rep.elts(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long sa = a.rep.length(); long i; if (bn == 0) { for (i = 0; i < sa-wn; i++) xp[i] = ap[i+wn]; } else { for (i = 0; i < sa-wn-1; i++) xp[i] = (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn)); xp[sa-wn-1] = ap[sa-1] >> bn; } for (i = sa-wn; i < sa; i++) xp[i] = 0; } void shift(vec_GF2& x, const vec_GF2& a, long n) { long l = a.length(); if (n >= l || n <= -l) { x.SetLength(l); clear(x); } else if (n < 0) ShiftToLow(x, a, -n); // |n| < l, so -n won't overflow! else ShiftToHigh(x, a, n); } // This code is simply canibalized from GF2X.c... // so much for "code re-use" and "modularity" static const _ntl_ulong revtab[256] = { 0UL, 128UL, 64UL, 192UL, 32UL, 160UL, 96UL, 224UL, 16UL, 144UL, 80UL, 208UL, 48UL, 176UL, 112UL, 240UL, 8UL, 136UL, 72UL, 200UL, 40UL, 168UL, 104UL, 232UL, 24UL, 152UL, 88UL, 216UL, 56UL, 184UL, 120UL, 248UL, 4UL, 132UL, 68UL, 196UL, 36UL, 164UL, 100UL, 228UL, 20UL, 148UL, 84UL, 212UL, 52UL, 180UL, 116UL, 244UL, 12UL, 140UL, 76UL, 204UL, 44UL, 172UL, 108UL, 236UL, 28UL, 156UL, 92UL, 220UL, 60UL, 188UL, 124UL, 252UL, 2UL, 130UL, 66UL, 194UL, 34UL, 162UL, 98UL, 226UL, 18UL, 146UL, 82UL, 210UL, 50UL, 178UL, 114UL, 242UL, 10UL, 138UL, 74UL, 202UL, 42UL, 170UL, 106UL, 234UL, 26UL, 154UL, 90UL, 218UL, 58UL, 186UL, 122UL, 250UL, 6UL, 134UL, 70UL, 198UL, 38UL, 166UL, 102UL, 230UL, 22UL, 150UL, 86UL, 214UL, 54UL, 182UL, 118UL, 246UL, 14UL, 142UL, 78UL, 206UL, 46UL, 174UL, 110UL, 238UL, 30UL, 158UL, 94UL, 222UL, 62UL, 190UL, 126UL, 254UL, 1UL, 129UL, 65UL, 193UL, 33UL, 161UL, 97UL, 225UL, 17UL, 145UL, 81UL, 209UL, 49UL, 177UL, 113UL, 241UL, 9UL, 137UL, 73UL, 201UL, 41UL, 169UL, 105UL, 233UL, 25UL, 153UL, 89UL, 217UL, 57UL, 185UL, 121UL, 249UL, 5UL, 133UL, 69UL, 197UL, 37UL, 165UL, 101UL, 229UL, 21UL, 149UL, 85UL, 213UL, 53UL, 181UL, 117UL, 245UL, 13UL, 141UL, 77UL, 205UL, 45UL, 173UL, 109UL, 237UL, 29UL, 157UL, 93UL, 221UL, 61UL, 189UL, 125UL, 253UL, 3UL, 131UL, 67UL, 195UL, 35UL, 163UL, 99UL, 227UL, 19UL, 147UL, 83UL, 211UL, 51UL, 179UL, 115UL, 243UL, 11UL, 139UL, 75UL, 203UL, 43UL, 171UL, 107UL, 235UL, 27UL, 155UL, 91UL, 219UL, 59UL, 187UL, 123UL, 251UL, 7UL, 135UL, 71UL, 199UL, 39UL, 167UL, 103UL, 231UL, 23UL, 151UL, 87UL, 215UL, 55UL, 183UL, 119UL, 247UL, 15UL, 143UL, 79UL, 207UL, 47UL, 175UL, 111UL, 239UL, 31UL, 159UL, 95UL, 223UL, 63UL, 191UL, 127UL, 255UL }; static inline _ntl_ulong rev1(_ntl_ulong a) { return NTL_BB_REV_CODE; } void reverse(vec_GF2& c, const vec_GF2& a) // c = reverse of a { long n = a.length(); c = a; if (n <= 0) { return; } long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (bn != 0) { wn++; bn = NTL_BITS_PER_LONG - bn; } _ntl_ulong *cp = c.rep.elts(); long i; if (bn != 0) { for (i = wn-1; i >= 1; i--) cp[i] = (cp[i] << bn) | (cp[i-1] >> (NTL_BITS_PER_LONG-bn)); cp[0] = cp[0] << bn; } for (i = 0; i < wn/2; i++) { _ntl_ulong t; t = cp[i]; cp[i] = cp[wn-1-i]; cp[wn-1-i] = t; } for (i = 0; i < wn; i++) cp[i] = rev1(cp[i]); } static long weight1(_ntl_ulong a) { long res = 0; while (a) { if (a & 1) res ++; a >>= 1; } return res; } long weight(const vec_GF2& a) { long wlen = a.rep.length(); long res = 0; long i; for (i = 0; i < wlen; i++) res += weight1(a.rep[i]); return res; } void random(vec_GF2& x, long n) { if (n < 0) Error("random: bad arg"); x.SetLength(n); long wl = x.rep.length(); long i; for (i = 0; i < wl-1; i++) { x.rep[i] = RandomWord(); } if (n > 0) { long pos = n % NTL_BITS_PER_LONG; if (pos == 0) pos = NTL_BITS_PER_LONG; x.rep[wl-1] = RandomBits_ulong(pos); } } void VectorCopy(vec_GF2& x, const vec_GF2& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long wn = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long wm = (m + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; _ntl_ulong *xp = x.rep.elts(); const _ntl_ulong *ap = a.rep.elts(); long i; for (i = 0; i < wm; i++) xp[i] = ap[i]; for (i = wm; i < wn; i++) xp[i] = 0; long p = n % NTL_BITS_PER_LONG; if (p != 0) { xp[wn-1] &= ((1UL << p) - 1UL); } } NTL_END_IMPL ntl-6.2.1/src/vec_GF2E.c000644 000765 000024 00000006746 12377144456 015123 0ustar00shoupstaff000000 000000 #include NTL_START_IMPL static void BasicBlockConstruct(GF2E* x, long n, long d) { long m, j; long i = 0; while (i < n) { m = WV_BlockConstructAlloc(x[i]._GF2E__rep.xrep, d, n-i); for (j = 1; j < m; j++) WV_BlockConstructSet(x[i]._GF2E__rep.xrep, x[i+j]._GF2E__rep.xrep, j); i += m; } } void BlockConstruct(GF2E* x, long n) { if (n <= 0) return; if (!GF2EInfo) Error("GF2E constructor called while modulus undefined"); long d = GF2E::WordLength(); BasicBlockConstruct(x, n, d); } void BlockConstructFromVec(GF2E* x, long n, const GF2E* y) { if (n <= 0) return; long d = y->_GF2E__rep.xrep.MaxLength(); BasicBlockConstruct(x, n, d); long i; for (i = 0; i < n; i++) x[i] = y[i]; } void BlockConstructFromObj(GF2E* x, long n, const GF2E& y) { if (n <= 0) return; long d = y._GF2E__rep.xrep.MaxLength(); BasicBlockConstruct(x, n, d); long i; for (i = 0; i < n; i++) x[i] = y; } void BlockDestroy(GF2E* x, long n) { if (n <= 0) return; long i = 0; long m; while (i < n) { m = WV_BlockDestroy(x[i]._GF2E__rep.xrep); i += m; } } void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b) { long n = min(a.length(), b.length()); long i; GF2X accum, t; clear(accum); for (i = 0; i < n; i++) { mul(t, rep(a[i]), rep(b[i])); add(accum, accum, t); } conv(x, accum); } void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b, long offset) { if (offset < 0) Error("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) Error("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; GF2X accum, t; clear(accum); for (i = offset; i < n; i++) { mul(t, rep(a[i]), rep(b[i-offset])); add(accum, accum, t); } conv(x, accum); } void mul(vec_GF2E& x, const vec_GF2E& a, const GF2E& b_in) { GF2E b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_GF2E& x, const vec_GF2E& a, GF2 b) { x = a; if (b == 0) clear(x); } void add(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b) { long n = a.length(); if (b.length() != n) Error("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void clear(vec_GF2E& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } long IsZero(const vec_GF2E& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_GF2E operator+(const vec_GF2E& a, const vec_GF2E& b) { vec_GF2E res; add(res, a, b); NTL_OPT_RETURN(vec_GF2E, res); } vec_GF2E operator-(const vec_GF2E& a, const vec_GF2E& b) { vec_GF2E res; sub(res, a, b); NTL_OPT_RETURN(vec_GF2E, res); } vec_GF2E operator-(const vec_GF2E& a) { vec_GF2E res; negate(res, a); NTL_OPT_RETURN(vec_GF2E, res); } GF2E operator*(const vec_GF2E& a, const vec_GF2E& b) { GF2E res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_GF2E& x, const vec_GF2E& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-6.2.1/src/vec_RR.c000644 000765 000024 00000004473 12377144456 014756 0ustar00shoupstaff000000 000000 #include NTL_START_IMPL void InnerProduct(RR& xx, const vec_RR& a, const vec_RR& b) { RR t1, x; long n = min(a.length(), b.length()); long i; clear(x); for (i = 1; i <= n; i++) { mul(t1, a(i), b(i)); add(x, x, t1); } xx = x; } void mul(vec_RR& x, const vec_RR& a, const RR& b_in) { RR b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_RR& x, const vec_RR& a, double b_in) { NTL_THREAD_LOCAL static RR b; conv(b, b_in); long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_RR& x, const vec_RR& a, const vec_RR& b) { long n = a.length(); if (b.length() != n) Error("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_RR& x, const vec_RR& a, const vec_RR& b) { long n = a.length(); if (b.length() != n) Error("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void clear(vec_RR& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } void negate(vec_RR& x, const vec_RR& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } long IsZero(const vec_RR& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_RR operator+(const vec_RR& a, const vec_RR& b) { vec_RR res; add(res, a, b); NTL_OPT_RETURN(vec_RR, res); } vec_RR operator-(const vec_RR& a, const vec_RR& b) { vec_RR res; sub(res, a, b); NTL_OPT_RETURN(vec_RR, res); } vec_RR operator-(const vec_RR& a) { vec_RR res; negate(res, a); NTL_OPT_RETURN(vec_RR, res); } RR operator*(const vec_RR& a, const vec_RR& b) { RR res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_RR& x, const vec_RR& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-6.2.1/src/vec_ZZ.c000644 000765 000024 00000004423 12377144456 014771 0ustar00shoupstaff000000 000000 #include NTL_START_IMPL void InnerProduct(ZZ& xx, const vec_ZZ& a, const vec_ZZ& b) { ZZ t1, x; long n = min(a.length(), b.length()); long i; clear(x); for (i = 1; i <= n; i++) { mul(t1, a(i), b(i)); add(x, x, t1); } xx = x; } void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b_in) { ZZ b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_ZZ& x, const vec_ZZ& a, long b) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b) { long n = a.length(); if (b.length() != n) Error("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b) { long n = a.length(); if (b.length() != n) Error("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void clear(vec_ZZ& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } void negate(vec_ZZ& x, const vec_ZZ& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } long IsZero(const vec_ZZ& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_ZZ operator+(const vec_ZZ& a, const vec_ZZ& b) { vec_ZZ res; add(res, a, b); NTL_OPT_RETURN(vec_ZZ, res); } vec_ZZ operator-(const vec_ZZ& a, const vec_ZZ& b) { vec_ZZ res; sub(res, a, b); NTL_OPT_RETURN(vec_ZZ, res); } vec_ZZ operator-(const vec_ZZ& a) { vec_ZZ res; negate(res, a); NTL_OPT_RETURN(vec_ZZ, res); } ZZ operator*(const vec_ZZ& a, const vec_ZZ& b) { ZZ res; InnerProduct(res, a, b); NTL_OPT_RETURN(ZZ, res); } void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-6.2.1/src/vec_ZZ_p.c000644 000765 000024 00000010602 12377144456 015304 0ustar00shoupstaff000000 000000 #include NTL_START_IMPL static void BasicBlockConstruct(ZZ_p* x, long n, long d) { long m, j; long i = 0; while (i < n) { m = ZZ_BlockConstructAlloc(x[i]._ZZ_p__rep, d, n-i); for (j = 1; j < m; j++) ZZ_BlockConstructSet(x[i]._ZZ_p__rep, x[i+j]._ZZ_p__rep, j); i += m; } } void BlockConstruct(ZZ_p* x, long n) { if (n <= 0) return; if (!ZZ_pInfo) Error("ZZ_p constructor called while modulus undefined"); long d = ZZ_p::ModulusSize(); BasicBlockConstruct(x, n, d); } void BlockConstructFromVec(ZZ_p* x, long n, const ZZ_p* y) { if (n <= 0) return; long d = y->_ZZ_p__rep.MaxAlloc() - 1; BasicBlockConstruct(x, n, d); long i; for (i = 0; i < n; i++) x[i] = y[i]; } void BlockConstructFromObj(ZZ_p* x, long n, const ZZ_p& y) { if (n <= 0) return; long d = y._ZZ_p__rep.MaxAlloc() - 1; BasicBlockConstruct(x, n, d); long i; for (i = 0; i < n; i++) x[i] = y; } void BlockDestroy(ZZ_p* x, long n) { if (n <= 0) return; long i = 0; long m; while (i < n) { m = ZZ_BlockDestroy(x[i]._ZZ_p__rep); i += m; } } void conv(vec_ZZ_p& x, const vec_ZZ& a) { long i, n; n = a.length(); x.SetLength(n); ZZ_p* xp = x.elts(); const ZZ* ap = a.elts(); for (i = 0; i < n; i++) conv(xp[i], ap[i]); } void conv(vec_ZZ& x, const vec_ZZ_p& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) x[i] = rep(a[i]); } void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b) { long n = min(a.length(), b.length()); long i; NTL_ZZRegister(accum); NTL_ZZRegister(t); clear(accum); for (i = 0; i < n; i++) { mul(t, rep(a[i]), rep(b[i])); add(accum, accum, t); } conv(x, accum); } void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b, long offset) { if (offset < 0) Error("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) Error("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; NTL_ZZRegister(accum); NTL_ZZRegister(t); clear(accum); for (i = offset; i < n; i++) { mul(t, rep(a[i]), rep(b[i-offset])); add(accum, accum, t); } conv(x, accum); } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_p& b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, long b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b) { long n = a.length(); if (b.length() != n) Error("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b) { long n = a.length(); if (b.length() != n) Error("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void clear(vec_ZZ_p& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } void negate(vec_ZZ_p& x, const vec_ZZ_p& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } long IsZero(const vec_ZZ_p& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_ZZ_p operator+(const vec_ZZ_p& a, const vec_ZZ_p& b) { vec_ZZ_p res; add(res, a, b); NTL_OPT_RETURN(vec_ZZ_p, res); } vec_ZZ_p operator-(const vec_ZZ_p& a, const vec_ZZ_p& b) { vec_ZZ_p res; sub(res, a, b); NTL_OPT_RETURN(vec_ZZ_p, res); } vec_ZZ_p operator-(const vec_ZZ_p& a) { vec_ZZ_p res; negate(res, a); NTL_OPT_RETURN(vec_ZZ_p, res); } ZZ_p operator*(const vec_ZZ_p& a, const vec_ZZ_p& b) { ZZ_p res; InnerProduct(res, a, b); NTL_OPT_RETURN(ZZ_p, res); } void VectorCopy(vec_ZZ_p& x, const vec_ZZ_p& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-6.2.1/src/vec_ZZ_pE.c000644 000765 000024 00000006155 12377144456 015421 0ustar00shoupstaff000000 000000 #include NTL_START_IMPL void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b) { long n = min(a.length(), b.length()); long i; ZZ_pX accum, t; clear(accum); for (i = 0; i < n; i++) { mul(t, rep(a[i]), rep(b[i])); add(accum, accum, t); } conv(x, accum); } void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b, long offset) { if (offset < 0) Error("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) Error("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; ZZ_pX accum, t; clear(accum); for (i = offset; i < n; i++) { mul(t, rep(a[i]), rep(b[i-offset])); add(accum, accum, t); } conv(x, accum); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pE& b_in) { ZZ_pE b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_p& b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, long b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b) { long n = a.length(); if (b.length() != n) Error("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b) { long n = a.length(); if (b.length() != n) Error("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void negate(vec_ZZ_pE& x, const vec_ZZ_pE& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } void clear(vec_ZZ_pE& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } long IsZero(const vec_ZZ_pE& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_ZZ_pE operator+(const vec_ZZ_pE& a, const vec_ZZ_pE& b) { vec_ZZ_pE res; add(res, a, b); NTL_OPT_RETURN(vec_ZZ_pE, res); } vec_ZZ_pE operator-(const vec_ZZ_pE& a, const vec_ZZ_pE& b) { vec_ZZ_pE res; sub(res, a, b); NTL_OPT_RETURN(vec_ZZ_pE, res); } vec_ZZ_pE operator-(const vec_ZZ_pE& a) { vec_ZZ_pE res; negate(res, a); NTL_OPT_RETURN(vec_ZZ_pE, res); } ZZ_pE operator*(const vec_ZZ_pE& a, const vec_ZZ_pE& b) { ZZ_pE res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_ZZ_pE& x, const vec_ZZ_pE& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-6.2.1/src/vec_lzz_p.c000644 000765 000024 00000010577 12377144456 015573 0ustar00shoupstaff000000 000000 #include NTL_START_IMPL void conv(vec_zz_p& x, const vec_ZZ& a) { long i, n; n = a.length(); x.SetLength(n); zz_p* xp = x.elts(); const ZZ* ap = a.elts(); for (i = 0; i < n; i++) conv(xp[i], ap[i]); } void conv(vec_ZZ& x, const vec_zz_p& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) x[i] = rep(a[i]); } void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b) { long n = min(a.length(), b.length()); long i; zz_p accum, t; clear(accum); for (i = 0; i < n; i++) { mul(t, a[i], b[i]); add(accum, accum, t); } x = accum; } void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b, long offset) { if (offset < 0) Error("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) Error("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; zz_p accum, t; clear(accum); for (i = offset; i < n; i++) { mul(t, a[i], b[i-offset]); add(accum, accum, t); } x = accum; } long CRT(vec_ZZ& gg, ZZ& a, const vec_zz_p& G) { long n = gg.length(); if (G.length() != n) Error("CRT: vector length mismatch"); long p = zz_p::modulus(); ZZ new_a; mul(new_a, a, p); long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long p1; p1 = p >> 1; ZZ a1; RightShift(a1, a, 1); long p_odd = (p & 1); long modified = 0; long h; ZZ g; long i; for (i = 0; i < n; i++) { if (!CRTInRange(gg[i], a)) { modified = 1; rem(g, gg[i], a); if (g > a1) sub(g, g, a); } else g = gg[i]; h = rem(g, p); h = SubMod(rep(G[i]), h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!p_odd && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } gg[i] = g; } a = new_a; return modified; } void mul(vec_zz_p& x, const vec_zz_p& a, zz_p b) { long n = a.length(); x.SetLength(n); long i; if (n <= 1) { for (i = 0; i < n; i++) mul(x[i], a[i], b); } else { long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); long bb = rep(b); mulmod_precon_t bpinv = PrepMulModPrecon(bb, p, pinv); const zz_p *ap = a.elts(); zz_p *xp = x.elts(); for (i = 0; i < n; i++) xp[i].LoopHole() = MulModPrecon(rep(ap[i]), bb, p, bpinv); } } void mul(vec_zz_p& x, const vec_zz_p& a, long b_in) { zz_p b; b = b_in; mul(x, a, b); } void add(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b) { long n = a.length(); if (b.length() != n) Error("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b) { long n = a.length(); if (b.length() != n) Error("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void clear(vec_zz_p& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } void negate(vec_zz_p& x, const vec_zz_p& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } long IsZero(const vec_zz_p& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_zz_p operator+(const vec_zz_p& a, const vec_zz_p& b) { vec_zz_p res; add(res, a, b); NTL_OPT_RETURN(vec_zz_p, res); } vec_zz_p operator-(const vec_zz_p& a, const vec_zz_p& b) { vec_zz_p res; sub(res, a, b); NTL_OPT_RETURN(vec_zz_p, res); } vec_zz_p operator-(const vec_zz_p& a) { vec_zz_p res; negate(res, a); NTL_OPT_RETURN(vec_zz_p, res); } zz_p operator*(const vec_zz_p& a, const vec_zz_p& b) { zz_p res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_zz_p& x, const vec_zz_p& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-6.2.1/src/vec_lzz_pE.c000644 000765 000024 00000006155 12377144456 015675 0ustar00shoupstaff000000 000000 #include NTL_START_IMPL void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b) { long n = min(a.length(), b.length()); long i; zz_pX accum, t; clear(accum); for (i = 0; i < n; i++) { mul(t, rep(a[i]), rep(b[i])); add(accum, accum, t); } conv(x, accum); } void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b, long offset) { if (offset < 0) Error("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) Error("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; zz_pX accum, t; clear(accum); for (i = offset; i < n; i++) { mul(t, rep(a[i]), rep(b[i-offset])); add(accum, accum, t); } conv(x, accum); } void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_pE& b_in) { zz_pE b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_p& b_in) { NTL_zz_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_zz_pE& x, const vec_zz_pE& a, long b_in) { NTL_zz_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b) { long n = a.length(); if (b.length() != n) Error("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b) { long n = a.length(); if (b.length() != n) Error("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void negate(vec_zz_pE& x, const vec_zz_pE& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } void clear(vec_zz_pE& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } long IsZero(const vec_zz_pE& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_zz_pE operator+(const vec_zz_pE& a, const vec_zz_pE& b) { vec_zz_pE res; add(res, a, b); NTL_OPT_RETURN(vec_zz_pE, res); } vec_zz_pE operator-(const vec_zz_pE& a, const vec_zz_pE& b) { vec_zz_pE res; sub(res, a, b); NTL_OPT_RETURN(vec_zz_pE, res); } vec_zz_pE operator-(const vec_zz_pE& a) { vec_zz_pE res; negate(res, a); NTL_OPT_RETURN(vec_zz_pE, res); } zz_pE operator*(const vec_zz_pE& a, const vec_zz_pE& b) { zz_pE res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_zz_pE& x, const vec_zz_pE& a, long n) { if (n < 0) Error("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-6.2.1/src/xdouble.c000644 000765 000024 00000036323 12377144456 015237 0ustar00shoupstaff000000 000000 #include #include #include NTL_START_IMPL long xdouble::oprec = 10; void xdouble::SetOutputPrecision(long p) { if (p < 1) p = 1; if (NTL_OVERFLOW(p, 1, 0)) Error("xdouble: output precision too big"); oprec = p; } void xdouble::normalize() { if (x == 0) e = 0; else if (x > 0) { while (x < NTL_XD_HBOUND_INV) { x *= NTL_XD_BOUND; e--; } while (x > NTL_XD_HBOUND) { x *= NTL_XD_BOUND_INV; e++; } } else { while (x > -NTL_XD_HBOUND_INV) { x *= NTL_XD_BOUND; e--; } while (x < -NTL_XD_HBOUND) { x *= NTL_XD_BOUND_INV; e++; } } if (e >= NTL_OVFBND) Error("xdouble: overflow"); if (e <= -NTL_OVFBND) Error("xdouble: underflow"); } xdouble to_xdouble(double a) { if (a == 0 || a == 1 || (a > 0 && a >= NTL_XD_HBOUND_INV && a <= NTL_XD_HBOUND) || (a < 0 && a <= -NTL_XD_HBOUND_INV && a >= -NTL_XD_HBOUND)) { return xdouble(a, 0); } if (!IsFinite(&a)) Error("double to xdouble conversion: non finite value"); xdouble z = xdouble(a, 0); z.normalize(); return z; } void conv(double& xx, const xdouble& a) { double x; long e; x = a.x; e = a.e; while (e > 0) { x *= NTL_XD_BOUND; e--; } while (e < 0) { x *= NTL_XD_BOUND_INV; e++; } xx = x; } xdouble operator+(const xdouble& a, const xdouble& b) { xdouble z; if (a.x == 0) return b; if (b.x == 0) return a; if (a.e == b.e) { z.x = a.x + b.x; z.e = a.e; z.normalize(); return z; } else if (a.e > b.e) { if (a.e > b.e+1) return a; z.x = a.x + b.x*NTL_XD_BOUND_INV; z.e = a.e; z.normalize(); return z; } else { if (b.e > a.e+1) return b; z.x = a.x*NTL_XD_BOUND_INV + b.x; z.e = b.e; z.normalize(); return z; } } xdouble operator-(const xdouble& a, const xdouble& b) { xdouble z; if (a.x == 0) return -b; if (b.x == 0) return a; if (a.e == b.e) { z.x = a.x - b.x; z.e = a.e; z.normalize(); return z; } else if (a.e > b.e) { if (a.e > b.e+1) return a; z.x = a.x - b.x*NTL_XD_BOUND_INV; z.e = a.e; z.normalize(); return z; } else { if (b.e > a.e+1) return -b; z.x = a.x*NTL_XD_BOUND_INV - b.x; z.e = b.e; z.normalize(); return z; } } xdouble operator-(const xdouble& a) { xdouble z; z.x = -a.x; z.e = a.e; return z; } xdouble operator*(const xdouble& a, const xdouble& b) { xdouble z; z.e = a.e + b.e; z.x = a.x * b.x; z.normalize(); return z; } xdouble operator/(const xdouble& a, const xdouble& b) { xdouble z; if (b.x == 0) Error("xdouble division by 0"); z.e = a.e - b.e; z.x = a.x / b.x; z.normalize(); return z; } long compare(const xdouble& a, const xdouble& b) { xdouble z = a - b; if (z.x < 0) return -1; else if (z.x == 0) return 0; else return 1; } long sign(const xdouble& z) { if (z.x < 0) return -1; else if (z.x == 0) return 0; else return 1; } xdouble trunc(const xdouble& a) { if (a.x >= 0) return floor(a); else return ceil(a); } xdouble floor(const xdouble& aa) { xdouble z; xdouble a = aa; ForceToMem(&a.x); if (a.e == 0) { z.x = floor(a.x); z.e = 0; z.normalize(); return z; } else if (a.e > 0) { return a; } else { if (a.x < 0) return to_xdouble(-1); else return to_xdouble(0); } } xdouble ceil(const xdouble& aa) { xdouble z; xdouble a = aa; ForceToMem(&a.x); if (a.e == 0) { z.x = ceil(a.x); z.e = 0; z.normalize(); return z; } else if (a.e > 0) { return a; } else { if (a.x < 0) return to_xdouble(0); else return to_xdouble(1); } } xdouble to_xdouble(const ZZ& a) { long old_p = RR::precision(); RR::SetPrecision(NTL_DOUBLE_PRECISION); NTL_THREAD_LOCAL static RR t; conv(t, a); double x; conv(x, t.mantissa()); xdouble y, z, res; conv(y, x); power2(z, t.exponent()); res = y*z; RR::SetPrecision(old_p); return res; } void conv(ZZ& x, const xdouble& a) { xdouble b = floor(a); long old_p = RR::precision(); RR::SetPrecision(NTL_DOUBLE_PRECISION); NTL_THREAD_LOCAL static RR t; conv(t, b); conv(x, t); RR::SetPrecision(old_p); } xdouble fabs(const xdouble& a) { xdouble z; z.e = a.e; z.x = fabs(a.x); return z; } xdouble sqrt(const xdouble& a) { if (a == 0) return to_xdouble(0); if (a < 0) Error("xdouble: sqrt of negative number"); xdouble t; if (a.e & 1) { t.e = (a.e - 1)/2; t.x = sqrt(a.x * NTL_XD_BOUND); } else { t.e = a.e/2; t.x = sqrt(a.x); } t.normalize(); return t; } void power(xdouble& z, const xdouble& a, const ZZ& e) { xdouble b, res; b = a; res = 1; long n = NumBits(e); long i; for (i = n-1; i >= 0; i--) { res = res * res; if (bit(e, i)) res = res * b; } if (sign(e) < 0) z = 1/res; else z = res; } void power(xdouble& z, const xdouble& a, long e) { NTL_ZZRegister(E); E = e; power(z, a, E); } void power2(xdouble& z, long e) { long hb = NTL_XD_HBOUND_LOG; long b = 2*hb; long q, r; q = e/b; r = e%b; while (r >= hb) { r -= b; q++; } while (r < -hb) { r += b; q--; } if (q >= NTL_OVFBND) Error("xdouble: overflow"); if (q <= -NTL_OVFBND) Error("xdouble: underflow"); double x = _ntl_ldexp(1.0, r); z.x = x; z.e = q; } void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c) // z = a + b*c { double x; long e; e = b.e + c.e; x = b.x * c.x; if (x == 0) { z = a; return; } if (a.x == 0) { z.e = e; z.x = x; z.normalize(); return; } if (a.e == e) { z.x = a.x + x; z.e = e; z.normalize(); return; } else if (a.e > e) { if (a.e > e+1) { z = a; return; } z.x = a.x + x*NTL_XD_BOUND_INV; z.e = a.e; z.normalize(); return; } else { if (e > a.e+1) { z.x = x; z.e = e; z.normalize(); return; } z.x = a.x*NTL_XD_BOUND_INV + x; z.e = e; z.normalize(); return; } } void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c) // z = a - b*c { double x; long e; e = b.e + c.e; x = b.x * c.x; if (x == 0) { z = a; return; } if (a.x == 0) { z.e = e; z.x = -x; z.normalize(); return; } if (a.e == e) { z.x = a.x - x; z.e = e; z.normalize(); return; } else if (a.e > e) { if (a.e > e+1) { z = a; return; } z.x = a.x - x*NTL_XD_BOUND_INV; z.e = a.e; z.normalize(); return; } else { if (e > a.e+1) { z.x = -x; z.e = e; z.normalize(); return; } z.x = a.x*NTL_XD_BOUND_INV - x; z.e = e; z.normalize(); return; } } double log(const xdouble& a) { NTL_THREAD_LOCAL static double LogBound = log(NTL_XD_BOUND); if (a.x <= 0) { Error("log(xdouble): argument must be positive"); } return log(a.x) + a.e*LogBound; } xdouble xexp(double x) { const double LogBound = log(NTL_XD_BOUND); double y = x/LogBound; double iy = floor(y+0.5); if (iy >= NTL_OVFBND) Error("xdouble: overflow"); if (iy <= -NTL_OVFBND) Error("xdouble: underflow"); double fy = y - iy; xdouble res; res.e = long(iy); res.x = exp(fy*LogBound); res.normalize(); return res; } /************** input / output routines **************/ void ComputeLn2(RR&); void ComputeLn10(RR&); long ComputeMax10Power() { long old_p = RR::precision(); RR::SetPrecision(NTL_BITS_PER_LONG); RR ln2, ln10; ComputeLn2(ln2); ComputeLn10(ln10); long k = to_long( to_RR(NTL_OVFBND/2) * ln2 / ln10 ); RR::SetPrecision(old_p); return k; } xdouble PowerOf10(const ZZ& e) { NTL_THREAD_LOCAL static long init = 0; NTL_THREAD_LOCAL static xdouble v10k; NTL_THREAD_LOCAL static long k; if (!init) { long old_p = RR::precision(); k = ComputeMax10Power(); RR::SetPrecision(NTL_DOUBLE_PRECISION); v10k = to_xdouble(power(to_RR(10), k)); RR::SetPrecision(old_p); init = 1; } ZZ e1; long neg; if (e < 0) { e1 = -e; neg = 1; } else { e1 = e; neg = 0; } long r; ZZ q; r = DivRem(q, e1, k); long old_p = RR::precision(); RR::SetPrecision(NTL_DOUBLE_PRECISION); xdouble x1 = to_xdouble(power(to_RR(10), r)); RR::SetPrecision(old_p); xdouble x2 = power(v10k, q); xdouble x3 = x1*x2; if (neg) x3 = 1/x3; return x3; } ostream& operator<<(ostream& s, const xdouble& a) { if (a == 0) { s << "0"; return s; } long old_p = RR::precision(); long temp_p = long(log(fabs(log(fabs(a))) + 1.0)/log(2.0)) + 10; RR::SetPrecision(temp_p); RR ln2, ln10, log_2_10; ComputeLn2(ln2); ComputeLn10(ln10); log_2_10 = ln10/ln2; ZZ log_10_a = to_ZZ( (to_RR(a.e)*to_RR(2*NTL_XD_HBOUND_LOG) + log(fabs(a.x))/log(2.0))/log_2_10); RR::SetPrecision(old_p); xdouble b; long neg; if (a < 0) { b = -a; neg = 1; } else { b = a; neg = 0; } ZZ k = xdouble::OutputPrecision() - log_10_a; xdouble c, d; c = PowerOf10(to_ZZ(xdouble::OutputPrecision())); d = PowerOf10(log_10_a); b = b / d; b = b * c; while (b < c) { b = b * 10.0; k++; } while (b >= c) { b = b / 10.0; k--; } b = b + 0.5; k = -k; ZZ B; conv(B, b); long bp_len = xdouble::OutputPrecision()+10; char *bp = NTL_NEW_OP char[bp_len]; if (!bp) Error("xdouble output: out of memory"); long len, i; len = 0; do { if (len >= bp_len) Error("xdouble output: buffer overflow"); bp[len] = IntValToChar(DivRem(B, B, 10)); len++; } while (B > 0); for (i = 0; i < len/2; i++) { char tmp; tmp = bp[i]; bp[i] = bp[len-1-i]; bp[len-1-i] = tmp; } i = len-1; while (bp[i] == '0') i--; k += (len-1-i); len = i+1; bp[len] = '\0'; if (k > 3 || k < -len - 3) { // use scientific notation if (neg) s << "-"; s << "0." << bp << "e" << (k + len); } else { long kk = to_long(k); if (kk >= 0) { if (neg) s << "-"; s << bp; for (i = 0; i < kk; i++) s << "0"; } else if (kk <= -len) { if (neg) s << "-"; s << "0."; for (i = 0; i < -len-kk; i++) s << "0"; s << bp; } else { if (neg) s << "-"; for (i = 0; i < len+kk; i++) s << bp[i]; s << "."; for (i = len+kk; i < len; i++) s << bp[i]; } } delete [] bp; return s; } istream& operator>>(istream& s, xdouble& x) { long c; long cval; long sign; ZZ a, b; if (!s) Error("bad xdouble input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c == '-') { sign = -1; s.get(); c = s.peek(); } else sign = 1; long got1 = 0; long got_dot = 0; long got2 = 0; a = 0; b = 1; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got1 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); s.get(); c = s.peek(); cval = CharToIntVal(c); } } if (c == '.') { got_dot = 1; s.get(); c = s.peek(); cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got2 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); mul(b, b, 10); s.get(); c = s.peek(); cval = CharToIntVal(c); } } } if (got_dot && !got1 && !got2) Error("bad xdouble input"); ZZ e; long got_e = 0; long e_sign; if (c == 'e' || c == 'E') { got_e = 1; s.get(); c = s.peek(); if (c == '-') { e_sign = -1; s.get(); c = s.peek(); } else if (c == '+') { e_sign = 1; s.get(); c = s.peek(); } else e_sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) Error("bad xdouble input"); e = 0; while (cval >= 0 && cval <= 9) { mul(e, e, 10); add(e, e, cval); s.get(); c = s.peek(); cval = CharToIntVal(c); } } if (!got1 && !got2 && !got_e) Error("bad xdouble input"); xdouble t1, t2, v; if (got1 || got2) { conv(t1, a); conv(t2, b); v = t1/t2; } else v = 1; if (sign < 0) v = -v; if (got_e) { if (e_sign < 0) negate(e, e); t1 = PowerOf10(e); v = v * t1; } x = v; return s; } xdouble to_xdouble(const char *s) { long c; long cval; long sign; ZZ a, b; long i=0; if (!s) Error("bad xdouble input"); c = s[i]; while (IsWhiteSpace(c)) { i++; c = s[i]; } if (c == '-') { sign = -1; i++; c = s[i]; } else sign = 1; long got1 = 0; long got_dot = 0; long got2 = 0; a = 0; b = 1; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got1 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); i++; c = s[i]; cval = CharToIntVal(c); } } if (c == '.') { got_dot = 1; i++; c = s[i]; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got2 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); mul(b, b, 10); i++; c = s[i]; cval = CharToIntVal(c); } } } if (got_dot && !got1 && !got2) Error("bad xdouble input"); ZZ e; long got_e = 0; long e_sign; if (c == 'e' || c == 'E') { got_e = 1; i++; c = s[i]; if (c == '-') { e_sign = -1; i++; c = s[i]; } else if (c == '+') { e_sign = 1; i++; c = s[i]; } else e_sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) Error("bad xdouble input"); e = 0; while (cval >= 0 && cval <= 9) { mul(e, e, 10); add(e, e, cval); i++; c = s[i]; cval = CharToIntVal(c); } } if (!got1 && !got2 && !got_e) Error("bad xdouble input"); xdouble t1, t2, v; if (got1 || got2) { conv(t1, a); conv(t2, b); v = t1/t2; } else v = 1; if (sign < 0) v = -v; if (got_e) { if (e_sign < 0) negate(e, e); t1 = PowerOf10(e); v = v * t1; } return v; } NTL_END_IMPL ntl-6.2.1/include/NTL/000755 000765 000024 00000000000 12377144460 014706 5ustar00shoupstaff000000 000000 ntl-6.2.1/include/NTL/FFT.h000644 000765 000024 00000010714 12377144457 015507 0ustar00shoupstaff000000 000000 #ifndef NTL_FFT__H #define NTL_FFT__H #include #include #include NTL_OPEN_NNS #define NTL_FFTFudge (4) // This constant is used in selecting the correct // number of FFT primes for polynomial multiplication // in ZZ_pX and zz_pX. Set at 4, this allows for // two FFT reps to be added or subtracted once, // before performing CRT, and leaves a reasonable margin for error. // Don't change this! #define NTL_FFTMaxRootBnd (NTL_SP_NBITS-2) // Absolute maximum root bound for FFT primes. // Don't change this! #if (25 <= NTL_FFTMaxRootBnd) #define NTL_FFTMaxRoot (25) #else #define NTL_FFTMaxRoot NTL_FFTMaxRootBnd #endif // Root bound for FFT primes. Held to a maximum // of 25 to avoid large tables and excess precomputation, // and to keep the number of FFT primes needed small. // This means we can multiply polynomials of degree less than 2^24. // This can be increased, with a slight performance penalty. // New interface class FFTMultipliers { public: long MaxK; Vec< Vec > wtab_precomp; Vec< Vec > wqinvtab_precomp; FFTMultipliers() : MaxK(-1) { } }; #ifndef NTL_WIZARD_HACK class zz_pInfoT; // forward reference, defined in lzz_p.h #else typedef long zz_pInfoT; #endif struct FFTPrimeInfo { long q; // the prime itself double qinv; // 1/((double) q) zz_pInfoT *zz_p_context; // pointer to corresponding zz_p context, which points back to this // object in the case of a non-user FFT prime Vec RootTable; // RootTable[j] = w^{2^{MaxRoot-j}}, // where w is a primitive 2^MaxRoot root of unity // for q Vec RootInvTable; // RootInvTable[j] = 1/RootTable[j] mod q Vec TwoInvTable; // TwoInvTable[j] = 1/2^j mod q Vec TwoInvPreconTable; // mulmod preconditioning data long bigtab; // flag indicating if we use big tables for this prime FFTMultipliers MulTab; FFTMultipliers InvMulTab; }; void InitFFTPrimeInfo(FFTPrimeInfo& info, long q, long w, long bigtab); #define NTL_FFT_BIGTAB_LIMIT (256) // big tables are only used for the first NTL_FFT_BIGTAB_LIMIT primes // TODO: maybe we should have a similar limit for the degree of // the convolution as well. NTL_THREAD_LOCAL extern FFTPrimeInfo **FFTTables; // legacy interface NTL_THREAD_LOCAL extern long NumFFTPrimes; NTL_THREAD_LOCAL extern long *FFTPrime; NTL_THREAD_LOCAL extern double *FFTPrimeInv; long CalcMaxRoot(long p); // calculates max power of two supported by this FFT prime. void UseFFTPrime(long index); // allocates and initializes information for FFT prime void FFT(long* A, const long* a, long k, long q, const long* root); // the low-level FFT routine. // computes a 2^k point FFT modulo q, using the table root for the roots. void FFT(long* A, const long* a, long k, long q, const long* root, FFTMultipliers& tab); inline void FFTFwd(long* A, const long *a, long k, FFTPrimeInfo& info) // Slightly higher level interface...using the ith FFT prime { #ifdef NTL_FFT_BIGTAB if (info.bigtab) FFT(A, a, k, info.q, &info.RootTable[0], info.MulTab); else FFT(A, a, k, info.q, &info.RootTable[0]); #else FFT(A, a, k, info.q, &info.RootTable[0]); #endif } inline void FFTFwd(long* A, const long *a, long k, long i) { FFTFwd(A, a, k, *FFTTables[i]); } inline void FFTRev(long* A, const long *a, long k, FFTPrimeInfo& info) // Slightly higher level interface...using the ith FFT prime { #ifdef NTL_FFT_BIGTAB if (info.bigtab) FFT(A, a, k, info.q, &info.RootInvTable[0], info.InvMulTab); else FFT(A, a, k, info.q, &info.RootInvTable[0]); #else FFT(A, a, k, info.q, &info.RootInvTable[0]); #endif } inline void FFTRev(long* A, const long *a, long k, long i) { FFTRev(A, a, k, *FFTTables[i]); } inline void FFTMulTwoInv(long* A, const long *a, long k, FFTPrimeInfo& info) { VectorMulModPrecon(1L << k, A, a, info.TwoInvTable[k], info.q, info.TwoInvPreconTable[k]); } inline void FFTMulTwoInv(long* A, const long *a, long k, long i) { FFTMulTwoInv(A, a, k, *FFTTables[i]); } inline void FFTRev1(long* A, const long *a, long k, FFTPrimeInfo& info) // FFTRev + FFTMulTwoInv { FFTRev(A, a, k, info); FFTMulTwoInv(A, A, k, info); } inline void FFTRev1(long* A, const long *a, long k, long i) { FFTRev1(A, a, k, *FFTTables[i]); } long IsFFTPrime(long n, long& w); // tests if n is an "FFT prime" and returns corresponding root NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/FacVec.h000644 000765 000024 00000000510 12377144457 016210 0ustar00shoupstaff000000 000000 #ifndef NTL_FacVec__H #define NTL_FacVec__H #include NTL_OPEN_NNS struct IntFactor { IntFactor() { } ~IntFactor() { } long q; long a; long val; long link; }; typedef Vec vec_IntFactor; typedef vec_IntFactor FacVec; void FactorInt(FacVec& fvec, long n); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/GF2.h000644 000765 000024 00000023040 12377144457 015442 0ustar00shoupstaff000000 000000 #ifndef NTL_GF2__H #define NTL_GF2__H #include #include NTL_OPEN_NNS // Context, Bak, and Push types, just for consistency. // They don't do anything class GF2Context { public: GF2Context() {} explicit GF2Context(long p) { if (p != 2) Error("GF2Context with p != 2"); } void save() {} void restore() const {} }; class GF2Bak { public: void save(); void restore(); private: GF2Bak(const GF2Bak&); // disabled void operator=(const GF2Bak&); // disabled }; class GF2Push { GF2Push(const GF2Push&); // disabled void operator=(const GF2Push&); // disabled public: GF2Push() { } explicit GF2Push(const GF2Context& context) { } explicit GF2Push(long p) { if (p != 2) Error("GF2Push with p != 2"); } }; class GF2X; // forward declaration class GF2 { public: typedef long rep_type; typedef GF2Context context_type; typedef GF2Bak bak_type; typedef GF2Push push_type; typedef GF2X poly_type; unsigned long _GF2__rep; GF2() : _GF2__rep(0) { } GF2(const GF2& a) : _GF2__rep(a._GF2__rep) { } explicit GF2(long a) : _GF2__rep(0) { *this = a; } GF2(INIT_VAL_TYPE, long a) : _GF2__rep(a & 1) { } GF2(INIT_LOOP_HOLE_TYPE, unsigned long a) : _GF2__rep(a) { } ~GF2() { } GF2& operator=(const GF2& a) { _GF2__rep = a._GF2__rep; return *this; } GF2& operator=(long a) { _GF2__rep = a & 1; return *this; } static long modulus() { return 2; } static GF2 zero() { return GF2(); } // for consistency GF2(INIT_NO_ALLOC_TYPE) : _GF2__rep(0) { } GF2(INIT_ALLOC_TYPE) : _GF2__rep(0) { } void allocate() { } }; class ref_GF2 { public: unsigned long *_ref_GF2__ptr; long _ref_GF2__pos; ref_GF2() : _ref_GF2__ptr(0), _ref_GF2__pos(0) { } ref_GF2(const ref_GF2& a) : _ref_GF2__ptr(a._ref_GF2__ptr), _ref_GF2__pos(a._ref_GF2__pos) { } ref_GF2(GF2& a) : _ref_GF2__ptr(&a._GF2__rep), _ref_GF2__pos(0) { } ref_GF2(INIT_LOOP_HOLE_TYPE, unsigned long *ptr, long pos) : _ref_GF2__ptr(ptr), _ref_GF2__pos(pos) { } operator const GF2() const { return GF2(INIT_LOOP_HOLE, (*_ref_GF2__ptr >> _ref_GF2__pos) & 1); } ~ref_GF2() { } ref_GF2 operator=(const ref_GF2& a) { unsigned long rval = (*a._ref_GF2__ptr >> a._ref_GF2__pos) & 1; unsigned long lval = *_ref_GF2__ptr; lval = (lval & ~(1UL << _ref_GF2__pos)) | (rval << _ref_GF2__pos); *_ref_GF2__ptr = lval; return *this; } ref_GF2 operator=(const GF2& a) { unsigned long rval = (a._GF2__rep) & 1; unsigned long lval = *_ref_GF2__ptr; lval = (lval & ~(1UL << _ref_GF2__pos)) | (rval << _ref_GF2__pos); *_ref_GF2__ptr = lval; return *this; } ref_GF2 operator=(long a) { unsigned long rval = a & 1; unsigned long lval = *_ref_GF2__ptr; lval = (lval & ~(1UL << _ref_GF2__pos)) | (rval << _ref_GF2__pos); *_ref_GF2__ptr = lval; return *this; } }; // functions inline long rep(GF2 a) { return a._GF2__rep; } inline long IsZero(GF2 a) { return a._GF2__rep == 0; } inline long IsOne(GF2 a) { return a._GF2__rep == 1; } inline GF2 to_GF2(long a) { return GF2(INIT_VAL, a); } inline GF2 to_GF2(const ZZ& a) { return GF2(INIT_LOOP_HOLE, IsOdd(a)); } inline GF2 operator+(GF2 a, GF2 b) { return GF2(INIT_LOOP_HOLE, a._GF2__rep ^ b._GF2__rep); } inline GF2 operator+(GF2 a, long b) { return a + to_GF2(b); } inline GF2 operator+(long a, GF2 b) { return to_GF2(a) + b; } inline GF2 operator-(GF2 a, GF2 b) { return a + b; } inline GF2 operator-(GF2 a, long b) { return a + b; } inline GF2 operator-(long a, GF2 b) { return a + b; } inline GF2 operator-(GF2 a) { return a; } inline GF2 sqr(GF2 a) { return a; } inline GF2 operator*(GF2 a, GF2 b) { return GF2(INIT_LOOP_HOLE, a._GF2__rep & b._GF2__rep); } inline GF2 operator*(GF2 a, long b) { return a * to_GF2(b); } inline GF2 operator*(long a, GF2 b) { return to_GF2(a) * b; } inline GF2 operator/(GF2 a, GF2 b) { if (IsZero(b)) Error("GF2: division by zero"); return a; } inline GF2 operator/(GF2 a, long b) { return a / to_GF2(b); } inline GF2 operator/(long a, GF2 b) { return to_GF2(a) / b; } inline GF2 inv(GF2 a) { return 1 / a; } inline long operator==(GF2 a, GF2 b) { return a._GF2__rep == b._GF2__rep; } inline long operator==(GF2 a, long b) { return a == to_GF2(b); } inline long operator==(long a, GF2 b) { return to_GF2(a) == b; } inline long operator!=(GF2 a, GF2 b) { return !(a == b); } inline long operator!=(GF2 a, long b) { return !(a == b); } inline long operator!=(long a, GF2 b) { return !(a == b); } GF2 power(GF2 a, long e); inline GF2 random_GF2() { return GF2(INIT_LOOP_HOLE, RandomBnd(2)); } // procedural versions inline GF2& operator+=(GF2& x, GF2 b) { return x = x + b; } inline GF2& operator+=(GF2& x, long b) { return x = x + b; } inline GF2& operator-=(GF2& x, GF2 b) { return x = x - b; } inline GF2& operator-=(GF2& x, long b) { return x = x - b; } inline GF2& operator++(GF2& x) { return x = x + 1; } inline void operator++(GF2& x, int) { x = x + 1; } inline GF2& operator--(GF2& x) { return x = x - 1; } inline void operator--(GF2& x, int) { x = x - 1; } inline GF2& operator*=(GF2& x, GF2 b) { return x = x * b; } inline GF2& operator*=(GF2& x, long b) { return x = x * b; } inline GF2& operator/=(GF2& x, GF2 b) { return x = x / b; } inline GF2& operator/=(GF2& x, long b) { return x = x / b; } inline void conv(GF2& x, long a) { x = to_GF2(a); } inline void conv(GF2& x, const ZZ& a) { x = to_GF2(a); } inline void clear(GF2& x) { x = 0; } inline void set(GF2& x) { x = 1; } inline void swap(GF2& x, GF2& y) { GF2 t; t = x; x = y; y = t; } inline void add(GF2& x, GF2 a, GF2 b) { x = a + b; } inline void sub(GF2& x, GF2 a, GF2 b) { x = a - b; } inline void negate(GF2& x, GF2 a) { x = -a; } inline void add(GF2& x, GF2 a, long b) { x = a + b; } inline void add(GF2& x, long a, GF2 b) { x = a + b; } inline void sub(GF2& x, GF2 a, long b) { x = a - b; } inline void sub(GF2& x, long a, GF2 b) { x = a - b; } inline void mul(GF2& x, GF2 a, GF2 b) { x = a * b; } inline void mul(GF2& x, GF2 a, long b) { x = a * b; } inline void mul(GF2& x, long a, GF2 b) { x = a * b; } inline void sqr(GF2& x, GF2 a) { x = sqr(a); } inline void div(GF2& x, GF2 a, GF2 b) { x = a / b; } inline void div(GF2& x, long a, GF2 b) { x = a / b; } inline void div(GF2& x, GF2 a, long b) { x = a / b; } inline void inv(GF2& x, GF2 a) { x = inv(a); } inline void power(GF2& x, GF2 a, long e) { x = power(a, e); } inline void random(GF2& x) { x = random_GF2(); } // ref_GF2 variants...theoretically, these would // have sufficed, because of the implicit conversion // from GF2& to ref_GF2, but it may be a bit more efficient // to explicitly overload everything. Moreover, // the return types of the += type operators would // not be right. inline ref_GF2 operator+=(ref_GF2 x, GF2 b) { return x = x + b; } inline ref_GF2 operator+=(ref_GF2 x, long b) { return x = x + b; } inline ref_GF2 operator-=(ref_GF2 x, GF2 b) { return x = x - b; } inline ref_GF2 operator-=(ref_GF2 x, long b) { return x = x - b; } inline ref_GF2 operator++(ref_GF2 x) { return x = x + 1; } inline void operator++(ref_GF2 x, int) { x = x + 1; } inline ref_GF2 operator--(ref_GF2 x) { return x = x - 1; } inline void operator--(ref_GF2 x, int) { x = x - 1; } inline ref_GF2 operator*=(ref_GF2 x, GF2 b) { return x = x * b; } inline ref_GF2 operator*=(ref_GF2 x, long b) { return x = x * b; } inline ref_GF2 operator/=(ref_GF2 x, GF2 b) { return x = x / b; } inline ref_GF2 operator/=(ref_GF2 x, long b) { return x = x / b; } inline void conv(ref_GF2 x, long a) { x = to_GF2(a); } inline void conv(ref_GF2 x, const ZZ& a) { x = to_GF2(a); } inline void clear(ref_GF2 x) { x = 0; } inline void set(ref_GF2 x) { x = 1; } inline void swap(ref_GF2 x, ref_GF2 y) { GF2 t; t = x; x = y; y = t; } inline void add(ref_GF2 x, GF2 a, GF2 b) { x = a + b; } inline void sub(ref_GF2 x, GF2 a, GF2 b) { x = a - b; } inline void negate(ref_GF2 x, GF2 a) { x = -a; } inline void add(ref_GF2 x, GF2 a, long b) { x = a + b; } inline void add(ref_GF2 x, long a, GF2 b) { x = a + b; } inline void sub(ref_GF2 x, GF2 a, long b) { x = a - b; } inline void sub(ref_GF2 x, long a, GF2 b) { x = a - b; } inline void mul(ref_GF2 x, GF2 a, GF2 b) { x = a * b; } inline void mul(ref_GF2 x, GF2 a, long b) { x = a * b; } inline void mul(ref_GF2 x, long a, GF2 b) { x = a * b; } inline void sqr(ref_GF2 x, GF2 a) { x = sqr(a); } inline void div(ref_GF2 x, GF2 a, GF2 b) { x = a / b; } inline void div(ref_GF2 x, long a, GF2 b) { x = a / b; } inline void div(ref_GF2 x, GF2 a, long b) { x = a / b; } inline void inv(ref_GF2 x, GF2 a) { x = inv(a); } inline void power(ref_GF2 x, GF2 a, long e) { x = power(a, e); } inline void random(ref_GF2 x) { x = random_GF2(); } // I/O...for input, we only provide the ref_GF2 variant NTL_SNS ostream& operator<<(NTL_SNS ostream& s, GF2 a); NTL_SNS istream& operator>>(NTL_SNS istream& s, ref_GF2 x); /* additional legacy conversions for v6 conversion regime */ inline void conv(int& x, GF2 a) { conv(x, rep(a)); } inline void conv(unsigned int& x, GF2 a) { conv(x, rep(a)); } inline void conv(long& x, GF2 a) { conv(x, rep(a)); } inline void conv(unsigned long& x, GF2 a) { conv(x, rep(a)); } inline void conv(ZZ& x, GF2 a) { conv(x, rep(a)); } inline void conv(GF2& x, GF2 a) { x = a; } inline void conv(ref_GF2 x, GF2 a) { x = a; } /* ------------------------------------- */ // Finally, we declare an specialization Vec: template<> class Vec; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/GF2E.h000644 000765 000024 00000027205 12377144457 015556 0ustar00shoupstaff000000 000000 #ifndef NTL_GF2E__H #define NTL_GF2E__H #include NTL_OPEN_NNS class GF2EInfoT { private: GF2EInfoT(); // disabled GF2EInfoT(const GF2EInfoT&); // disabled void operator=(const GF2EInfoT&); // disabled public: long ref_count; GF2EInfoT(const GF2X& NewP); ~GF2EInfoT() { } GF2XModulus p; long KarCross; long ModCross; long DivCross; ZZ _card; long _card_init; long _card_exp; }; NTL_THREAD_LOCAL extern GF2EInfoT *GF2EInfo; // info for current modulus, initially null // FIXME: in a thread safe implementation, we need to use // shared_ptrs for contexts class GF2EContext { private: GF2EInfoT *ptr; public: void save(); void restore() const; GF2EContext() { ptr = 0; } explicit GF2EContext(const GF2X& p); GF2EContext(const GF2EContext&); GF2EContext& operator=(const GF2EContext&); ~GF2EContext(); }; class GF2EBak { private: long MustRestore; GF2EInfoT *ptr; GF2EBak(const GF2EBak&); // disabled void operator=(const GF2EBak&); // disabled public: void save(); void restore(); GF2EBak() { MustRestore = 0; ptr = 0; } ~GF2EBak(); }; class GF2EPush { private: GF2EBak bak; GF2EPush(const GF2EPush&); // disabled void operator=(const GF2EPush&); // disabled public: GF2EPush() { bak.save(); } explicit GF2EPush(const GF2EContext& context) { bak.save(); context.restore(); } explicit GF2EPush(const GF2X& p) { bak.save(); GF2EContext c(p); c.restore(); } }; class GF2EX; // forward declaration class GF2E { public: typedef GF2X rep_type; typedef GF2EContext context_type; typedef GF2EBak bak_type; typedef GF2EPush push_type; typedef GF2EX poly_type; GF2X _GF2E__rep; // ****** constructors and assignment GF2E() { } // NO_ALLOC GF2E(const GF2E& a) { _GF2E__rep = a._GF2E__rep; } // NO_ALLOC explicit GF2E(long a) { *this = a; } // NO_ALLOC explicit GF2E(GF2 a) { *this = a; } // NO_ALLOC GF2E(GF2E& x, INIT_TRANS_TYPE) : _GF2E__rep(x._GF2E__rep, INIT_TRANS) { } GF2E(INIT_NO_ALLOC_TYPE) { } // allocates no space GF2E(INIT_ALLOC_TYPE) { _GF2E__rep.xrep.SetMaxLength(GF2E::WordLength()); } // allocates space void allocate() { _GF2E__rep.xrep.SetMaxLength(GF2E::WordLength()); } ~GF2E() { } GF2E& operator=(const GF2E& a) { _GF2E__rep = a._GF2E__rep; return *this; } inline GF2E& operator=(long a); inline GF2E& operator=(GF2 a); // You can always access the _GF2E__representation directly...if you dare. GF2X& LoopHole() { return _GF2E__rep; } static long WordLength() { return GF2EInfo->p.WordLength(); } static long storage() { return WV_storage(GF2E::WordLength()); } static const GF2XModulus& modulus() { return GF2EInfo->p; } static long KarCross() { return GF2EInfo->KarCross; } static long ModCross() { return GF2EInfo->ModCross; } static long DivCross() { return GF2EInfo->DivCross; } static long degree() { return GF2EInfo->p.n; } static const GF2E& zero(); static const ZZ& cardinality(); static void init(const GF2X& NewP); }; // read-only access to GF2E representation inline const GF2X& rep(const GF2E& a) { return a._GF2E__rep; } inline void clear(GF2E& x) // x = 0 { clear(x._GF2E__rep); } inline void set(GF2E& x) // x = 1 { set(x._GF2E__rep); } inline void swap(GF2E& x, GF2E& y) // swap x and y { swap(x._GF2E__rep, y._GF2E__rep); } // ****** addition inline void add(GF2E& x, const GF2E& a, const GF2E& b) { add(x._GF2E__rep, a._GF2E__rep, b._GF2E__rep); } inline void add(GF2E& x, const GF2E& a, GF2 b) { add(x._GF2E__rep, a._GF2E__rep, b); } inline void add(GF2E& x, const GF2E& a, long b) { add(x._GF2E__rep, a._GF2E__rep, b); } inline void add(GF2E& x, GF2 a, const GF2E& b) { add(x, b, a); } inline void add(GF2E& x, long a, const GF2E& b) { add(x, b, a); } inline void sub(GF2E& x, const GF2E& a, const GF2E& b) { add(x, a, b); } inline void sub(GF2E& x, const GF2E& a, GF2 b) { add(x, a, b); } inline void sub(GF2E& x, const GF2E& a, long b) { add(x, a, b); } inline void sub(GF2E& x, GF2 a, const GF2E& b) { add(x, a, b); } inline void sub(GF2E& x, long a, const GF2E& b) { add(x, a, b); } inline void negate(GF2E& x, const GF2E& a) { x = a; } inline GF2E operator+(const GF2E& a, const GF2E& b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator+(const GF2E& a, GF2 b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator+(const GF2E& a, long b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator+(GF2 a, const GF2E& b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator+(long a, const GF2E& b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(const GF2E& a, const GF2E& b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(const GF2E& a, GF2 b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(const GF2E& a, long b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(GF2 a, const GF2E& b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(long a, const GF2E& b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(const GF2E& a) { GF2E x; negate(x, a); NTL_OPT_RETURN(GF2E, x); } inline GF2E& operator+=(GF2E& x, const GF2E& b) { add(x, x, b); return x; } inline GF2E& operator+=(GF2E& x, GF2 b) { add(x, x, b); return x; } inline GF2E& operator+=(GF2E& x, long b) { add(x, x, b); return x; } inline GF2E& operator-=(GF2E& x, const GF2E& b) { sub(x, x, b); return x; } inline GF2E& operator-=(GF2E& x, GF2 b) { sub(x, x, b); return x; } inline GF2E& operator-=(GF2E& x, long b) { sub(x, x, b); return x; } inline GF2E& operator++(GF2E& x) { add(x, x, 1); return x; } inline void operator++(GF2E& x, int) { add(x, x, 1); } inline GF2E& operator--(GF2E& x) { sub(x, x, 1); return x; } inline void operator--(GF2E& x, int) { sub(x, x, 1); } // ****** multiplication inline void mul(GF2E& x, const GF2E& a, const GF2E& b) // x = a*b { MulMod(x._GF2E__rep, a._GF2E__rep, b._GF2E__rep, GF2E::modulus()); } inline void sqr(GF2E& x, const GF2E& a) // x = a^2 { SqrMod(x._GF2E__rep, a._GF2E__rep, GF2E::modulus()); } inline GF2E sqr(const GF2E& a) { GF2E x; sqr(x, a); NTL_OPT_RETURN(GF2E, x); } inline void mul(GF2E& x, const GF2E& a, GF2 b) { mul(x._GF2E__rep, a._GF2E__rep, b); } inline void mul(GF2E& x, const GF2E& a, long b) { mul(x._GF2E__rep, a._GF2E__rep, b); } inline void mul(GF2E& x, GF2 a, const GF2E& b) { mul(x, b, a); } inline void mul(GF2E& x, long a, const GF2E& b) { mul(x, b, a); } inline GF2E operator*(const GF2E& a, const GF2E& b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator*(const GF2E& a, GF2 b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator*(const GF2E& a, long b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator*(GF2 a, const GF2E& b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator*(long a, const GF2E& b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E& operator*=(GF2E& x, const GF2E& b) { mul(x, x, b); return x; } inline GF2E& operator*=(GF2E& x, GF2 b) { mul(x, x, b); return x; } inline GF2E& operator*=(GF2E& x, long b) { mul(x, x, b); return x; } // ****** division void div(GF2E& x, const GF2E& a, const GF2E& b); void inv(GF2E& x, const GF2E& a); inline GF2E inv(const GF2E& a) { GF2E x; inv(x, a); NTL_OPT_RETURN(GF2E, x); } inline void div(GF2E& x, const GF2E& a, GF2 b) { div(x._GF2E__rep, a._GF2E__rep, b); } inline void div(GF2E& x, const GF2E& a, long b) { div(x._GF2E__rep, a._GF2E__rep, b); } void div(GF2E& x, GF2 a, const GF2E& b); void div(GF2E& x, long a, const GF2E& b); inline GF2E operator/(const GF2E& a, const GF2E& b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator/(const GF2E& a, GF2 b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator/(const GF2E& a, long b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator/(GF2 a, const GF2E& b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator/(long a, const GF2E& b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E& operator/=(GF2E& x, const GF2E& b) { div(x, x, b); return x; } inline GF2E& operator/=(GF2E& x, GF2 b) { div(x, x, b); return x; } inline GF2E& operator/=(GF2E& x, long b) { div(x, x, b); return x; } // ****** exponentiation inline void power(GF2E& x, const GF2E& a, const ZZ& e) { PowerMod(x._GF2E__rep, a._GF2E__rep, e, GF2E::modulus()); } inline GF2E power(const GF2E& a, const ZZ& e) { GF2E x; power(x, a, e); NTL_OPT_RETURN(GF2E, x); } inline void power(GF2E& x, const GF2E& a, long e) { PowerMod(x._GF2E__rep, a._GF2E__rep, e, GF2E::modulus()); } inline GF2E power(const GF2E& a, long e) { GF2E x; power(x, a, e); NTL_OPT_RETURN(GF2E, x); } // ****** conversion inline void conv(GF2E& x, const GF2X& a) // x = (a mod p) { rem(x._GF2E__rep, a, GF2E::modulus()); } inline void conv(GF2E& x, long a) { conv(x._GF2E__rep, a); } inline void conv(GF2E& x, GF2 a) { conv(x._GF2E__rep, a); } inline void conv(GF2E& x, const ZZ& a) { conv(x._GF2E__rep, a); } inline GF2E to_GF2E(const GF2X& a) { GF2E x; conv(x, a); NTL_OPT_RETURN(GF2E, x); } inline GF2E to_GF2E(long a) { GF2E x; conv(x, a); NTL_OPT_RETURN(GF2E, x); } inline GF2E to_GF2E(GF2 a) { GF2E x; conv(x, a); NTL_OPT_RETURN(GF2E, x); } inline GF2E to_GF2E(const ZZ& a) { GF2E x; conv(x, a); NTL_OPT_RETURN(GF2E, x); } // ****** comparison inline long IsZero(const GF2E& a) { return IsZero(a._GF2E__rep); } inline long IsOne(const GF2E& a) { return IsOne(a._GF2E__rep); } inline long operator==(const GF2E& a, const GF2E& b) { return a._GF2E__rep == b._GF2E__rep; } inline long operator==(const GF2E& a, GF2 b) { return a._GF2E__rep == b; } inline long operator==(const GF2E& a, long b) { return a._GF2E__rep == b; } inline long operator==(const GF2 a, const GF2E& b) { return a == b._GF2E__rep; } inline long operator==(const long a, const GF2E& b) { return a == b._GF2E__rep; } inline long operator!=(const GF2E& a, const GF2E& b) { return !(a == b); } inline long operator!=(const GF2E& a, GF2 b) { return !(a == b); } inline long operator!=(const GF2E& a, long b) { return !(a == b); } inline long operator!=(GF2 a, const GF2E& b) { return !(a == b); } inline long operator!=(long a, const GF2E& b) { return !(a == b); } // ****** trace inline void trace(ref_GF2 x, const GF2E& a) { TraceMod(x, a._GF2E__rep, GF2E::modulus()); } inline GF2 trace(const GF2E& a) { return TraceMod(a._GF2E__rep, GF2E::modulus()); } // ****** random numbers inline void random(GF2E& x) // x = random element in GF2E { random(x._GF2E__rep, GF2EInfo->p.n); } inline GF2E random_GF2E() { GF2E x; random(x); NTL_OPT_RETURN(GF2E, x); } // ****** input/output inline NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const GF2E& a) { return s << a._GF2E__rep; } NTL_SNS istream& operator>>(NTL_SNS istream& s, GF2E& x); inline GF2E& GF2E::operator=(long a) { conv(*this, a); return *this; } inline GF2E& GF2E::operator=(GF2 a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(GF2X& x, const GF2E& a) { x = rep(a); } inline void conv(GF2E& x, const GF2E& a) { x = a; } /* ------------------------------------- */ // overload these functions for Vec. // They are defined in vec_GF2E.c void BlockConstruct(GF2E* p, long n); void BlockConstructFromVec(GF2E* p, long n, const GF2E* q); void BlockConstructFromObj(GF2E* p, long n, const GF2E& q); void BlockDestroy(GF2E* p, long n); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/GF2EX.h000644 000765 000024 00000073633 12377144457 015714 0ustar00shoupstaff000000 000000 #ifndef NTL_GF2EX__H #define NTL_GF2EX__H #include #include #include #include #include NTL_OPEN_NNS class GF2EXModulus; // forward declaration class GF2EX { public: typedef GF2E coeff_type; typedef GF2EXModulus modulus_type; vec_GF2E rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ GF2EX() { } explicit GF2EX(long a) { *this = a; } explicit GF2EX(GF2 a) { *this = a; } explicit GF2EX(const GF2& a) { *this = a; } GF2EX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } GF2EX(const GF2EX& a) : rep(a.rep) { } GF2EX& operator=(const GF2EX& a) { rep = a.rep; return *this; } ~GF2EX() { } void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } GF2E& operator[](long i) { return rep[i]; } const GF2E& operator[](long i) const { return rep[i]; } static const GF2EX& zero(); inline GF2EX& operator=(long a); inline GF2EX& operator=(GF2 a); inline GF2EX& operator=(const GF2E& a); inline GF2EX(long i, long a); inline GF2EX(long i, GF2 a); inline GF2EX(long i, const GF2E& a); inline GF2EX(INIT_MONO_TYPE, long i, long a); inline GF2EX(INIT_MONO_TYPE, long i, GF2 a); inline GF2EX(INIT_MONO_TYPE, long i, const GF2E& a); inline GF2EX(INIT_MONO_TYPE, long i); GF2EX(GF2EX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } }; /******************************************************************** input and output *********************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, GF2EX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const GF2EX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const GF2EX& a) { return a.rep.length() - 1; } const GF2E& coeff(const GF2EX& a, long i); // zero if i not in range void GetCoeff(GF2E& x, const GF2EX& a, long i); // x = a[i], or zero if i not in range const GF2E& LeadCoeff(const GF2EX& a); // zero if a == 0 const GF2E& ConstTerm(const GF2EX& a); // zero if a == 0 void SetCoeff(GF2EX& x, long i, const GF2E& a); void SetCoeff(GF2EX& x, long i, GF2 a); void SetCoeff(GF2EX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(GF2EX& x, long i); // x[i] = 1, error is raised if i < 0 inline GF2EX::GF2EX(long i, const GF2E& a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(long i, GF2 a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(long i, long a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(INIT_MONO_TYPE, long i, const GF2E& a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(INIT_MONO_TYPE, long i, GF2 a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(GF2EX& x); // x is set to the monomial X long IsX(const GF2EX& a); // test if x = X inline void clear(GF2EX& x) // x = 0 { x.rep.SetLength(0); } inline void set(GF2EX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(GF2EX& x, GF2EX& y) // swap x & y (only pointers are swapped) { swap(x.rep, y.rep); } void random(GF2EX& x, long n); inline GF2EX random_GF2EX(long n) { GF2EX x; random(x, n); NTL_OPT_RETURN(GF2EX, x); } // generate a random polynomial of degree < n void trunc(GF2EX& x, const GF2EX& a, long m); inline GF2EX trunc(const GF2EX& a, long m) { GF2EX x; trunc(x, a, m); NTL_OPT_RETURN(GF2EX, x); } // x = a % X^m void RightShift(GF2EX& x, const GF2EX& a, long n); inline GF2EX RightShift(const GF2EX& a, long n) { GF2EX x; RightShift(x, a, n); NTL_OPT_RETURN(GF2EX, x); } // x = a/X^n void LeftShift(GF2EX& x, const GF2EX& a, long n); inline GF2EX LeftShift(const GF2EX& a, long n) { GF2EX x; LeftShift(x, a, n); NTL_OPT_RETURN(GF2EX, x); } // x = a*X^n #ifndef NTL_TRANSITION inline GF2EX operator>>(const GF2EX& a, long n) { GF2EX x; RightShift(x, a, n); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator<<(const GF2EX& a, long n) { GF2EX x; LeftShift(x, a, n); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator<<=(GF2EX& x, long n) { LeftShift(x, x, n); return x; } inline GF2EX& operator>>=(GF2EX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(GF2EX& x, const GF2EX& a); inline GF2EX diff(const GF2EX& a) { GF2EX x; diff(x, a); NTL_OPT_RETURN(GF2EX, x); } // x = derivative of a void MakeMonic(GF2EX& x); void reverse(GF2EX& c, const GF2EX& a, long hi); inline GF2EX reverse(const GF2EX& a, long hi) { GF2EX x; reverse(x, a, hi); NTL_OPT_RETURN(GF2EX, x); } inline void reverse(GF2EX& c, const GF2EX& a) { reverse(c, a, deg(a)); } inline GF2EX reverse(const GF2EX& a) { GF2EX x; reverse(x, a); NTL_OPT_RETURN(GF2EX, x); } inline void VectorCopy(vec_GF2E& x, const GF2EX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_GF2E VectorCopy(const GF2EX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(GF2EX& x, long a); void conv(GF2EX& x, GF2 a); void conv(GF2EX& x, const GF2E& a); void conv(GF2EX& x, const ZZ& a); #ifndef NTL_TRANSITION void conv(GF2EX& x, const GF2X& a); #endif void conv(GF2EX& x, const vec_GF2E& a); inline GF2EX to_GF2EX(long a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX to_GF2EX(GF2 a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX to_GF2EX(const GF2E& a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX to_GF2EX(const ZZ& a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } #ifndef NTL_TRANSITION inline GF2EX to_GF2EX(const GF2X& a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } #endif inline GF2EX to_GF2EX(const vec_GF2E& a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& GF2EX::operator=(const GF2E& a) { conv(*this, a); return *this; } inline GF2EX& GF2EX::operator=(GF2 a) { conv(*this, a); return *this; } inline GF2EX& GF2EX::operator=(long a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(GF2EX& x, const GF2EX& a) { x = a; } inline void conv(vec_GF2E& x, const GF2EX& a) { x = a.rep; } class ZZX; void conv(GF2EX& x, const ZZX& a); /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const GF2EX& a); long IsOne(const GF2EX& a); inline long operator==(const GF2EX& a, const GF2EX& b) { return a.rep == b.rep; } long operator==(const GF2EX& a, const GF2E& b); long operator==(const GF2EX& a, GF2 b); long operator==(const GF2EX& a, long b); inline long operator==(const GF2E& a, const GF2EX& b) { return b == a; } inline long operator==(GF2 a, const GF2EX& b) { return b == a; } inline long operator==(long a, const GF2EX& b) { return b == a; } inline long operator!=(const GF2EX& a, const GF2EX& b) { return !(a == b); } inline long operator!=(const GF2EX& a, const GF2E& b) { return !(a == b); } inline long operator!=(const GF2EX& a, GF2 b) { return !(a == b); } inline long operator!=(const GF2EX& a, long b) { return !(a == b); } inline long operator!=(const GF2E& a, const GF2EX& b) { return !(a == b); } inline long operator!=(GF2 a, const GF2EX& b) { return !(a == b); } inline long operator!=(long a, const GF2EX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a + b void add(GF2EX& x, const GF2EX& a, const GF2E& b); void add(GF2EX& x, const GF2EX& a, GF2 b); void add(GF2EX& x, const GF2EX& a, long); inline void add(GF2EX& x, const GF2E& a, const GF2EX& b) { add(x, b, a); } inline void add(GF2EX& x, GF2 a, const GF2EX& b) { add(x, b, a); } inline void add(GF2EX& x, long a, const GF2EX& b) { add(x, b, a); } inline void sub(GF2EX& x, const GF2EX& a, const GF2EX& b) { add(x, a, b); } inline void sub(GF2EX& x, const GF2EX& a, const GF2E& b) { add(x, a, b); } inline void sub(GF2EX& x, const GF2EX& a, GF2 b) { add(x, a, b); } inline void sub(GF2EX& x, const GF2EX& a, long b) { add(x, a, b); } inline void sub(GF2EX& x, const GF2E& a, const GF2EX& b) { add(x, a, b); } inline void sub(GF2EX& x, GF2 a, const GF2EX& b) { add(x, a, b); } inline void sub(GF2EX& x, long a, const GF2EX& b) { add(x, a, b); } inline void negate(GF2EX& x, const GF2EX& a) { x = a; } inline GF2EX operator+(const GF2EX& a, const GF2EX& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(const GF2EX& a, const GF2E& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(const GF2EX& a, GF2 b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(const GF2EX& a, long b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(const GF2E& a, const GF2EX& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(GF2 a, const GF2EX& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(long a, const GF2EX& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2EX& a, const GF2EX& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2EX& a, const GF2E& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2EX& a, GF2 b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2EX& a, long b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2E& a, const GF2EX& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(GF2 a, const GF2EX& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(long a, const GF2EX& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator+=(GF2EX& x, const GF2EX& b) { add(x, x, b); return x; } inline GF2EX& operator+=(GF2EX& x, const GF2E& b) { add(x, x, b); return x; } inline GF2EX& operator+=(GF2EX& x, GF2 b) { add(x, x, b); return x; } inline GF2EX& operator+=(GF2EX& x, long b) { add(x, x, b); return x; } inline GF2EX& operator-=(GF2EX& x, const GF2EX& b) { sub(x, x, b); return x; } inline GF2EX& operator-=(GF2EX& x, const GF2E& b) { sub(x, x, b); return x; } inline GF2EX& operator-=(GF2EX& x, GF2 b) { sub(x, x, b); return x; } inline GF2EX& operator-=(GF2EX& x, long b) { sub(x, x, b); return x; } inline GF2EX operator-(const GF2EX& a) { GF2EX x; negate(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator++(GF2EX& x) { add(x, x, 1); return x; } inline void operator++(GF2EX& x, int) { add(x, x, 1); } inline GF2EX& operator--(GF2EX& x) { sub(x, x, 1); return x; } inline void operator--(GF2EX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a * b void sqr(GF2EX& x, const GF2EX& a); inline GF2EX sqr(const GF2EX& a) { GF2EX x; sqr(x, a); NTL_OPT_RETURN(GF2EX, x); } // x = a^2 void mul(GF2EX & x, const GF2EX& a, const GF2E& b); void mul(GF2EX & x, const GF2EX& a, GF2 b); void mul(GF2EX & x, const GF2EX& a, long b); inline void mul(GF2EX& x, const GF2E& a, const GF2EX& b) { mul(x, b, a); } inline void mul(GF2EX& x, GF2 a, const GF2EX& b) { mul(x, b, a); } inline void mul(GF2EX& x, long a, const GF2EX& b) { mul(x, b, a); } void MulTrunc(GF2EX& x, const GF2EX& a, const GF2EX& b, long n); inline GF2EX MulTrunc(const GF2EX& a, const GF2EX& b, long n) { GF2EX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(GF2EX, x); } // x = a * b % X^n void SqrTrunc(GF2EX& x, const GF2EX& a, long n); inline GF2EX SqrTrunc(const GF2EX& a, long n) { GF2EX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(GF2EX, x); } // x = a*a % X^n inline GF2EX operator*(const GF2EX& a, const GF2EX& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(const GF2EX& a, const GF2E& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(const GF2EX& a, GF2 b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(const GF2EX& a, long b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(const GF2E& a, const GF2EX& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(GF2 a, const GF2EX& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(long a, const GF2EX& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator*=(GF2EX& x, const GF2EX& b) { mul(x, x, b); return x; } inline GF2EX& operator*=(GF2EX& x, const GF2E& b) { mul(x, x, b); return x; } inline GF2EX& operator*=(GF2EX& x, GF2 b) { mul(x, x, b); return x; } inline GF2EX& operator*=(GF2EX& x, long b) { mul(x, x, b); return x; } void power(GF2EX& x, const GF2EX& a, long e); inline GF2EX power(const GF2EX& a, long e) { GF2EX x; power(x, a, e); NTL_OPT_RETURN(GF2EX, x); } /************************************************************* Division **************************************************************/ void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b); // q = a/b, r = a%b void div(GF2EX& q, const GF2EX& a, const GF2EX& b); void div(GF2EX& q, const GF2EX& a, const GF2E& b); void div(GF2EX& q, const GF2EX& a, GF2 b); void div(GF2EX& q, const GF2EX& a, long b); // q = a/b void rem(GF2EX& r, const GF2EX& a, const GF2EX& b); // r = a%b long divide(GF2EX& q, const GF2EX& a, const GF2EX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const GF2EX& a, const GF2EX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(GF2EX& x, const GF2EX& a, long m); inline GF2EX InvTrunc(const GF2EX& a, long m) { GF2EX x; InvTrunc(x, a, m); NTL_OPT_RETURN(GF2EX, x); } // computes x = a^{-1} % X^m // constant term must be non-zero inline GF2EX operator/(const GF2EX& a, const GF2EX& b) { GF2EX x; div(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator/(const GF2EX& a, const GF2E& b) { GF2EX x; div(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator/(const GF2EX& a, GF2 b) { GF2EX x; div(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator/(const GF2EX& a, long b) { GF2EX x; div(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator/=(GF2EX& x, const GF2EX& b) { div(x, x, b); return x; } inline GF2EX& operator/=(GF2EX& x, const GF2E& b) { div(x, x, b); return x; } inline GF2EX& operator/=(GF2EX& x, GF2 b) { div(x, x, b); return x; } inline GF2EX& operator/=(GF2EX& x, long b) { div(x, x, b); return x; } inline GF2EX operator%(const GF2EX& a, const GF2EX& b) { GF2EX x; rem(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator%=(GF2EX& x, const GF2EX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(GF2EX& x, const GF2EX& a, const GF2EX& b); inline GF2EX GCD(const GF2EX& a, const GF2EX& b) { GF2EX x; GCD(x, a, b); NTL_OPT_RETURN(GF2EX, x); } // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(GF2EX& d, GF2EX& s, GF2EX& t, const GF2EX& a, const GF2EX& b); // d = gcd(a,b), a s + b t = d /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the GF2EXModulus data structure and associated routines below. void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EX& f); inline GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EX& f) { GF2EX x; MulMod(x, a, b, f); NTL_OPT_RETURN(GF2EX, x); } // x = (a * b) % f void SqrMod(GF2EX& x, const GF2EX& a, const GF2EX& f); inline GF2EX SqrMod(const GF2EX& a, const GF2EX& f) { GF2EX x; SqrMod(x, a, f); NTL_OPT_RETURN(GF2EX, x); } // x = a^2 % f void MulByXMod(GF2EX& x, const GF2EX& a, const GF2EX& f); inline GF2EX MulByXMod(const GF2EX& a, const GF2EX& f) { GF2EX x; MulByXMod(x, a, f); NTL_OPT_RETURN(GF2EX, x); } // x = (a * X) mod f void InvMod(GF2EX& x, const GF2EX& a, const GF2EX& f); inline GF2EX InvMod(const GF2EX& a, const GF2EX& f) { GF2EX x; InvMod(x, a, f); NTL_OPT_RETURN(GF2EX, x); } // x = a^{-1} % f, error is a is not invertible long InvModStatus(GF2EX& x, const GF2EX& a, const GF2EX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build GF2EXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class GF2EXModulus { public: GF2EXModulus(); ~GF2EXModulus() { } GF2EXModulus(const GF2EX& ff); GF2EX f; // the modulus operator const GF2EX& () const { return f; } const GF2EX& val() const { return f; } long n; // deg(f) long method; // GF2EX_MOD_PLAIN or GF2EX_MOD_MUL GF2EX h0; GF2E hlc; GF2EX f0; vec_GF2E tracevec; }; inline long deg(const GF2EXModulus& F) { return F.n; } void build(GF2EXModulus& F, const GF2EX& f); void rem(GF2EX& r, const GF2EX& a, const GF2EXModulus& F); void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F); void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F); void MulMod(GF2EX& c, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F); inline GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EXModulus& F) { GF2EX x; MulMod(x, a, b, F); NTL_OPT_RETURN(GF2EX, x); } void SqrMod(GF2EX& c, const GF2EX& a, const GF2EXModulus& F); inline GF2EX SqrMod(const GF2EX& a, const GF2EXModulus& F) { GF2EX x; SqrMod(x, a, F); NTL_OPT_RETURN(GF2EX, x); } void PowerMod(GF2EX& h, const GF2EX& g, const ZZ& e, const GF2EXModulus& F); inline void PowerMod(GF2EX& h, const GF2EX& g, long e, const GF2EXModulus& F) { PowerMod(h, g, ZZ_expo(e), F); } inline GF2EX PowerMod(const GF2EX& g, const ZZ& e, const GF2EXModulus& F) { GF2EX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX PowerMod(const GF2EX& g, long e, const GF2EXModulus& F) { GF2EX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(GF2EX, x); } void PowerXMod(GF2EX& hh, const ZZ& e, const GF2EXModulus& F); inline void PowerXMod(GF2EX& h, long e, const GF2EXModulus& F) { PowerXMod(h, ZZ_expo(e), F); } inline GF2EX PowerXMod(const ZZ& e, const GF2EXModulus& F) { GF2EX x; PowerXMod(x, e, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX PowerXMod(long e, const GF2EXModulus& F) { GF2EX x; PowerXMod(x, e, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator%(const GF2EX& a, const GF2EXModulus& F) { GF2EX x; rem(x, a, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator%=(GF2EX& x, const GF2EXModulus& F) { rem(x, x, F); return x; } inline GF2EX operator/(const GF2EX& a, const GF2EXModulus& F) { GF2EX x; div(x, a, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator/=(GF2EX& x, const GF2EXModulus& F) { div(x, x, F); return x; } /***************************************************************** vectors of GF2EX's *****************************************************************/ typedef Vec vec_GF2EX; /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(GF2EX& x, const vec_GF2E& a); inline GF2EX BuildFromRoots(const vec_GF2E& a) { GF2EX x; BuildFromRoots(x, a); NTL_OPT_RETURN(GF2EX, x); } // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(GF2E& b, const GF2EX& f, const GF2E& a); inline GF2E eval(const GF2EX& f, const GF2E& a) { GF2E x; eval(x, f, a); NTL_OPT_RETURN(GF2E, x); } // b = f(a) void eval(vec_GF2E& b, const GF2EX& f, const vec_GF2E& a); inline vec_GF2E eval(const GF2EX& f, const vec_GF2E& a) { vec_GF2E x; eval(x, f, a); NTL_OPT_RETURN(vec_GF2E, x); } // b[i] = f(a[i]) inline void eval(GF2E& b, const GF2X& f, const GF2E& a) { conv(b, CompMod(f, rep(a), GF2E::modulus())); } inline GF2E eval(const GF2X& f, const GF2E& a) { GF2E x; eval(x, f, a); NTL_OPT_RETURN(GF2E, x); } // b = f(a) void interpolate(GF2EX& f, const vec_GF2E& a, const vec_GF2E& b); inline GF2EX interpolate(const vec_GF2E& a, const vec_GF2E& b) { GF2EX x; interpolate(x, a, b); NTL_OPT_RETURN(GF2EX, x); } // computes f such that f(a[i]) = b[i] /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ // algorithms for computing g(h) mod f void CompMod(GF2EX& x, const GF2EX& g, const GF2EX& h, const GF2EXModulus& F); inline GF2EX CompMod(const GF2EX& g, const GF2EX& h, const GF2EXModulus& F) { GF2EX x; CompMod(x, g, h, F); NTL_OPT_RETURN(GF2EX, x); } // x = g(h) mod f void Comp2Mod(GF2EX& x1, GF2EX& x2, const GF2EX& g1, const GF2EX& g2, const GF2EX& h, const GF2EXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(GF2EX& x1, GF2EX& x2, GF2EX& x3, const GF2EX& g1, const GF2EX& g2, const GF2EX& g3, const GF2EX& h, const GF2EXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If GF2EXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If GF2EXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, GF2EXArgBound = 0. // If a single h is going to be used with many g's // then you should build a GF2EXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If GF2EXArgBound > 0, a table of size less than m may be built. struct GF2EXArgument { vec_GF2EX H; }; NTL_THREAD_LOCAL extern long GF2EXArgBound; void build(GF2EXArgument& H, const GF2EX& h, const GF2EXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(GF2EX& x, const GF2EX& g, const GF2EXArgument& H, const GF2EXModulus& F); inline GF2EX CompMod(const GF2EX& g, const GF2EXArgument& H, const GF2EXModulus& F) { GF2EX x; CompMod(x, g, H, F); NTL_OPT_RETURN(GF2EX, x); } void MinPolySeq(GF2EX& h, const vec_GF2E& a, long m); inline GF2EX MinPolySeq(const vec_GF2E& a, long m) { GF2EX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(GF2EX, x); } void MinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F); inline GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F) { GF2EX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(GF2EX, x); } void MinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m) { GF2EX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2EX, x); } void ProbMinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F); inline GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F) { GF2EX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(GF2EX, x); } void ProbMinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m) { GF2EX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2EX, x); } void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F); inline GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F) { GF2EX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(GF2EX, x); } void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F, long m) { GF2EX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2EX, x); } struct GF2EXTransMultiplier { GF2EX f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(GF2EXTransMultiplier& B, const GF2EX& b, const GF2EXModulus& F); void TransMulMod(GF2EX& x, const GF2EX& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F); void UpdateMap(vec_GF2E& x, const vec_GF2E& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F); inline vec_GF2E UpdateMap(const vec_GF2E& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F) { vec_GF2E x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_GF2E, x); } void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F); inline vec_GF2E ProjectPowers(const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F) { vec_GF2E x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_GF2E, x); } void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F); inline vec_GF2E ProjectPowers(const vec_GF2E& a, long k, const GF2EX& H, const GF2EXModulus& F) { vec_GF2E x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_GF2E, x); } inline void project(GF2E& x, const vec_GF2E& a, const GF2EX& b) { InnerProduct(x, a, b.rep); } inline GF2E project(const vec_GF2E& a, const GF2EX& b) { GF2E x; InnerProduct(x, a, b.rep); NTL_OPT_RETURN(GF2E, x); } /********************************************************** Modular Composition and Minimal Polynomials in towers ***********************************************************/ // composition void CompTower(GF2EX& x, const GF2X& g, const GF2EXArgument& A, const GF2EXModulus& F); inline GF2EX CompTower(const GF2X& g, const GF2EXArgument& A, const GF2EXModulus& F) { GF2EX x; CompTower(x, g, A, F); NTL_OPT_RETURN(GF2EX, x); } void CompTower(GF2EX& x, const GF2X& g, const GF2EX& h, const GF2EXModulus& F); inline GF2EX CompTower(const GF2X& g, const GF2EX& h, const GF2EXModulus& F) { GF2EX x; CompTower(x, g, h, F); NTL_OPT_RETURN(GF2EX, x); } // prob min poly void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m) { GF2X x; ProbMinPolyTower(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } inline void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F) { ProbMinPolyTower(h, g, F, deg(F)*GF2E::degree()); } inline GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F) { GF2X x; ProbMinPolyTower(x, g, F); NTL_OPT_RETURN(GF2X, x); } // min poly void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m) { GF2X x; MinPolyTower(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } inline void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F) { MinPolyTower(h, g, F, deg(F)*GF2E::degree()); } inline GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F) { GF2X x; MinPolyTower(x, g, F); NTL_OPT_RETURN(GF2X, x); } // irred poly void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F, long m) { GF2X x; IrredPolyTower(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } inline void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F) { IrredPolyTower(h, g, F, deg(F)*GF2E::degree()); } inline GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F) { GF2X x; IrredPolyTower(x, g, F); NTL_OPT_RETURN(GF2X, x); } /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_GF2E& S, const GF2EX& f); inline vec_GF2E TraceVec(const GF2EX& f) { vec_GF2E x; TraceVec(x, f); NTL_OPT_RETURN(vec_GF2E, x); } void TraceMod(GF2E& x, const GF2EX& a, const GF2EXModulus& F); inline GF2E TraceMod(const GF2EX& a, const GF2EXModulus& F) { GF2E x; TraceMod(x, a, F); NTL_OPT_RETURN(GF2E, x); } void TraceMod(GF2E& x, const GF2EX& a, const GF2EX& f); inline GF2E TraceMod(const GF2EX& a, const GF2EX& f) { GF2E x; TraceMod(x, a, f); NTL_OPT_RETURN(GF2E, x); } void NormMod(GF2E& x, const GF2EX& a, const GF2EX& f); inline GF2E NormMod(const GF2EX& a, const GF2EX& f) { GF2E x; NormMod(x, a, f); NTL_OPT_RETURN(GF2E, x); } void resultant(GF2E& rres, const GF2EX& a, const GF2EX& b); inline GF2E resultant(const GF2EX& a, const GF2EX& b) { GF2E x; resultant(x, a, b); NTL_OPT_RETURN(GF2E, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/GF2EXFactoring.h000644 000765 000024 00000015551 12377144457 017544 0ustar00shoupstaff000000 000000 #ifndef NTL_GF2EXFactoring__H #define NTL_GF2EXFactoring__H #include #include NTL_OPEN_NNS /************************************************************ factorization routines ************************************************************/ void SquareFreeDecomp(vec_pair_GF2EX_long& u, const GF2EX& f); inline vec_pair_GF2EX_long SquareFreeDecomp(const GF2EX& f) { vec_pair_GF2EX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_GF2E& x, const GF2EX& f); inline vec_GF2E FindRoots(const GF2EX& f) { vec_GF2E x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(GF2E& root, const GF2EX& f); inline GF2E FindRoot(const GF2EX& f) { GF2E x; FindRoot(x, f); return x; } // finds a single root of f. // assumes that f is monic and splits into distinct linear factors void SFBerlekamp(vec_GF2EX& factors, const GF2EX& f, long verbose=0); inline vec_GF2EX SFBerlekamp(const GF2EX& f, long verbose=0) { vec_GF2EX x; SFBerlekamp(x, f, verbose); return x; } // Assumes f is square-free and monic. // returns list of factors of f. // Uses "Berlekamp" appraoch. void berlekamp(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose=0); inline vec_pair_GF2EX_long berlekamp(const GF2EX& f, long verbose=0) { vec_pair_GF2EX_long x; berlekamp(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Berlekamp" appraoch. NTL_THREAD_LOCAL extern long GF2EX_BlockingFactor; // Controls GCD blocking for DDF. void DDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h, long verbose=0); inline vec_pair_GF2EX_long DDF(const GF2EX& f, const GF2EX& h, long verbose=0) { vec_pair_GF2EX_long x; DDF(x, f, h, verbose); return x; } // Performs distinct-degree factorization. // Assumes f is monic and square-free, and h = X^p mod f // Obsolete: see NewDDF, below. NTL_THREAD_LOCAL extern long GF2EX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF NTL_THREAD_LOCAL extern char GF2EX_stem[]; // Determines filename stem for external storage in NewDDF. NTL_THREAD_LOCAL extern double GF2EXFileThresh; // external files are used for baby/giant steps if size // of these tables exceeds GF2EXFileThresh KB. void NewDDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h, long verbose=0); inline vec_pair_GF2EX_long NewDDF(const GF2EX& f, const GF2EX& h, long verbose=0) { vec_pair_GF2EX_long x; NewDDF(x, f, h, verbose); return x; } // same as above, but uses baby-step/giant-step method void EDF(vec_GF2EX& factors, const GF2EX& f, const GF2EX& b, long d, long verbose=0); inline vec_GF2EX EDF(const GF2EX& f, const GF2EX& b, long d, long verbose=0) { vec_GF2EX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_GF2EX& factors, const GF2EX& f, long verbose=0); inline vec_GF2EX RootEDF(const GF2EX& f, long verbose=0) { vec_GF2EX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_GF2EX& factors, const GF2EX& f, long verbose=0); inline vec_GF2EX SFCanZass(const GF2EX& f, long verbose=0) { vec_GF2EX x; SFCanZass(x, f, verbose); return x; } // Assumes f is monic and square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void CanZass(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose=0); inline vec_pair_GF2EX_long CanZass(const GF2EX& f, long verbose=0) { vec_pair_GF2EX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(GF2EX& f, const vec_pair_GF2EX_long& v); inline GF2EX mul(const vec_pair_GF2EX_long& v) { GF2EX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const GF2EX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const GF2EX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const GF2EX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(GF2EX& f, long n); inline GF2EX BuildIrred_GF2EX(long n) { GF2EX x; BuildIrred(x, n); NTL_OPT_RETURN(GF2EX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(GF2EX& f, const GF2EX& g); inline GF2EX BuildRandomIrred(const GF2EX& g) { GF2EX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(GF2EX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long RecComputeDegree(const GF2EX& h, const GF2EXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long IterComputeDegree(const GF2EX& h, const GF2EXModulus& F); void TraceMap(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& b); inline GF2EX TraceMap(const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& b) { GF2EX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) void PowerCompose(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F); inline GF2EX PowerCompose(const GF2EX& a, long d, const GF2EXModulus& F) { GF2EX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) void PlainFrobeniusMap(GF2EX& h, const GF2EXModulus& F); void ComposeFrobeniusMap(GF2EX& y, const GF2EXModulus& F); void FrobeniusMap(GF2EX& h, const GF2EXModulus& F); inline GF2EX FrobeniusMap(const GF2EXModulus& F) { GF2EX x; FrobeniusMap(x, F); return x; } long UseComposeFrobenius(long d, long n); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/GF2X.h000644 000765 000024 00000047646 12377144457 015614 0ustar00shoupstaff000000 000000 #ifndef NTL_GF2X__H #define NTL_GF2X__H #include #include #include #include NTL_OPEN_NNS class GF2E; // forward declaration class GF2XModulus; class GF2X { public: typedef GF2 coeff_type; typedef GF2E residue_type; typedef GF2XModulus modulus_type; WordVector xrep; typedef vec_GF2 VectorBaseType; GF2X() { } explicit GF2X(long a) { *this = a; } explicit GF2X(GF2 a) { *this = a; } ~GF2X() { } GF2X(INIT_SIZE_TYPE, long n); GF2X& operator=(const GF2X& a) { xrep = a.xrep; return *this; } inline GF2X& operator=(GF2 a); inline GF2X& operator=(long a); void normalize(); static const GF2X& zero(); void kill() { xrep.kill(); } void SetMaxLength(long n); void SetLength(long n); ref_GF2 operator[](long i); const GF2 operator[](long i) const; NTL_THREAD_LOCAL static long HexOutput; inline GF2X(long i, GF2 c); inline GF2X(long i, long c); inline GF2X(INIT_MONO_TYPE, long i, GF2 c); inline GF2X(INIT_MONO_TYPE, long i, long c); inline GF2X(INIT_MONO_TYPE, long i); GF2X(GF2X& x, INIT_TRANS_TYPE) : xrep(x.xrep, INIT_TRANS) { } // This should only be used for simple, local variables // that are not be subject to special memory management. // mainly for internal consumption by GF2XWatcher void release() { xrep.release(); } }; long IsZero(const GF2X& a); long IsOne(const GF2X& a); long IsX(const GF2X& a); const GF2 coeff(const GF2X& a, long i); const GF2 LeadCoeff(const GF2X& a); const GF2 ConstTerm(const GF2X& a); inline void clear(GF2X& x) { x.xrep.ZeroLength(); } void set(GF2X& x); void SetX(GF2X& x); void SetCoeff(GF2X& x, long i); void SetCoeff(GF2X& x, long i, GF2 a); void SetCoeff(GF2X& x, long i, long a); inline GF2X::GF2X(long i, GF2 a) { SetCoeff(*this, i, a); } inline GF2X::GF2X(long i, long a) { SetCoeff(*this, i, a); } inline GF2X::GF2X(INIT_MONO_TYPE, long i, GF2 a) { SetCoeff(*this, i, a); } inline GF2X::GF2X(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline GF2X::GF2X(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void swap(GF2X& a, GF2X& b); long deg(const GF2X& aa); long weight(const GF2X& a); long operator==(const GF2X& a, const GF2X& b); inline long operator!=(const GF2X& a, const GF2X& b) { return !(a == b); } long operator==(const GF2X& a, GF2 b); long operator==(const GF2X& a, long b); inline long operator==(GF2 a, const GF2X& b) { return b == a; } inline long operator==(long a, const GF2X& b) { return b == a; } inline long operator!=(const GF2X& a, GF2 b) { return !(a == b); } inline long operator!=(const GF2X& a, long b) { return !(a == b); } inline long operator!=(GF2 a, const GF2X& b) { return !(a == b); } inline long operator!=(long a, const GF2X& b) { return !(a == b); } NTL_SNS istream & operator>>(NTL_SNS istream& s, GF2X& a); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const GF2X& a); void random(GF2X& x, long n); inline GF2X random_GF2X(long n) { GF2X x; random(x, n); NTL_OPT_RETURN(GF2X, x); } void add(GF2X& x, const GF2X& a, const GF2X& b); void add(GF2X& x, const GF2X& a, GF2 b); void add(GF2X& x, const GF2X& a, long b); inline void add(GF2X& x, GF2 a, const GF2X& b) { add(x, b, a); } inline void add(GF2X& x, long a, const GF2X& b) { add(x, b, a); } inline void sub(GF2X& x, const GF2X& a, const GF2X& b) { add(x, a, b); } inline void sub(GF2X& x, const GF2X& a, GF2 b) { add(x, a, b); } inline void sub(GF2X& x, const GF2X& a, long b) { add(x, a, b); } inline void sub(GF2X& x, GF2 a, const GF2X& b) { add(x, a, b); } inline void sub(GF2X& x, long a, const GF2X& b) { add(x, a, b); } inline void negate(GF2X& x, const GF2X& a) { x = a; } inline GF2X operator+(const GF2X& a, const GF2X& b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator+(const GF2X& a, GF2 b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator+(const GF2X& a, long b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator+(GF2 a, const GF2X& b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator+(long a, const GF2X& b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(const GF2X& a, const GF2X& b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(const GF2X& a, GF2 b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(const GF2X& a, long b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(GF2 a, const GF2X& b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(long a, const GF2X& b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator+=(GF2X& x, const GF2X& b) { add(x, x, b); return x; } inline GF2X& operator+=(GF2X& x, GF2 b) { add(x, x, b); return x; } inline GF2X& operator+=(GF2X& x, long b) { add(x, x, b); return x; } inline GF2X& operator-=(GF2X& x, const GF2X& b) { sub(x, x, b); return x; } inline GF2X& operator-=(GF2X& x, GF2 b) { sub(x, x, b); return x; } inline GF2X& operator-=(GF2X& x, long b) { sub(x, x, b); return x; } inline GF2X operator-(const GF2X& a) { GF2X x; negate(x, a); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator++(GF2X& x) { add(x, x, 1); return x; } inline void operator++(GF2X& x, int) { add(x, x, 1); } inline GF2X& operator--(GF2X& x) { sub(x, x, 1); return x; } inline void operator--(GF2X& x, int) { sub(x, x, 1); } void mul(GF2X& c, const GF2X& a, const GF2X& b); void OldMul(GF2X& c, const GF2X& a, const GF2X& b); void mul(GF2X& x, const GF2X& a, GF2 b); void mul(GF2X& x, const GF2X& a, long b); inline void mul(GF2X& x, GF2 a, const GF2X& b) { mul(x, b, a); } inline void mul(GF2X& x, long a, const GF2X& b) { mul(x, b, a); } void MulByX(GF2X& x, const GF2X& a); inline GF2X MulByX(const GF2X& a) { GF2X x; MulByX(x, a); NTL_OPT_RETURN(GF2X, x); } void sqr(GF2X& c, const GF2X& a); inline GF2X sqr(const GF2X& a) { GF2X x; sqr(x, a); NTL_OPT_RETURN(GF2X, x); } void trunc(GF2X& x, const GF2X& a, long m); inline GF2X trunc(const GF2X& a, long m) { GF2X x; trunc(x, a, m); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(const GF2X& a, const GF2X& b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(const GF2X& a, GF2 b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(const GF2X& a, long b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(GF2 a, const GF2X& b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(long a, const GF2X& b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator*=(GF2X& x, const GF2X& b) { mul(x, x, b); return x; } inline GF2X& operator*=(GF2X& x, GF2 b) { mul(x, x, b); return x; } inline GF2X& operator*=(GF2X& x, long b) { mul(x, x, b); return x; } void power(GF2X& x, const GF2X& a, long e); // x = a^e (e >= 0) inline GF2X power(const GF2X& a, long e) { GF2X x; power(x, a, e); NTL_OPT_RETURN(GF2X, x); } typedef Vec vec_GF2X; void LeftShift(GF2X& c, const GF2X& a, long n); inline GF2X LeftShift(const GF2X& a, long n) { GF2X x; LeftShift(x, a, n); NTL_OPT_RETURN(GF2X, x); } void ShiftAdd(GF2X& c, const GF2X& a, long n); void RightShift(GF2X& c, const GF2X& a, long n); inline GF2X RightShift(const GF2X& a, long n) { GF2X x; RightShift(x, a, n); NTL_OPT_RETURN(GF2X, x); } #ifndef NTL_TRANSITION inline GF2X operator>>(const GF2X& a, long n) { GF2X x; RightShift(x, a, n); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator<<(const GF2X& a, long n) { GF2X x; LeftShift(x, a, n); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator<<=(GF2X& x, long n) { LeftShift(x, x, n); return x; } inline GF2X& operator>>=(GF2X& x, long n) { RightShift(x, x, n); return x; } #endif void CopyReverse(GF2X& c, const GF2X& a, long hi); // c[0..hi] = reverse(a[0..hi]), with zero fill as necessary inline void reverse(GF2X& c, const GF2X& a, long hi) { CopyReverse(c, a, hi); } inline GF2X reverse(const GF2X& a, long hi) { GF2X x; reverse(x, a, hi); NTL_OPT_RETURN(GF2X, x); } inline void reverse(GF2X& c, const GF2X& a) { CopyReverse(c, a, deg(a)); } inline GF2X reverse(const GF2X& a) { GF2X x; reverse(x, a); NTL_OPT_RETURN(GF2X, x); } void InvTrunc(GF2X& c, const GF2X& a, long e); inline GF2X InvTrunc(const GF2X& a, long e) { GF2X x; InvTrunc(x, a, e); NTL_OPT_RETURN(GF2X, x); } class GF2XModulus { public: GF2XModulus(); ~GF2XModulus(); GF2XModulus(const GF2XModulus&); GF2XModulus& operator=(const GF2XModulus&); GF2XModulus(const GF2X& ff); GF2X f; // the modulus operator const GF2X& () const { return f; } const GF2X& val() const { return f; } long n; // deg(f) long sn; // f.xrep.length() long posn; // n - NTL_BITS_PER_LONG*(sn-1); long k3; // used for trinomials and pentanomials long k2; long k1; long size; // word length of residues long WordLength() const { return size; } _ntl_ulong msk; // mask of high bits of residues long method; vec_GF2X stab; _ntl_ulong **stab_ptr; long *stab_cnt; _ntl_ulong *stab1; GF2X h0, f0; vec_GF2 tracevec; }; inline long deg(const GF2XModulus& F) { return F.n; } void build(GF2XModulus& F, const GF2X& f); void rem(GF2X& r, const GF2X& a, const GF2XModulus& F); void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F); void div(GF2X& q, const GF2X& a, const GF2XModulus& F); void PlainDivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b); void PlainDiv(GF2X& q, const GF2X& a, const GF2X& b); void PlainRem(GF2X& r, const GF2X& a, const GF2X& b); void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2XModulus& F); inline GF2X MulMod(const GF2X& a, const GF2X& b, const GF2XModulus& F) { GF2X x; MulMod(x, a, b, F); NTL_OPT_RETURN(GF2X, x); } void SqrMod(GF2X& c, const GF2X& a, const GF2XModulus& F); inline GF2X SqrMod(const GF2X& a, const GF2XModulus& F) { GF2X x; SqrMod(x, a, F); NTL_OPT_RETURN(GF2X, x); } void MulByXMod(GF2X& c, const GF2X& a, const GF2XModulus& F); inline GF2X MulByXMod(const GF2X& a, const GF2XModulus& F) { GF2X x; MulByXMod(x, a, F); NTL_OPT_RETURN(GF2X, x); } void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2X& f); inline GF2X MulMod(const GF2X& a, const GF2X& b, const GF2X& f) { GF2X x; MulMod(x, a, b, f); NTL_OPT_RETURN(GF2X, x); } void SqrMod(GF2X& c, const GF2X& a, const GF2X& f); inline GF2X SqrMod(const GF2X& a, const GF2X& f) { GF2X x; SqrMod(x, a, f); NTL_OPT_RETURN(GF2X, x); } void MulByXMod(GF2X& c, const GF2X& a, const GF2X& f); inline GF2X MulByXMod(const GF2X& a, const GF2X& f) { GF2X x; MulByXMod(x, a, f); NTL_OPT_RETURN(GF2X, x); } void InvMod(GF2X& c, const GF2X& a, const GF2X& f); inline GF2X InvMod(const GF2X& a, const GF2X& f) { GF2X x; InvMod(x, a, f); NTL_OPT_RETURN(GF2X, x); } long InvModStatus(GF2X& c, const GF2X& a, const GF2X& f); inline long InvModStatus(GF2X& c, const GF2X& a, const GF2XModulus& F) { return InvModStatus(c, a, F.f); } void PowerMod(GF2X& h, const GF2X& g, const ZZ& e, const GF2XModulus& F); inline void PowerMod(GF2X& x, const GF2X& g, long e, const GF2XModulus& F) { PowerMod(x, g, ZZ_expo(e), F); } void PowerXMod(GF2X& hh, const ZZ& e, const GF2XModulus& F); inline void PowerXMod(GF2X& x, long e, const GF2XModulus& F) { PowerXMod(x, ZZ_expo(e), F); } inline GF2X PowerMod(const GF2X& g, const ZZ& e, const GF2XModulus& F) { GF2X x; PowerMod(x, g, e, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X PowerMod(const GF2X& g, long e, const GF2XModulus& F) { GF2X x; PowerMod(x, g, e, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X PowerXMod(const ZZ& e, const GF2XModulus& F) { GF2X x; PowerXMod(x, e, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X PowerXMod(long e, const GF2XModulus& F) { GF2X x; PowerXMod(x, e, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator%(const GF2X& a, const GF2XModulus& F) { GF2X x; rem(x, a, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator%=(GF2X& x, const GF2XModulus& F) { rem(x, x, F); return x; } inline GF2X operator/(const GF2X& a, const GF2XModulus& F) { GF2X x; div(x, a, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator/=(GF2X& x, const GF2XModulus& F) { div(x, x, F); return x; } void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b); void div(GF2X& q, const GF2X& a, const GF2X& b); void div(GF2X& q, const GF2X& a, GF2 b); void div(GF2X& q, const GF2X& a, long b); void rem(GF2X& r, const GF2X& a, const GF2X& b); inline GF2X operator/(const GF2X& a, const GF2X& b) { GF2X x; div(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator/(const GF2X& a, GF2 b) { GF2X x; div(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator/(const GF2X& a, long b) { GF2X x; div(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator/=(GF2X& x, GF2 b) { div(x, x, b); return x; } inline GF2X& operator/=(GF2X& x, long b) { div(x, x, b); return x; } inline GF2X& operator/=(GF2X& x, const GF2X& b) { div(x, x, b); return x; } inline GF2X operator%(const GF2X& a, const GF2X& b) { GF2X x; rem(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator%=(GF2X& x, const GF2X& b) { rem(x, x, b); return x; } void GCD(GF2X& d, const GF2X& a, const GF2X& b); inline GF2X GCD(const GF2X& a, const GF2X& b) { GF2X x; GCD(x, a, b); NTL_OPT_RETURN(GF2X, x); } void OldGCD(GF2X& d, const GF2X& a, const GF2X& b); void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b); void OldXGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b); void diff(GF2X& c, const GF2X& a); inline GF2X diff(const GF2X& a) { GF2X x; diff(x, a); NTL_OPT_RETURN(GF2X, x); } void conv(GF2X& c, long a); void conv(GF2X& c, GF2 a); void conv(GF2X& x, const vec_GF2& a); inline void conv(GF2X& x, const ZZ& a) { conv(x, to_GF2(a)); } void conv(vec_GF2& x, const GF2X& a); inline GF2X to_GF2X(long a) { GF2X x; conv(x, a); NTL_OPT_RETURN(GF2X, x); } inline GF2X to_GF2X(GF2 a) { GF2X x; conv(x, a); NTL_OPT_RETURN(GF2X, x); } inline GF2X to_GF2X(const vec_GF2& a) { GF2X x; conv(x, a); NTL_OPT_RETURN(GF2X, x); } inline GF2X to_GF2X(const ZZ& a) { GF2X x; conv(x, a); NTL_OPT_RETURN(GF2X, x); } inline vec_GF2 to_vec_GF2(const GF2X& a) { vec_GF2 x; conv(x, a); NTL_OPT_RETURN(vec_GF2, x); } /* additional legacy conversions for v6 conversion regime */ inline void conv(GF2X& x, const GF2X& a) { x = a; } class ZZX; void conv(GF2X& x, const ZZX& a); void conv(ZZX& x, const GF2X& a); /* ------------------------------------- */ inline GF2X& GF2X::operator=(long a) { conv(*this, a); return *this; } inline GF2X& GF2X::operator=(GF2 a) { conv(*this, a); return *this; } void VectorCopy(vec_GF2& x, const GF2X& a, long n); inline vec_GF2 VectorCopy(const GF2X& a, long n) { vec_GF2 x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_GF2, x); } void MulTrunc(GF2X& c, const GF2X& a, const GF2X& b, long n); inline GF2X MulTrunc(const GF2X& a, const GF2X& b, long n) { GF2X x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(GF2X, x); } void SqrTrunc(GF2X& c, const GF2X& a, long n); inline GF2X SqrTrunc(const GF2X& a, long n) { GF2X x; SqrTrunc(x, a, n); NTL_OPT_RETURN(GF2X, x); } long divide(GF2X& q, const GF2X& a, const GF2X& b); long divide(const GF2X& a, const GF2X& b); /*** modular composition routines and data structures ***/ struct GF2XArgument { vec_GF2X H; }; void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& A, const GF2XModulus& F); inline GF2X CompMod(const GF2X& g, const GF2XArgument& A, const GF2XModulus& F) { GF2X x; CompMod(x, g, A, F); NTL_OPT_RETURN(GF2X, x); } void build(GF2XArgument& A, const GF2X& h, const GF2XModulus& F, long m); void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F); inline GF2X CompMod(const GF2X& g, const GF2X& h, const GF2XModulus& F) { GF2X x; CompMod(x, g, h, F); NTL_OPT_RETURN(GF2X, x); } void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2, const GF2X& h, const GF2XModulus& F); void Comp3Mod(GF2X& x1, GF2X& x2, GF2X& x3, const GF2X& g1, const GF2X& g2, const GF2X& g3, const GF2X& h, const GF2XModulus& F); void MinPolySeq(GF2X& h, const vec_GF2& a, long m); inline GF2X MinPolySeq(const vec_GF2& a, long m) { GF2X x; MinPolySeq(x, a, m); NTL_OPT_RETURN(GF2X, x); } void ProbMinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F); inline GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F) { GF2X x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(GF2X, x); } void ProbMinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F, long m); inline GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F, long m) { GF2X x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F); inline GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F) { GF2X x; MinPolyMod(x, g, F); NTL_OPT_RETURN(GF2X, x); } void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F, long m); inline GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F, long m) { GF2X x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F); inline GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F) { GF2X x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(GF2X, x); } void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m); inline GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F, long m) { GF2X x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } // undocumented stuff: void MinPolyInternal(GF2X& h, const GF2X& x, long m); void OldMinPolyInternal(GF2X& h, const GF2X& x, long m); struct GF2XTransMultiplier { GF2X f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F); void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F); inline vec_GF2 UpdateMap(const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F) { vec_GF2 x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_GF2, x); } inline void project(ref_GF2 x, const vec_GF2& a, const GF2X& b) { x = to_GF2(InnerProduct(a.rep, b.xrep)); } inline GF2 project(const vec_GF2& a, const GF2X& b) { return to_GF2(InnerProduct(a.rep, b.xrep)); } void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F); inline vec_GF2 ProjectPowers(const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F) { vec_GF2 x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_GF2, x); } void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2X& h, const GF2XModulus& F); inline vec_GF2 ProjectPowers(const vec_GF2& a, long k, const GF2X& H, const GF2XModulus& F) { vec_GF2 x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_GF2, x); } void TraceVec(vec_GF2& S, const GF2X& f); inline vec_GF2 TraceVec(const GF2X& f) { vec_GF2 x; TraceVec(x, f); NTL_OPT_RETURN(vec_GF2, x); } void TraceMod(ref_GF2 x, const GF2X& a, const GF2XModulus& F); inline GF2 TraceMod(const GF2X& a, const GF2XModulus& F) { GF2 x; TraceMod(x, a, F); return x; } void TraceMod(ref_GF2 x, const GF2X& a, const GF2X& f); inline GF2 TraceMod(const GF2X& a, const GF2X& f) { GF2 x; TraceMod(x, a, f); return x; } void GF2XFromBytes(GF2X& x, const unsigned char *p, long n); inline GF2X GF2XFromBytes(const unsigned char *p, long n) { GF2X x; GF2XFromBytes(x, p, n); NTL_OPT_RETURN(GF2X, x); } void BytesFromGF2X(unsigned char *p, const GF2X& a, long n); inline long NumBits(const GF2X& a) { return deg(a) + 1; } inline long NumBytes(const GF2X& a) { return (NumBits(a) + 7)/8; } // GF2X scratch variabes class GF2XWatcher { public: GF2X *watched; explicit GF2XWatcher(GF2X *_watched) : watched(_watched) {} ~GF2XWatcher() { watched->release(); } }; #define NTL_GF2XRegister(x) NTL_THREAD_LOCAL static GF2X x; GF2XWatcher _WATCHER__ ## x(&x) NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/GF2XFactoring.h000644 000765 000024 00000003264 12377144457 017435 0ustar00shoupstaff000000 000000 #ifndef NTL_GF2XFactoring__H #define NTL_GF2XFactoring__H #include #include NTL_OPEN_NNS long IterIrredTest(const GF2X& f); void SquareFreeDecomp(vec_pair_GF2X_long& u, const GF2X& ff); inline vec_pair_GF2X_long SquareFreeDecomp(const GF2X& f) { vec_pair_GF2X_long x; SquareFreeDecomp(x, f); return x; } void DDF(vec_pair_GF2X_long& factors, const GF2X& ff, long verbose=0); inline vec_pair_GF2X_long DDF(const GF2X& f, long verbose=0) { vec_pair_GF2X_long x; DDF(x, f, verbose); return x; } void EDF(vec_GF2X& factors, const GF2X& ff, long d, long verbose=0); inline vec_GF2X EDF(const GF2X& f, long d, long verbose=0) { vec_GF2X x; EDF(x, f, d, verbose); return x; } void SFCanZass(vec_GF2X& factors, const GF2X& ff, long verbose=0); inline vec_GF2X SFCanZass(const GF2X& f, long verbose=0) { vec_GF2X x; SFCanZass(x, f, verbose); return x; } void CanZass(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0); inline vec_pair_GF2X_long CanZass(const GF2X& f, long verbose=0) { vec_pair_GF2X_long x; CanZass(x, f, verbose); return x; } void mul(GF2X& f, const vec_pair_GF2X_long& v); inline GF2X mul(const vec_pair_GF2X_long& v) { GF2X x; mul(x, v); return x; } void BuildIrred(GF2X& f, long n); inline GF2X BuildIrred_GF2X(long n) { GF2X x; BuildIrred(x, n); NTL_OPT_RETURN(GF2X, x); } void BuildRandomIrred(GF2X& f, const GF2X& g); inline GF2X BuildRandomIrred(const GF2X& g) { GF2X x; BuildRandomIrred(x, g); NTL_OPT_RETURN(GF2X, x); } void BuildSparseIrred(GF2X& f, long n); inline GF2X BuildSparseIrred_GF2X(long n) { GF2X x; BuildSparseIrred(x, n); NTL_OPT_RETURN(GF2X, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/GF2XVec.h000644 000765 000024 00000002675 12377144457 016243 0ustar00shoupstaff000000 000000 #ifndef NTL_GF2XVec__H #define NTL_GF2XVec__H #include NTL_OPEN_NNS /***************************************************************** The class GF2XVec implements vectors of fixed-length GF2X's. You can allocate a vector of GF2X's of a specified length, where the maximum size of each GF2X is also specified. These parameters can be specified once, either with a constructor, or with SetSize. It is an error to try to re-size a vector, or store a GF2X that doesn't fit. The space can be released with "kill", and then you are free to call SetSize again. If you want more flexible---but less efficient---vectors, use vec_GF2X. *****************************************************************/ class GF2XVec { private: GF2X* v; long len; long bsize; public: GF2XVec& operator=(const GF2XVec&); GF2XVec(const GF2XVec&); long length() const { return len; } long BaseSize() const { return bsize; } void SetSize(long n, long d); void kill(); GF2XVec() { v = 0; len = 0; bsize = 0; } GF2XVec(long n, long d) { v = 0; len = 0; bsize = 0; SetSize(n, d); } ~GF2XVec() { kill(); }; GF2X* elts() { return v; } const GF2X* elts() const { return v; } GF2X& operator[](long i) { return v[i]; } const GF2X& operator[](long i) const { return v[i]; } static void swap_impl(GF2XVec& x, GF2XVec& y); }; inline void swap(GF2XVec& x, GF2XVec& y) { GF2XVec::swap_impl(x, y); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/HNF.h000644 000765 000024 00000001365 12377144457 015505 0ustar00shoupstaff000000 000000 #ifndef NTL_HNF__H #define NTL_HNF__H #include NTL_OPEN_NNS void HNF(mat_ZZ& W, const mat_ZZ& A, const ZZ& D); // The input matrix A is an n x m matrix of rank m (so n >= m), and // D is a multiple of the determinant of the lattice L spanned by // the rows of A. // W is computed as the Hermite Normal Form of A; // that is, W is the unique m x m matrix whose rows span L, such that // - W is lower triangular, // - the diagonal entries are positive, // - any entry below the diagonal is a non-negative number // strictly less than the diagonal entry in its column. // Currently, this is implemented using the algorithm of // [P. Domich, R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987]. NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/LLL.h000644 000765 000024 00000013245 12377144457 015515 0ustar00shoupstaff000000 000000 #ifndef NTL_LLL__H #define NTL_LLL__H #include #include NTL_OPEN_NNS long LLL(ZZ& det, mat_ZZ& B, long verbose = 0); long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose = 0); long LLL(ZZ& det, mat_ZZ& B, long a, long b, long verbose = 0); long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose = 0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long verbose=0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, long verbose=0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose=0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, long a, long b, long verbose=0); long image(ZZ& det, mat_ZZ& B, long verbose = 0); long image(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose = 0); long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce=0); typedef long (*LLLCheckFct)(const vec_ZZ&); NTL_THREAD_LOCAL extern double LLLStatusInterval; NTL_THREAD_LOCAL extern char *LLLDumpFile; // classical Gramm-Schmidt versions long LLL_FP(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long LLL_FP(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long BKZ_FP(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0) ; long BKZ_FP(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long LLL_XD(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long LLL_XD(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long BKZ_XD(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_XD(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long LLL_QP(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long LLL_QP(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long BKZ_QP(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_QP(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_QP1(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_QP1(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long LLL_RR(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long LLL_RR(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long BKZ_RR(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_RR(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); // Givens rotations versions long G_LLL_FP(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_FP(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_FP(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0) ; long G_BKZ_FP(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_XD(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_XD(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_XD(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_XD(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_QP(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_QP(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_QP(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_QP(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_QP1(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_QP1(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_RR(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_RR(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_RR(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_RR(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); void ComputeGS(const mat_ZZ& B, mat_RR& mu, vec_RR& c); void NearVector(vec_ZZ& ww, const mat_ZZ& BB, const vec_ZZ& a); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/RR.h000644 000765 000024 00000036327 12377144457 015423 0ustar00shoupstaff000000 000000 #ifndef NTL_RR__H #define NTL_RR__H #include #include #include NTL_OPEN_NNS class RR { public: ZZ x; long e; RR() { e = 0; } explicit RR(double a) : e(0) { *this = a; } inline RR(INIT_VAL_TYPE, const ZZ& a); inline RR(INIT_VAL_TYPE, int a); inline RR(INIT_VAL_TYPE, long a); inline RR(INIT_VAL_TYPE, unsigned int a); inline RR(INIT_VAL_TYPE, unsigned long a); inline RR(INIT_VAL_TYPE, float a); inline RR(INIT_VAL_TYPE, double a); inline RR(INIT_VAL_TYPE, const xdouble& a); inline RR(INIT_VAL_TYPE, const quad_float& a); inline RR(INIT_VAL_TYPE, const char *a); // read from string inline RR(INIT_VAL_TYPE, const RR& a); inline RR& operator=(double a); RR(RR& z, INIT_TRANS_TYPE) : x(z.x, INIT_TRANS), e(z.e) { } ~RR() { } const ZZ& mantissa() const { return x; } long exponent() const { return e; } NTL_THREAD_LOCAL static long prec; static void SetPrecision(long p); static long precision() { return prec; } NTL_THREAD_LOCAL static long oprec; static void SetOutputPrecision(long p); static long OutputPrecision() { return oprec; } #ifdef NTL_TRANSITION private: RR& operator=(const RR&); RR(const RR&); #endif }; long IsZero(const RR& a); long IsOne(const RR& a); long sign(const RR& a); void clear(RR& z); void set(RR& z); void swap(RR& a, RR& b); void add(RR& z, const RR& a, const RR& b); void add(RR& z, const RR& a, double b); inline void add(RR& z, double a, const RR& b) { add(z, b, a); } void sub(RR& z, const RR& a, const RR& b); void sub(RR& z, const RR& a, double b); void sub(RR& z, double a, const RR& b); void negate(RR& z, const RR& a); void abs(RR& z, const RR& a); inline RR abs(const RR& a) { RR z; abs(z, a); NTL_OPT_RETURN(RR, z); } inline RR fabs(const RR& a) { RR z; abs(z, a); NTL_OPT_RETURN(RR, z); } void mul(RR& z, const RR& a, const RR& b); void mul(RR& z, const RR& a, double b); inline void mul(RR& z, double a, const RR& b) { mul(z, b, a); } void sqr(RR& z, const RR& a); inline RR sqr(const RR& a) { RR z; sqr(z, a); NTL_OPT_RETURN(RR, z); } void div(RR& z, const RR& a, const RR& b); void div(RR& z, const RR& a, double b); void div(RR& z, double a, const RR& b); void inv(RR& z, const RR& a); inline RR inv(const RR& a) { RR z; inv(z, a); NTL_OPT_RETURN(RR, z); } // operator notation: inline RR operator+(const RR& a, const RR& b) { RR x; add(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator+(const RR& a, double b) { RR x; add(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator+(double a, const RR& b) { RR x; add(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR& operator+=(RR& x, const RR& b) { add(x, x, b); return x; } inline RR& operator+=(RR& x, double b) { add(x, x, b); return x; } inline RR operator-(const RR& a, const RR& b) { RR x; sub(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator-(const RR& a, double b) { RR x; sub(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator-(double a, const RR& b) { RR x; sub(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR& operator-=(RR& x, const RR& b) { sub(x, x, b); return x; } inline RR& operator-=(RR& x, double b) { sub(x, x, b); return x; } inline RR operator*(const RR& a, const RR& b) { RR x; mul(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator*(const RR& a, double b) { RR x; mul(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator*(double a, const RR& b) { RR x; mul(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR& operator*=(RR& x, const RR& b) { mul(x, x, b); return x; } inline RR& operator*=(RR& x, double b) { mul(x, x, b); return x; } inline RR operator/(const RR& a, const RR& b) { RR x; div(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator/(const RR& a, double b) { RR x; div(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator/(double a, const RR& b) { RR x; div(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR& operator/=(RR& x, const RR& b) { div(x, x, b); return x; } inline RR& operator/=(RR& x, double b) { div(x, x, b); return x; } inline RR operator-(const RR& a) { RR x; negate(x, a); NTL_OPT_RETURN(RR, x); } inline RR& operator++(RR& x) { add(x, x, 1); return x; } inline void operator++(RR& x, int) { add(x, x, 1); } inline RR& operator--(RR& x) { sub(x, x, 1); return x; } inline void operator--(RR& x, int) { sub(x, x, 1); } long compare(const RR& a, const RR& b); long compare(const RR& a, double b); inline long compare(double a, const RR& b) { return -compare(b, a); } long operator==(const RR& a, const RR& b); inline long operator!=(const RR& a, const RR& b) { return !(a == b); } inline long operator<=(const RR& a, const RR& b) { return compare(a, b) <= 0; } inline long operator>=(const RR& a, const RR& b) { return compare(a, b) >= 0; } inline long operator <(const RR& a, const RR& b) { return compare(a, b) < 0; } inline long operator >(const RR& a, const RR& b) { return compare(a, b) > 0; } long operator==(const RR& a, double b); inline long operator!=(const RR& a, double b) { return !(a == b); } inline long operator<=(const RR& a, double b) { return compare(a, b) <= 0; } inline long operator>=(const RR& a, double b) { return compare(a, b) >= 0; } inline long operator <(const RR& a, double b) { return compare(a, b) < 0; } inline long operator >(const RR& a, double b) { return compare(a, b) > 0; } inline long operator==(double a, const RR& b) { return (b == a); } inline long operator!=(double a, const RR& b) { return !(a == b); } inline long operator<=(double a, const RR& b) { return compare(a, b) <= 0; } inline long operator>=(double a, const RR& b) { return compare(a, b) >= 0; } inline long operator <(double a, const RR& b) { return compare(a, b) < 0; } inline long operator >(double a, const RR& b) { return compare(a, b) > 0; } void ceil(RR& z, const RR& a); inline RR ceil(const RR& a) { RR z; ceil(z, a); NTL_OPT_RETURN(RR, z); } void floor(RR& z, const RR& a); inline RR floor(const RR& a) { RR z; floor(z, a); NTL_OPT_RETURN(RR, z); } void trunc(RR& z, const RR& a); inline RR trunc(const RR& a) { RR z; trunc(z, a); NTL_OPT_RETURN(RR, z); } void round(RR& z, const RR& a); inline RR round(const RR& a) { RR z; round(z, a); NTL_OPT_RETURN(RR, z); } void RoundToPrecision(RR& z, const RR& a, long p); inline RR RoundToPrecision(const RR& a, long p) { RR z; RoundToPrecision(z, a, p); NTL_OPT_RETURN(RR, z); } // routines with a precision parameter void ConvPrec(RR& z, const RR& a, long p); inline RR ConvPrec(const RR& a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void AddPrec(RR& z, const RR& a, const RR& b, long p); inline RR AddPrec(const RR& a, const RR& b, long p) { RR z; AddPrec(z, a, b, p); NTL_OPT_RETURN(RR, z); } void SubPrec(RR& z, const RR& a, const RR& b, long p); inline RR SubPrec(const RR& a, const RR& b, long p) { RR z; SubPrec(z, a, b, p); NTL_OPT_RETURN(RR, z); } void NegatePrec(RR& z, const RR& a, long p); inline RR NegatePrec(const RR& a, long p) { RR z; NegatePrec(z, a, p); NTL_OPT_RETURN(RR, z); } void AbsPrec(RR& z, const RR& a, long p); inline RR AbsPrec(const RR& a, long p) { RR z; AbsPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void MulPrec(RR& z, const RR& a, const RR& b, long p); inline RR MulPrec(const RR& a, const RR& b, long p) { RR z; MulPrec(z, a, b, p); NTL_OPT_RETURN(RR, z); } void SqrPrec(RR& z, const RR& a, long p); inline RR SqrPrec(const RR& a, long p) { RR z; SqrPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void DivPrec(RR& z, const RR& a, const RR& b, long p); inline RR DivPrec(const RR& a, const RR& b, long p) { RR z; DivPrec(z, a, b, p); NTL_OPT_RETURN(RR, z); } void InvPrec(RR& z, const RR& a, long p); inline RR InvPrec(const RR& a, long p) { RR z; InvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void SqrRootPrec(RR& z, const RR& a, long p); inline RR SqrRootPrec(const RR& a, long p) { RR z; SqrRootPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void TruncPrec(RR& z, const RR& a, long p); inline RR TruncPrec(const RR& a, long p) { RR z; TruncPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void FloorPrec(RR& z, const RR& a, long p); inline RR FloorPrec(const RR& a, long p) { RR z; FloorPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void CeilPrec(RR& z, const RR& a, long p); inline RR CeilPrec(const RR& a, long p) { RR z; CeilPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void RoundPrec(RR& z, const RR& a, long p); inline RR RoundPrec(const RR& a, long p) { RR z; RoundPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, const ZZ& a, long p); inline RR ConvPrec(const ZZ& a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, long a, long p); inline RR ConvPrec(long a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } inline void ConvPrec(RR& z, int a, long p) { ConvPrec(z, long(a), p); } inline RR ConvPrec(int a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, unsigned long a, long p); inline RR ConvPrec(unsigned long a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } inline void ConvPrec(RR& z, unsigned int a, long p) { ConvPrec(z, (unsigned long)(a), p); } inline RR ConvPrec(unsigned int a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, double a, long p); inline RR ConvPrec(double a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, const xdouble& a, long p); inline RR ConvPrec(const xdouble& a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, const quad_float& a, long p); inline RR ConvPrec(const quad_float& a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, const char *s, long p); inline RR ConvPrec(const char *s, long p) { RR z; ConvPrec(z, s, p); NTL_OPT_RETURN(RR, z); } void InputPrec(RR& z, NTL_SNS istream& s, long p); inline RR InputPrec(NTL_SNS istream& s, long p) { RR z; InputPrec(z, s, p); NTL_OPT_RETURN(RR, z); } void MakeRRPrec(RR& z, const ZZ& a, long e, long p); inline RR MakeRRPrec(const ZZ& a, long e, long p) { RR z; MakeRRPrec(z, a, e, p); NTL_OPT_RETURN(RR, z); } void conv(RR& z, const ZZ& a); void conv(RR& z, long a); inline void conv(RR& z, int a) { conv(z, long(a)); } void conv(RR& z, unsigned long a); inline void conv(RR& z, unsigned int a) { conv(z, (unsigned long)(a)); } void conv(RR& z, const char *s); void conv(RR& z, double a); inline void conv(RR& z, float a) { conv(z, double(a)); } void conv(RR& z, const xdouble& a); void conv(RR& z, const quad_float& a); void conv(RR& z, const RR& a); inline RR::RR(INIT_VAL_TYPE, int a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, long a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, unsigned int a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, unsigned long a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, float a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, double a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const RR& a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const ZZ& a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const xdouble& a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const quad_float& a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const char *a) { e = 0; conv(*this, a); } inline RR to_RR(int a) { return RR(INIT_VAL, a); } inline RR to_RR(long a) { return RR(INIT_VAL, a); } inline RR to_RR(unsigned int a) { return RR(INIT_VAL, a); } inline RR to_RR(unsigned long a) { return RR(INIT_VAL, a); } inline RR to_RR(float a) { return RR(INIT_VAL, a); } inline RR to_RR(double a) { return RR(INIT_VAL, a); } inline RR to_RR(const ZZ& a) { return RR(INIT_VAL, a); } inline RR to_RR(const RR& a) { return RR(INIT_VAL, a); } inline RR to_RR(const xdouble& a) { return RR(INIT_VAL, a); } inline RR to_RR(const quad_float& a) { return RR(INIT_VAL, a); } inline RR to_RR(const char *a) { return RR(INIT_VAL, a); } inline RR& RR::operator=(double a) { conv(*this, a); return *this; } void conv(ZZ& z, const RR& a); void conv(long& z, const RR& a); void conv(double& z, const RR& a); void conv(xdouble& z, const RR& a); void conv(quad_float& z, const RR& a); inline void conv(int& z, const RR& a) { long t; conv(t, a); z = int(t); } inline void conv(float& z, const RR& a) { double t; conv(t, a); z = float(t); } inline int to_int(const RR& a) { int z; conv(z, a); return z; } inline long to_long(const RR& a) { long z; conv(z, a); return z; } inline float to_float(const RR& a) { float z; conv(z, a); return z; } inline double to_double(const RR& a) { double z; conv(z, a); return z; } inline xdouble to_xdouble(const RR& a) { xdouble z; conv(z, a); return z; } inline quad_float to_quad_float(const RR& a) { quad_float z; conv(z, a); return z; } inline ZZ to_ZZ(const RR& a) { ZZ z; conv(z, a); NTL_OPT_RETURN(ZZ, z); } void CeilToZZ(ZZ& z, const RR& a); inline ZZ CeilToZZ(const RR& a) { ZZ z; CeilToZZ(z, a); NTL_OPT_RETURN(ZZ, z); } void TruncToZZ(ZZ& z, const RR& a); inline ZZ TruncToZZ(const RR& a) { ZZ z; TruncToZZ(z, a); NTL_OPT_RETURN(ZZ, z); } void RoundToZZ(ZZ& z, const RR& a); inline ZZ RoundToZZ(const RR& a) { ZZ z; RoundToZZ(z, a); NTL_OPT_RETURN(ZZ, z); } inline void FloorToZZ(ZZ& z, const RR& a) { conv(z, a); } inline ZZ FloorToZZ(const RR& a) { ZZ z; conv(z, a); NTL_OPT_RETURN(ZZ, z); } /* additional legacy conversions for v6 conversion regime */ inline void conv(unsigned int& x, const RR& a) { long z; conv(z, a); conv(x, z); } inline void conv(unsigned long& x, const RR& a) { long z; conv(z, a); conv(x, z); } /* ------------------------------------- */ void MakeRR(RR& z, const ZZ& a, long e); inline RR MakeRR(const ZZ& a, long e) { RR z; MakeRR(z, a, e); NTL_OPT_RETURN(RR, z); } void random(RR& z); inline RR random_RR() { RR z; random(z); NTL_OPT_RETURN(RR, z); } void power(RR& z, const RR& a, long e); inline RR power(const RR& a, long e) { RR z; power(z, a, e); NTL_OPT_RETURN(RR, z); } void power2(RR& z, long e); inline RR power2_RR(long e) { RR z; power2(z, e); NTL_OPT_RETURN(RR, z); } NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const RR& a); NTL_SNS istream& operator>>(NTL_SNS istream& s, RR& x); void SqrRoot(RR& x, const RR& a); inline RR SqrRoot(const RR& a) { RR z; SqrRoot(z, a); NTL_OPT_RETURN(RR, z); } inline RR sqrt(const RR& a) { RR z; SqrRoot(z, a); NTL_OPT_RETURN(RR, z); } void exp(RR& res, const RR& x); inline RR exp(const RR& a) { RR z; exp(z, a); NTL_OPT_RETURN(RR, z); } void log(RR& res, const RR& x); inline RR log(const RR& a) { RR z; log(z, a); NTL_OPT_RETURN(RR, z); } void log10(RR& res, const RR& x); inline RR log10(const RR& a) { RR z; log10(z, a); NTL_OPT_RETURN(RR, z); } void expm1(RR& res, const RR& x); inline RR expm1(const RR& a) { RR z; expm1(z, a); NTL_OPT_RETURN(RR, z); } void log1p(RR& res, const RR& x); inline RR log1p(const RR& a) { RR z; log1p(z, a); NTL_OPT_RETURN(RR, z); } void pow(RR& res, const RR& x, const RR& y); inline RR pow(const RR& x, const RR& y) { RR z; pow(z, x, y); NTL_OPT_RETURN(RR, z); } void ComputePi(RR& res); inline RR ComputePi_RR() { RR z; ComputePi(z); NTL_OPT_RETURN(RR, z); } void sin(RR& res, const RR& x); inline RR sin(const RR& a) { RR z; sin(z, a); NTL_OPT_RETURN(RR, z); } void cos(RR& res, const RR& x); inline RR cos(const RR& a) { RR z; cos(z, a); NTL_OPT_RETURN(RR, z); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/SPMM_ASM.h000644 000765 000024 00000010576 12377144457 016352 0ustar00shoupstaff000000 000000 /************************************************************* Assembly code support for computing the high-order word of a word * word product (unsigned). Note that these typically only make a significant difference on some 64-bit machines, as on 32-bit machines, the "long long" solution is usually just as good. These code sequences were extracted from a recent version of the file longlong.h from gmp. Copyright notice follows: Copyright 1991, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this file; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *************************************************************/ #if (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))) // To simplify things, we require gcc v2.7 or higher. // ------ POWERPC ------ #if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \ || defined (__ppc__) || defined(__ppc64__) \ || (defined (PPC) && ! defined (CPU_FAMILY)) /* gcc 2.7.x GNU&SysV */ \ || (defined (PPC) && defined (CPU_FAMILY) /* VxWorks */ \ && CPU_FAMILY == PPC) #if (NTL_BITS_PER_LONG == 32) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi; __asm__ ("mulhwu %0,%1,%2" : "=r" (hi) : "%r" (a), "r" (b)); return hi; } #elif (NTL_BITS_PER_LONG == 64) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi; __asm__ ("mulhdu %0,%1,%2" : "=r" (hi) : "%r" (a), "r" (b)); return hi; } #endif #endif // ------ ALPHA ------ #if (defined (__alpha) && NTL_BITS_PER_LONG == 64) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi; __asm__ ("umulh %r1,%2,%0" : "=r" (hi) : "%rJ" (a), "rI" (b)); return hi; } #endif // ------ IA64 ------ #if (defined (__ia64) && NTL_BITS_PER_LONG == 64) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi; __asm__ ("xma.hu %0 = %1, %2, f0" : "=f" (hi) : "f" (a), "f" (b)); return hi; } #endif // ------ x86 ------ #if ((defined (__i386__) || defined (__i486__)) && NTL_BITS_PER_LONG == 32) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi, lo; __asm__ ("mull %3" : "=a" (lo), "=d" (hi) : "%0" (a), "rm" (b)); return hi; } #endif // ------ x86-64 ------ #if (defined (__x86_64__) && NTL_BITS_PER_LONG == 64) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi, lo; __asm__ ("mulq %3" : "=a" (lo), "=d" (hi) : "%0" (a), "rm" (b)); return hi; } #endif // ------ MIPS ------ #if (defined (__mips)) #if (NTL_BITS_PER_LONG == 32) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi, lo; __asm__ ("multu %2,%3" : "=l" (lo), "=h" (hi) : "d" (a), "d" (b)); return hi; } #elif (NTL_BITS_PER_LONG == 64) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi, lo; __asm__ ("dmultu %2,%3" : "=l" (lo), "=h" (hi) : "d" (a), "d" (b)); return hi; } #endif #endif // -------- SPARC -------- #if (defined (__sparc__) && NTL_BITS_PER_LONG == 32) #if (defined (__sparc_v9__) || defined (__sparcv9) || \ defined (__sparc_v8__) || defined (__sparcv8) || defined (__sparclite__)) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { unsigned long hi, lo; __asm__ ("umul %2,%3,%1;rd %%y,%0" : "=r" (hi), "=r" (lo) : "r" (a), "r" (b)); return hi; } #endif #endif #endif // __GNUC__ ntl-6.2.1/include/NTL/WordVector.h000644 000765 000024 00000007225 12377144457 017171 0ustar00shoupstaff000000 000000 #ifndef NTL_WordVector__H #define NTL_WordVector__H /************************************************************** A WordVector is functionally similar to a generic NTL vector of _ntl_ulong. Be careful! the MaxLength() function does not return the max length ever set, but rather the max space allocated, which *may* be more. The FixLength() facility is not available. The reason for special-casing is efficiency (of course). **************************************************************/ #include #include NTL_OPEN_NNS #ifndef NTL_RANGE_CHECK #define NTL_WV_RANGE_CHECK_CODE #else #define NTL_WV_RANGE_CHECK_CODE if (i < 0 || !rep || i >= long(rep[-1])) RangeError(i); #endif // vectors are allocated in chunks of this size #ifndef NTL_WordVectorMinAlloc #define NTL_WordVectorMinAlloc (4) #endif // vectors are always expanded by at least this ratio #ifndef NTL_WordVectorExpansionRatio #define NTL_WordVectorExpansionRatio (1.2) #endif // controls initialization during input #ifndef NTL_WordVectorInputBlock #define NTL_WordVectorInputBlock 50 #endif class WordVector { public: _ntl_ulong *rep; void RangeError(long i) const; WordVector(WordVector& x, INIT_TRANS_TYPE) { rep = x.rep; x.rep = 0; } WordVector() : rep(0) { } WordVector(INIT_SIZE_TYPE, long n) : rep(0) { DoSetLength(n); } WordVector(const WordVector& a) : rep(0) { *this = a; } WordVector& operator=(const WordVector& a); ~WordVector(); void kill(); void release() { if (MaxLength() > NTL_RELEASE_THRESH) kill(); } // this conditinally kills the vector, if its size is excessive void DoSetLength(long n); void SetLength(long n) { _ntl_ulong *x = rep; if (x && long(x[-2] >> 1) >= n && n >= 0) x[-1] = n; else DoSetLength(n); } void ZeroLength() { if (rep) rep[-1] = 0; } void SetMaxLength(long n); void QuickSetLength(long n) { rep[-1] = _ntl_ulong(n); } long length() const { return (!rep) ? 0 : long(rep[-1]); } long MaxLength() const { return (!rep) ? 0 : long(rep[-2] >> 1); } _ntl_ulong& operator[](long i) { NTL_WV_RANGE_CHECK_CODE return rep[i]; } const _ntl_ulong& operator[](long i) const { NTL_WV_RANGE_CHECK_CODE return rep[i]; } _ntl_ulong& operator()(long i) { return (*this)[i-1]; } const _ntl_ulong& operator()(long i) const { return (*this)[i-1]; } const _ntl_ulong* elts() const { return rep; } _ntl_ulong* elts() { return rep; } static void swap_impl(WordVector& x, WordVector& y); static void append_impl(WordVector& v, _ntl_ulong a); static void append_impl(WordVector& v, const WordVector& w); }; inline void swap(WordVector& x, WordVector& y) { WordVector::swap_impl(x, y); } inline void append(WordVector& v, _ntl_ulong a) { WordVector::append_impl(v, a); } inline void append(WordVector& v, const WordVector& w) { WordVector::append_impl(v, w); } NTL_SNS istream& operator>>(NTL_SNS istream&, WordVector&); NTL_SNS ostream& operator<<(NTL_SNS ostream&, const WordVector&); long operator==(const WordVector& a, const WordVector& b); long operator!=(const WordVector& a, const WordVector& b); long InnerProduct(const WordVector& a, const WordVector& b); void ShiftAdd(_ntl_ulong *cp, const _ntl_ulong* ap, long sa, long n); // cp = cp + (a << n) long WV_BlockConstructAlloc(WordVector& x, long d, long n); void WV_BlockConstructSet(WordVector& x, WordVector& y, long i); long WV_BlockDestroy(WordVector& x); long WV_storage(long d); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZ.h000644 000765 000024 00000126613 12377144457 015441 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZ__H #define NTL_ZZ__H /******************************************************** LIP INTERFACE The class ZZ implements signed, arbitrary length integers. **********************************************************/ #include #include #include NTL_OPEN_NNS class ZZ_p; // forward declaration class ZZX; class ZZ { public: typedef ZZ_p residue_type; typedef ZZX poly_type; NTL_verylong rep; // This is currently public for "emergency" situations // May be private in future versions. ZZ() : rep(0) { } // initial value is 0. explicit ZZ(long a) : rep(0) { *this = a; } ZZ(INIT_SIZE_TYPE, long k) : rep(0) // initial value is 0, but space is pre-allocated so that numbers // x with x.size() <= k can be stored without re-allocation. // Call with ZZ(INIT_SIZE, k). // The purpose for the INIT_SIZE argument is to prevent automatic // type conversion from long to ZZ, which would be tempting, but wrong. { NTL_zsetlength(&rep, k); } ZZ(const ZZ& a) : rep(0) // initial value is a. { NTL_zcopy(a.rep, &rep); } ZZ(INIT_VAL_TYPE, long a) : rep(0) { NTL_zintoz(a, &rep); } ZZ(INIT_VAL_TYPE, int a) : rep(0) { NTL_zintoz(a, &rep); } ZZ(INIT_VAL_TYPE, unsigned long a) : rep(0) { NTL_zuintoz(a, &rep); } ZZ(INIT_VAL_TYPE, unsigned int a) : rep(0) { NTL_zuintoz((unsigned long) a, &rep); } inline ZZ(INIT_VAL_TYPE, const char *); inline ZZ(INIT_VAL_TYPE, float); inline ZZ(INIT_VAL_TYPE, double); ZZ& operator=(const ZZ& a) { NTL_zcopy(a.rep, &rep); return *this; } ZZ& operator=(long a) { NTL_zintoz(a, &rep); return *this; } ~ZZ() { NTL_zfree(&rep); } void kill() // force the space held by this ZZ to be released. // The value then becomes 0. { NTL_zfree(&rep); } void SetSize(long k) // pre-allocates space for k-digit numbers (base 2^NTL_ZZ_NBITS); // does not change the value. { NTL_zsetlength(&rep, k); } long size() const // returns the number of (NTL_ZZ_NBIT-bit) digits of |a|; the size of 0 is 0. { return NTL_zsize(rep); } long null() const // test of rep is null { return !rep; } long MaxAlloc() const // returns max allocation request, possibly rounded up a bit... { return NTL_zmaxalloc(rep); } long SinglePrecision() const { return NTL_zsptest(rep); } // tests if less than NTL_SP_BOUND in absolute value long WideSinglePrecision() const { return NTL_zwsptest(rep); } // tests if less than NTL_WSP_BOUND in absolute value static const ZZ& zero(); ZZ(ZZ& x, INIT_TRANS_TYPE) { rep = x.rep; x.rep = 0; } // used to cheaply hand off memory management of return value, // without copying, assuming compiler implements the // "return value optimization". This is probably obsolete by // now, as modern compilers can and should optimize // the copy constructor in the situations where this is used. // This should only be used for simple, local variables // that are not be subject to special memory management. // mainly for internal consumption by ZZWatcher void release() { if (MaxAlloc() > NTL_RELEASE_THRESH) kill(); } }; class ZZWatcher { public: ZZ *watched; explicit ZZWatcher(ZZ *_watched) : watched(_watched) {} ~ZZWatcher() { watched->release(); } }; #define NTL_ZZRegister(x) NTL_THREAD_LOCAL static ZZ x; ZZWatcher _WATCHER__ ## x(&x) const ZZ& ZZ_expo(long e); inline void clear(ZZ& x) // x = 0 { NTL_zzero(&x.rep); } inline void set(ZZ& x) // x = 1 { NTL_zone(&x.rep); } inline void swap(ZZ& x, ZZ& y) // swap the values of x and y (swaps pointers only) { NTL_zswap(&x.rep, &y.rep); } inline double log(const ZZ& a) { return NTL_zlog(a.rep); } /********************************************************** Conversion routines. ***********************************************************/ inline void conv(ZZ& x, const ZZ& a) { x = a; } inline ZZ to_ZZ(const ZZ& a) { return a; } inline void conv(ZZ& x, long a) { NTL_zintoz(a, &x.rep); } inline ZZ to_ZZ(long a) { return ZZ(INIT_VAL, a); } inline void conv(ZZ& x, int a) { NTL_zintoz(long(a), &x.rep); } inline ZZ to_ZZ(int a) { return ZZ(INIT_VAL, a); } inline void conv(ZZ& x, unsigned long a) { NTL_zuintoz(a, &x.rep); } inline ZZ to_ZZ(unsigned long a) { return ZZ(INIT_VAL, a); } inline void conv(ZZ& x, unsigned int a) { NTL_zuintoz((unsigned long)(a), &x.rep); } inline ZZ to_ZZ(unsigned int a) { return ZZ(INIT_VAL, a); } void conv(ZZ& x, const char *s); inline ZZ::ZZ(INIT_VAL_TYPE, const char *s) : rep(0) { conv(*this, s); } inline ZZ to_ZZ(const char *s) { return ZZ(INIT_VAL, s); } inline void conv(ZZ& x, double a) { NTL_zdoubtoz(a, &x.rep); } inline ZZ::ZZ(INIT_VAL_TYPE, double a) : rep(0) { conv(*this, a); } inline ZZ to_ZZ(double a) { return ZZ(INIT_VAL, a); } inline void conv(ZZ& x, float a) { NTL_zdoubtoz(double(a), &x.rep); } inline ZZ::ZZ(INIT_VAL_TYPE, float a) : rep(0) { conv(*this, a); } inline ZZ to_ZZ(float a) { return ZZ(INIT_VAL, a); } inline void conv(long& x, const ZZ& a) { x = NTL_ztoint(a.rep); } inline long to_long(const ZZ& a) { return NTL_ztoint(a.rep); } inline void conv(int& x, const ZZ& a) { unsigned int res = (unsigned int) NTL_ztouint(a.rep); x = NTL_UINT_TO_INT(res); } inline int to_int(const ZZ& a) { unsigned int res = (unsigned int) NTL_ztouint(a.rep); return NTL_UINT_TO_INT(res); } inline void conv(unsigned long& x, const ZZ& a) { x = NTL_ztouint(a.rep); } inline unsigned long to_ulong(const ZZ& a) { return NTL_ztouint(a.rep); } inline void conv(unsigned int& x, const ZZ& a) { x = (unsigned int)(NTL_ztouint(a.rep)); } inline unsigned int to_uint(const ZZ& a) { return (unsigned int)(NTL_ztouint(a.rep)); } inline void conv(double& x, const ZZ& a) { x = NTL_zdoub(a.rep); } inline double to_double(const ZZ& a) { return NTL_zdoub(a.rep); } inline void conv(float& x, const ZZ& a) { x = float(NTL_zdoub(a.rep)); } inline float to_float(const ZZ& a) { return float(NTL_zdoub(a.rep)); } inline void ZZFromBytes(ZZ& x, const unsigned char *p, long n) { NTL_zfrombytes(&x.rep, p, n); } inline ZZ ZZFromBytes(const unsigned char *p, long n) { ZZ x; ZZFromBytes(x, p, n); NTL_OPT_RETURN(ZZ, x); } inline void BytesFromZZ(unsigned char *p, const ZZ& a, long n) { NTL_zbytesfromz(p, a.rep, n); } // ****** comparisons inline long sign(const ZZ& a) // returns the sign of a (-1, 0, or 1). { return NTL_zsign(a.rep); } inline long compare(const ZZ& a, const ZZ& b) // returns the sign of a-b (-1, 0, or 1). { return NTL_zcompare(a.rep, b.rep); } inline long IsZero(const ZZ& a) // zero test { return NTL_ziszero(a.rep); } inline long IsOne(const ZZ& a) { return NTL_zisone(a.rep); } // test for 1 /* the usual comparison operators */ inline long operator==(const ZZ& a, const ZZ& b) { return NTL_zcompare(a.rep, b.rep) == 0; } inline long operator!=(const ZZ& a, const ZZ& b) { return NTL_zcompare(a.rep, b.rep) != 0; } inline long operator<(const ZZ& a, const ZZ& b) { return NTL_zcompare(a.rep, b.rep) < 0; } inline long operator>(const ZZ& a, const ZZ& b) { return NTL_zcompare(a.rep, b.rep) > 0; } inline long operator<=(const ZZ& a, const ZZ& b) { return NTL_zcompare(a.rep, b.rep) <= 0; } inline long operator>=(const ZZ& a, const ZZ& b) { return NTL_zcompare(a.rep, b.rep) >= 0; } /* single-precision versions of the above */ inline long compare(const ZZ& a, long b) { return NTL_zscompare(a.rep, b); } inline long compare(long a, const ZZ& b) { return -NTL_zscompare(b.rep, a); } inline long operator==(const ZZ& a, long b) { return NTL_zscompare(a.rep, b) == 0; } inline long operator!=(const ZZ& a, long b) { return NTL_zscompare(a.rep, b) != 0; } inline long operator<(const ZZ& a, long b) { return NTL_zscompare(a.rep, b) < 0; } inline long operator>(const ZZ& a, long b) { return NTL_zscompare(a.rep, b) > 0; } inline long operator<=(const ZZ& a, long b) { return NTL_zscompare(a.rep, b) <= 0; } inline long operator>=(const ZZ& a, long b) { return NTL_zscompare(a.rep, b) >= 0; } inline long operator==(long a, const ZZ& b) { return b == a; } inline long operator!=(long a, const ZZ& b) { return b != a; } inline long operator<(long a, const ZZ& b) { return b > a; } inline long operator>(long a, const ZZ& b) { return b < a; } inline long operator<=(long a, const ZZ& b) { return b >= a; } inline long operator>=(long a, const ZZ& b) { return b <= a; } /************************************************** Addition **************************************************/ inline void add(ZZ& x, const ZZ& a, const ZZ& b) // x = a + b { NTL_zadd(a.rep, b.rep, &x.rep); } inline void sub(ZZ& x, const ZZ& a, const ZZ& b) // x = a - b { NTL_zsub(a.rep, b.rep, &x.rep); } inline void SubPos(ZZ& x, const ZZ& a, const ZZ& b) // x = a - b; assumes a >= b >= 0. { NTL_zsubpos(a.rep, b.rep, &x.rep); } inline void negate(ZZ& x, const ZZ& a) // x = -a { NTL_zcopy(a.rep, &x.rep); NTL_znegate(&x.rep); } inline void abs(ZZ& x, const ZZ& a) // x = |a| { NTL_zcopy(a.rep, &x.rep); NTL_zabs(&x.rep); } /* single-precision versions of the above */ inline void add(ZZ& x, const ZZ& a, long b) { NTL_zsadd(a.rep, b, &x.rep); } inline void add(ZZ& x, long a, const ZZ& b) { add(x, b, a); } void sub(ZZ& x, const ZZ& a, long b); void sub(ZZ& x, long a, const ZZ& b); /* operator/function notation */ inline ZZ operator+(const ZZ& a, const ZZ& b) { ZZ x; add(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator+(const ZZ& a, long b) { ZZ x; add(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator+(long a, const ZZ& b) { ZZ x; add(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator-(const ZZ& a, const ZZ& b) { ZZ x; sub(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator-(const ZZ& a, long b) { ZZ x; sub(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator-(long a, const ZZ& b) { ZZ x; sub(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator-(const ZZ& a) { ZZ x; negate(x, a); NTL_OPT_RETURN(ZZ, x); } inline ZZ abs(const ZZ& a) { ZZ x; abs(x, a); NTL_OPT_RETURN(ZZ, x); } /* op= notation */ inline ZZ& operator+=(ZZ& x, const ZZ& a) { add(x, x, a); return x; } inline ZZ& operator+=(ZZ& x, long a) { add(x, x, a); return x; } inline ZZ& operator-=(ZZ& x, const ZZ& a) { sub(x, x, a); return x; } inline ZZ& operator-=(ZZ& x, long a) { sub(x, x, a); return x; } /* inc/dec */ inline ZZ& operator++(ZZ& x) { add(x, x, 1); return x; } inline void operator++(ZZ& x, int) { add(x, x, 1); } inline ZZ& operator--(ZZ& x) { add(x, x, -1); return x; } inline void operator--(ZZ& x, int) { add(x, x, -1); } /******************************************************* Multiplication. ********************************************************/ inline void mul(ZZ& x, const ZZ& a, const ZZ& b) // x = a * b { NTL_zmul(a.rep, b.rep, &x.rep); } inline void sqr(ZZ& x, const ZZ& a) // x = a*a { NTL_zsq(a.rep, &x.rep); } inline ZZ sqr(const ZZ& a) { ZZ x; sqr(x, a); NTL_OPT_RETURN(ZZ, x); } /* single-precision versions */ inline void mul(ZZ& x, const ZZ& a, long b) { NTL_zsmul(a.rep, b, &x.rep); } inline void mul(ZZ& x, long a, const ZZ& b) { mul(x, b, a); } /* operator notation */ inline ZZ operator*(const ZZ& a, const ZZ& b) { ZZ x; mul(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator*(const ZZ& a, long b) { ZZ x; mul(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator*(long a, const ZZ& b) { ZZ x; mul(x, a, b); NTL_OPT_RETURN(ZZ, x); } /* op= notation */ inline ZZ& operator*=(ZZ& x, const ZZ& a) { mul(x, x, a); return x; } inline ZZ& operator*=(ZZ& x, long a) { mul(x, x, a); return x; } // x += a*b inline void MulAddTo(ZZ& x, const ZZ& a, long b) { NTL_zsaddmul(a.rep, b, &x.rep); } inline void MulAddTo(ZZ& x, const ZZ& a, const ZZ& b) { NTL_zaddmul(a.rep, b.rep, &x.rep); } // x -= a*b inline void MulSubFrom(ZZ& x, const ZZ& a, long b) { NTL_zssubmul(a.rep, b, &x.rep); } inline void MulSubFrom(ZZ& x, const ZZ& a, const ZZ& b) { NTL_zsubmul(a.rep, b.rep, &x.rep); } // Special routines for implementing CRT in ZZ_pX arithmetic inline void ZZ_p_crt_struct_init(void **crt_struct, long n, const ZZ& p, const long *primes) { NTL_crt_struct_init(crt_struct, n, p.rep, primes); } inline void ZZ_p_crt_struct_insert(void *crt_struct, long i, const ZZ& m) { NTL_crt_struct_insert(crt_struct, i, m.rep); } inline void ZZ_p_crt_struct_free(void *crt_struct) { NTL_crt_struct_free(crt_struct); } inline void ZZ_p_crt_struct_eval(void *crt_struct, ZZ& t, const long *a) { NTL_crt_struct_eval(crt_struct, &t.rep, a); } inline long ZZ_p_crt_struct_special(void *crt_struct) { return NTL_crt_struct_special(crt_struct); } // Special routines for fast remaindering inline void ZZ_p_rem_struct_init(void **rem_struct, long n, const ZZ& p, long *primes) { NTL_rem_struct_init(rem_struct, n, p.rep, primes); } inline void ZZ_p_rem_struct_free(void *rem_struct) { NTL_rem_struct_free(rem_struct); } inline void ZZ_p_rem_struct_eval(void *rem_struct, long *x, const ZZ& a) { NTL_rem_struct_eval(rem_struct, x, a.rep); } /******************************************************* Division *******************************************************/ inline void DivRem(ZZ& q, ZZ& r, const ZZ& a, const ZZ& b) // q = [a/b], r = a - b*q // |r| < |b|, and if r != 0, sign(r) = sign(b) { NTL_zdiv(a.rep, b.rep, &q.rep, &r.rep); } inline void div(ZZ& q, const ZZ& a, const ZZ& b) // q = a/b { NTL_zdiv(a.rep, b.rep, &q.rep, 0); } inline void rem(ZZ& r, const ZZ& a, const ZZ& b) // r = a%b { NTL_zmod(a.rep, b.rep, &r.rep); } inline void QuickRem(ZZ& r, const ZZ& b) // r = r%b // assumes b > 0 and r >=0 // division is performed in place and may cause r to be re-allocated. { NTL_zquickmod(&r.rep, b.rep); } long divide(ZZ& q, const ZZ& a, const ZZ& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0. long divide(const ZZ& a, const ZZ& b); // if b | a, returns 1; otherwise returns 0. /* non-standard single-precision versions */ inline long DivRem(ZZ& q, const ZZ& a, long b) { return NTL_zsdiv(a.rep, b, &q.rep); } inline long rem(const ZZ& a, long b) { return NTL_zsmod(a.rep, b); } /* single precision versions */ inline void div(ZZ& q, const ZZ& a, long b) { (void) NTL_zsdiv(a.rep, b, &q.rep); } long divide(ZZ& q, const ZZ& a, long b); // if b | a, sets q = a/b and returns 1; otherwise returns 0. long divide(const ZZ& a, long b); // if b | a, returns 1; otherwise returns 0. inline ZZ operator/(const ZZ& a, const ZZ& b) { ZZ x; div(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator/(const ZZ& a, long b) { ZZ x; div(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator%(const ZZ& a, const ZZ& b) { ZZ x; rem(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline long operator%(const ZZ& a, long b) { return rem(a, b); } inline ZZ& operator/=(ZZ& x, const ZZ& b) { div(x, x, b); return x; } inline ZZ& operator/=(ZZ& x, long b) { div(x, x, b); return x; } inline ZZ& operator%=(ZZ& x, const ZZ& b) { rem(x, x, b); return x; } /********************************************************** GCD's ***********************************************************/ inline void GCD(ZZ& d, const ZZ& a, const ZZ& b) // d = gcd(a, b) { NTL_zgcd(a.rep, b.rep, &d.rep); } inline ZZ GCD(const ZZ& a, const ZZ& b) { ZZ x; GCD(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline void XGCD(ZZ& d, ZZ& s, ZZ& t, const ZZ& a, const ZZ& b) // d = gcd(a, b) = a*s + b*t; { NTL_zexteucl(a.rep, &s.rep, b.rep, &t.rep, &d.rep); } // single-precision versions long GCD(long a, long b); void XGCD(long& d, long& s, long& t, long a, long b); /************************************************************ Bit Operations *************************************************************/ inline void LeftShift(ZZ& x, const ZZ& a, long k) // x = (a << k), k < 0 => RightShift { NTL_zlshift(a.rep, k, &x.rep); } inline ZZ LeftShift(const ZZ& a, long k) { ZZ x; LeftShift(x, a, k); NTL_OPT_RETURN(ZZ, x); } inline void RightShift(ZZ& x, const ZZ& a, long k) // x = (a >> k), k < 0 => LeftShift { NTL_zrshift(a.rep, k, &x.rep); } inline ZZ RightShift(const ZZ& a, long k) { ZZ x; RightShift(x, a, k); NTL_OPT_RETURN(ZZ, x); } #ifndef NTL_TRANSITION inline ZZ operator>>(const ZZ& a, long n) { ZZ x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator<<(const ZZ& a, long n) { ZZ x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ, x); } inline ZZ& operator<<=(ZZ& x, long n) { LeftShift(x, x, n); return x; } inline ZZ& operator>>=(ZZ& x, long n) { RightShift(x, x, n); return x; } #endif inline long MakeOdd(ZZ& x) // removes factors of 2 from x, returns the number of 2's removed // returns 0 if x == 0 { return NTL_zmakeodd(&x.rep); } inline long NumTwos(const ZZ& x) // returns max e such that 2^e divides x if x != 0, and returns 0 if x == 0. { return NTL_znumtwos(x.rep); } inline long IsOdd(const ZZ& a) // returns 1 if a is odd, otherwise 0 { return NTL_zodd(a.rep); } inline long NumBits(const ZZ& a) // returns the number of bits in |a|; NumBits(0) = 0 { return NTL_z2log(a.rep); } inline long bit(const ZZ& a, long k) // returns bit k of a, 0 being the low-order bit { return NTL_zbit(a.rep, k); } #ifndef NTL_GMP_LIP // only defined for the "classic" long integer package, for backward // compatability. inline long digit(const ZZ& a, long k) { return NTL_zdigit(a.rep, k); } #endif // returns k-th digit of |a|, 0 being the low-order digit. inline void trunc(ZZ& x, const ZZ& a, long k) // puts k low order bits of |a| into x { NTL_zlowbits(a.rep, k, &x.rep); } inline ZZ trunc_ZZ(const ZZ& a, long k) { ZZ x; trunc(x, a, k); NTL_OPT_RETURN(ZZ, x); } inline long trunc_long(const ZZ& a, long k) // returns k low order bits of |a| { return NTL_zslowbits(a.rep, k); } inline long SetBit(ZZ& x, long p) // returns original value of p-th bit of |a|, and replaces // p-th bit of a by 1 if it was zero; // error if p < 0 { return NTL_zsetbit(&x.rep, p); } inline long SwitchBit(ZZ& x, long p) // returns original value of p-th bit of |a|, and switches // the value of p-th bit of a; // p starts counting at 0; // error if p < 0 { return NTL_zswitchbit(&x.rep, p); } inline long weight(long a) // returns Hamming weight of |a| { return NTL_zweights(a); } inline long weight(const ZZ& a) // returns Hamming weight of |a| { return NTL_zweight(a.rep); } inline void bit_and(ZZ& x, const ZZ& a, const ZZ& b) // x = |a| AND |b| { NTL_zand(a.rep, b.rep, &x.rep); } void bit_and(ZZ& x, const ZZ& a, long b); inline void bit_and(ZZ& x, long a, const ZZ& b) { bit_and(x, b, a); } inline void bit_or(ZZ& x, const ZZ& a, const ZZ& b) // x = |a| OR |b| { NTL_zor(a.rep, b.rep, &x.rep); } void bit_or(ZZ& x, const ZZ& a, long b); inline void bit_or(ZZ& x, long a, const ZZ& b) { bit_or(x, b, a); } inline void bit_xor(ZZ& x, const ZZ& a, const ZZ& b) // x = |a| XOR |b| { NTL_zxor(a.rep, b.rep, &x.rep); } void bit_xor(ZZ& x, const ZZ& a, long b); inline void bit_xor(ZZ& x, long a, const ZZ& b) { bit_xor(x, b, a); } inline ZZ operator&(const ZZ& a, const ZZ& b) { ZZ x; bit_and(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator&(const ZZ& a, long b) { ZZ x; bit_and(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator&(long a, const ZZ& b) { ZZ x; bit_and(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator|(const ZZ& a, const ZZ& b) { ZZ x; bit_or(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator|(const ZZ& a, long b) { ZZ x; bit_or(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator|(long a, const ZZ& b) { ZZ x; bit_or(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator^(const ZZ& a, const ZZ& b) { ZZ x; bit_xor(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator^(const ZZ& a, long b) { ZZ x; bit_xor(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator^(long a, const ZZ& b) { ZZ x; bit_xor(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ& operator&=(ZZ& x, const ZZ& b) { bit_and(x, x, b); return x; } inline ZZ& operator&=(ZZ& x, long b) { bit_and(x, x, b); return x; } inline ZZ& operator|=(ZZ& x, const ZZ& b) { bit_or(x, x, b); return x; } inline ZZ& operator|=(ZZ& x, long b) { bit_or(x, x, b); return x; } inline ZZ& operator^=(ZZ& x, const ZZ& b) { bit_xor(x, x, b); return x; } inline ZZ& operator^=(ZZ& x, long b) { bit_xor(x, x, b); return x; } long NumBits(long a); long bit(long a, long k); long NextPowerOfTwo(long m); // returns least nonnegative k such that 2^k >= m inline long NumBytes(const ZZ& a) { return (NumBits(a)+7)/8; } inline long NumBytes(long a) { return (NumBits(a)+7)/8; } /*********************************************************** Some specialized routines ************************************************************/ inline long ZZ_BlockConstructAlloc(ZZ& x, long d, long n) { return NTL_zblock_construct_alloc(&x.rep, d, n); } inline void ZZ_BlockConstructSet(ZZ& x, ZZ& y, long i) { NTL_zblock_construct_set(x.rep, &y.rep, i); } inline long ZZ_BlockDestroy(ZZ& x) { return NTL_zblock_destroy(x.rep); } inline long ZZ_storage(long d) { return NTL_zblock_storage(d); } inline long ZZ_RoundCorrection(const ZZ& a, long k, long residual) { return NTL_zround_correction(a.rep, k, residual); } /*********************************************************** Psuedo-random Numbers ************************************************************/ void SetSeed(const ZZ& s); // initialize random number generator void RandomBnd(ZZ& x, const ZZ& n); // x = "random number" in the range 0..n-1, or 0 if n <= 0 inline ZZ RandomBnd(const ZZ& n) { ZZ x; RandomBnd(x, n); NTL_OPT_RETURN(ZZ, x); } void RandomLen(ZZ& x, long NumBits); // x = "random number" with precisely NumBits bits. inline ZZ RandomLen_ZZ(long NumBits) { ZZ x; RandomLen(x, NumBits); NTL_OPT_RETURN(ZZ, x); } void RandomBits(ZZ& x, long NumBits); // x = "random number", 0 <= x < 2^NumBits inline ZZ RandomBits_ZZ(long NumBits) { ZZ x; RandomBits(x, NumBits); NTL_OPT_RETURN(ZZ, x); } // single-precision version of the above long RandomBnd(long n); long RandomLen_long(long l); long RandomBits_long(long l); unsigned long RandomWord(); unsigned long RandomBits_ulong(long l); /********************************************************** Incremental Chinese Remaindering ***********************************************************/ long CRT(ZZ& a, ZZ& p, const ZZ& A, const ZZ& P); long CRT(ZZ& a, ZZ& p, long A, long P); // 0 <= A < P, (p, P) = 1; // computes b such that b = a mod p, b = A mod p, // and -p*P/2 < b <= p*P/2; // sets a = b, p = p*P, and returns 1 if a's value // has changed, otherwise 0 inline long CRTInRange(const ZZ& gg, const ZZ& aa) { return NTL_zcrtinrange(gg.rep, aa.rep); } // an auxilliary routine used by newer CRT routines to maintain // backward compatability. // test if a > 0 and -a/2 < g <= a/2 // this is "hand crafted" so as not too waste too much time // in the CRT routines. /********************************************************** Rational Reconstruction ***********************************************************/ inline long ReconstructRational(ZZ& a, ZZ& b, const ZZ& u, const ZZ& m, const ZZ& a_bound, const ZZ& b_bound) { return NTL_zxxratrecon(u.rep, m.rep, a_bound.rep, b_bound.rep, &a.rep, &b.rep); } /************************************************************ Primality Testing *************************************************************/ void GenPrime(ZZ& n, long l, long err = 80); inline ZZ GenPrime_ZZ(long l, long err = 80) { ZZ x; GenPrime(x, l, err); NTL_OPT_RETURN(ZZ, x); } long GenPrime_long(long l, long err = 80); // This generates a random prime n of length l so that the // probability of erroneously returning a composite is bounded by 2^(-err). void GenGermainPrime(ZZ& n, long l, long err = 80); inline ZZ GenGermainPrime_ZZ(long l, long err = 80) { ZZ x; GenGermainPrime(x, l, err); NTL_OPT_RETURN(ZZ, x); } long GenGermainPrime_long(long l, long err = 80); // This generates a random prime n of length l so that the long ProbPrime(const ZZ& n, long NumTrials = 10); // tests if n is prime; performs a little trial division, // followed by a single-precision MillerWitness test, followed by // up to NumTrials general MillerWitness tests. long MillerWitness(const ZZ& n, const ZZ& w); // Tests if w is a witness to primality a la Miller. // Assumption: n is odd and positive, 0 <= w < n. void RandomPrime(ZZ& n, long l, long NumTrials=10); // n = random l-bit prime inline ZZ RandomPrime_ZZ(long l, long NumTrials=10) { ZZ x; RandomPrime(x, l, NumTrials); NTL_OPT_RETURN(ZZ, x); } void NextPrime(ZZ& n, const ZZ& m, long NumTrials=10); // n = smallest prime >= m. inline ZZ NextPrime(const ZZ& m, long NumTrials=10) { ZZ x; NextPrime(x, m, NumTrials); NTL_OPT_RETURN(ZZ, x); } // single-precision versions long ProbPrime(long n, long NumTrials = 10); long RandomPrime_long(long l, long NumTrials=10); long NextPrime(long l, long NumTrials=10); /************************************************************ Exponentiation *************************************************************/ inline void power(ZZ& x, const ZZ& a, long e) { NTL_zexp(a.rep, e, &x.rep); } inline ZZ power(const ZZ& a, long e) { ZZ x; power(x, a, e); NTL_OPT_RETURN(ZZ, x); } inline void power(ZZ& x, long a, long e) { NTL_zexps(a, e, &x.rep); } inline ZZ power_ZZ(long a, long e) { ZZ x; power(x, a, e); NTL_OPT_RETURN(ZZ, x); } long power_long(long a, long e); void power2(ZZ& x, long e); inline ZZ power2_ZZ(long e) { ZZ x; power2(x, e); NTL_OPT_RETURN(ZZ, x); } /************************************************************* Square Roots **************************************************************/ inline void SqrRoot(ZZ& x, const ZZ& a) // x = [a^{1/2}], a >= 0 { NTL_zsqrt(a.rep, &x.rep); } inline ZZ SqrRoot(const ZZ& a) { ZZ x; SqrRoot(x, a); NTL_OPT_RETURN(ZZ, x); } inline long SqrRoot(long a) { return NTL_zsqrts(a); } // single-precision version /*************************************************************** Modular Arithmetic ***************************************************************/ // The following routines perform arithmetic mod n, n positive. // All args (other than exponents) are assumed to be in the range 0..n-1. inline void AddMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n) // x = (a+b)%n { NTL_zaddmod(a.rep, b.rep, n.rep, &x.rep); } inline ZZ AddMod(const ZZ& a, const ZZ& b, const ZZ& n) { ZZ x; AddMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void SubMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n) // x = (a-b)%n { NTL_zsubmod(a.rep, b.rep, n.rep, &x.rep); } inline ZZ SubMod(const ZZ& a, const ZZ& b, const ZZ& n) { ZZ x; SubMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void NegateMod(ZZ& x, const ZZ& a, const ZZ& n) // x = -a % n { NTL_zsubmod(0, a.rep, n.rep, &x.rep); } inline ZZ NegateMod(const ZZ& a, const ZZ& n) { ZZ x; NegateMod(x, a, n); NTL_OPT_RETURN(ZZ, x); } void AddMod(ZZ& x, const ZZ& a, long b, const ZZ& n); inline ZZ AddMod(const ZZ& a, long b, const ZZ& n) { ZZ x; AddMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void AddMod(ZZ& x, long a, const ZZ& b, const ZZ& n) { AddMod(x, b, a, n); } inline ZZ AddMod(long a, const ZZ& b, const ZZ& n) { ZZ x; AddMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } void SubMod(ZZ& x, const ZZ& a, long b, const ZZ& n); inline ZZ SubMod(const ZZ& a, long b, const ZZ& n) { ZZ x; SubMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } void SubMod(ZZ& x, long a, const ZZ& b, const ZZ& n); inline ZZ SubMod(long a, const ZZ& b, const ZZ& n) { ZZ x; SubMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void MulMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n) // x = (a*b)%n { NTL_zmulmod(a.rep, b.rep, n.rep, &x.rep); } inline ZZ MulMod(const ZZ& a, const ZZ& b, const ZZ& n) { ZZ x; MulMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void MulMod(ZZ& x, const ZZ& a, long b, const ZZ& n) // x = (a*b)%n { NTL_zsmulmod(a.rep, b, n.rep, &x.rep); } inline ZZ MulMod(const ZZ& a, long b, const ZZ& n) { ZZ x; MulMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void MulMod(ZZ& x, long a, const ZZ& b, const ZZ& n) { MulMod(x, b, a, n); } inline ZZ MulMod(long a, const ZZ& b, const ZZ& n) { ZZ x; MulMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void SqrMod(ZZ& x, const ZZ& a, const ZZ& n) // x = a^2 % n { NTL_zsqmod(a.rep, n.rep, &x.rep); } inline ZZ SqrMod(const ZZ& a, const ZZ& n) { ZZ x; SqrMod(x, a, n); NTL_OPT_RETURN(ZZ, x); } inline void InvMod(ZZ& x, const ZZ& a, const ZZ& n) // x = a^{-1} mod n, 0 <= x < n // error is raised occurs if inverse not defined { NTL_zinvmod(a.rep, n.rep, &x.rep); } inline ZZ InvMod(const ZZ& a, const ZZ& n) { ZZ x; InvMod(x, a, n); NTL_OPT_RETURN(ZZ, x); } inline long InvModStatus(ZZ& x, const ZZ& a, const ZZ& n) // if gcd(a,b) = 1, then ReturnValue = 0, x = a^{-1} mod n // otherwise, ReturnValue = 1, x = gcd(a, n) { return NTL_zinv(a.rep, n.rep, &x.rep); } inline void PowerMod(ZZ& x, const ZZ& a, const ZZ& e, const ZZ& n) { NTL_zpowermod(a.rep, e.rep, n.rep, &x.rep); } inline ZZ PowerMod(const ZZ& a, const ZZ& e, const ZZ& n) { ZZ x; PowerMod(x, a, e, n); NTL_OPT_RETURN(ZZ, x); } inline void PowerMod(ZZ& x, const ZZ& a, long e, const ZZ& n) { PowerMod(x, a, ZZ_expo(e), n); } inline ZZ PowerMod(const ZZ& a, long e, const ZZ& n) { ZZ x; PowerMod(x, a, e, n); NTL_OPT_RETURN(ZZ, x); } /************************************************************* Jacobi symbol and modular squre roots **************************************************************/ long Jacobi(const ZZ& a, const ZZ& n); // compute Jacobi symbol of a and n; // assumes 0 <= a < n, n odd void SqrRootMod(ZZ& x, const ZZ& a, const ZZ& n); // computes square root of a mod n; // assumes n is an odd prime, and that a is a square mod n inline ZZ SqrRootMod(const ZZ& a, const ZZ& n) { ZZ x; SqrRootMod(x, a, n); NTL_OPT_RETURN(ZZ, x); } /************************************************************* Small Prime Generation *************************************************************/ // primes are generated in sequence, starting at 2, // and up until (2*NTL_PRIME_BND+1)^2, which is less than NTL_SP_BOUND. #if (NTL_SP_NBITS > 30) #define NTL_PRIME_BND ((1L << 14) - 1) #else #define NTL_PRIME_BND ((1L << (NTL_SP_NBITS/2-1)) - 1) #endif class PrimeSeq { char *movesieve; Vec movesieve_mem; long pindex; long pshift; long exhausted; public: PrimeSeq(); long next(); // returns next prime in the sequence. // returns 0 if list of small primes is exhausted. void reset(long b); // resets generator so that the next prime in the sequence // is the smallest prime >= b. private: PrimeSeq(const PrimeSeq&); // disabled void operator=(const PrimeSeq&); // disabled // auxilliary routines void start(); void shift(long); }; /************************************************************** Input/Output ***************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ& a); /**************************************************************** Single-precision modular arithmetic *****************************************************************/ /* these routines implement single-precision modular arithmetic. If n is the modulus, all inputs should be in the range 0..n-1. The number n itself should be in the range 1..2^{NTL_SP_NBITS}-1. */ // I've declared these "static" so that the installation wizard // has more flexibility, without worrying about the (rather esoteric) // possibility of the linker complaining when the definitions // are inconsistent across severeal files. // Maybe an unnamed namespace would be better. // DIRT: undocumented feature: in all of these MulMod routines, // the first argument, a, need only be in the range // 0..2^{NTL_SP_NBITS}-1. This is assumption is used internally // in some NT routines...I've tried to mark all such uses with a // DIRT comment. I may decide to make this feature part // of the documented interface at some point in the future. static inline long AddMod(long a, long b, long n) // return (a+b)%n { long res = a + b; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING) && !defined(NTL_CLEAN_INT)) res -= n; res += (res >> (NTL_BITS_PER_LONG-1)) & n; return res; #elif (defined(NTL_AVOID_BRANCHING)) res -= n; res += (long) ((-(((unsigned long) res) >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n)); return res; #else if (res >= n) return res - n; else return res; #endif } static inline long SubMod(long a, long b, long n) // return (a-b)%n { long res = a - b; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING) && !defined(NTL_CLEAN_INT)) res += (res >> (NTL_BITS_PER_LONG-1)) & n; return res; #elif (defined(NTL_AVOID_BRANCHING)) res += (long) ((-(((unsigned long) res) >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n)); return res; #else if (res < 0) return res + n; else return res; #endif } static inline long NegateMod(long a, long n) { return SubMod(0, a, n); } #if (defined(NTL_CLEAN_INT) || (defined(NTL_AVOID_BRANCHING) && !NTL_ARITH_RIGHT_SHIFT)) #define NTL_CLEAN_SPMM #endif #if (!defined(NTL_CLEAN_SPMM)) /* * The default MulMod code. */ static inline long MulMod(long a, long b, long n) { long q, res; q = (long) ((((double) a) * ((double) b)) / ((double) n)); res = a*b - q*n; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING)) res += (res >> (NTL_BITS_PER_LONG-1)) & n; res -= n; res += (res >> (NTL_BITS_PER_LONG-1)) & n; #else if (res >= n) res -= n; else if (res < 0) res += n; #endif return res; } static inline long MulMod(long a, long b, long n, double ninv) { long q, res; q = (long) ((((double) a) * ((double) b)) * ninv); res = a*b - q*n; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING)) res += (res >> (NTL_BITS_PER_LONG-1)) & n; res -= n; res += (res >> (NTL_BITS_PER_LONG-1)) & n; #else if (res >= n) res -= n; else if (res < 0) res += n; #endif return res; } static inline long MulMod2(long a, long b, long n, double bninv) { long q, res; q = (long) (((double) a) * bninv); res = a*b - q*n; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING)) res += (res >> (NTL_BITS_PER_LONG-1)) & n; res -= n; res += (res >> (NTL_BITS_PER_LONG-1)) & n; #else if (res >= n) res -= n; else if (res < 0) res += n; #endif return res; } static inline long MulDivRem(long& qq, long a, long b, long n, double bninv) { long q, res; q = (long) (((double) a) * bninv); res = a*b - q*n; if (res >= n) { res -= n; q++; } else if (res < 0) { res += n; q--; } qq = q; return res; } #else /* * NTL_CLEAN_INT set: these versions of MulMod are completely portable, * assuming IEEE floating point arithmetic. */ static inline long MulMod(long a, long b, long n) { long q; unsigned long res; q = (long) ((((double) a) * ((double) b)) / ((double) n)); res = ((unsigned long) a)*((unsigned long) b) - ((unsigned long) q)*((unsigned long) n); #if (defined(NTL_AVOID_BRANCHING)) res += (-(res >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n); res -= ((unsigned long) n); res += (-(res >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n); #else if (res >> (NTL_BITS_PER_LONG-1)) res += ((unsigned long) n); else if (((long) res) >= n) res -= ((unsigned long) n); #endif return ((long) res); } static inline long MulMod(long a, long b, long n, double ninv) { long q; unsigned long res; q = (long) ((((double) a) * ((double) b)) * ninv); res = ((unsigned long) a)*((unsigned long) b) - ((unsigned long) q)*((unsigned long) n); #if (defined(NTL_AVOID_BRANCHING)) res += (-(res >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n); res -= ((unsigned long) n); res += (-(res >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n); #else if (res >> (NTL_BITS_PER_LONG-1)) res += ((unsigned long) n); else if (((long) res) >= n) res -= ((unsigned long) n); #endif return ((long) res); } static inline long MulMod2(long a, long b, long n, double bninv) { long q; unsigned long res; q = (long) (((double) a) * bninv); res = ((unsigned long) a)*((unsigned long) b) - ((unsigned long) q)*((unsigned long) n); #if (defined(NTL_AVOID_BRANCHING)) res += (-(res >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n); res -= ((unsigned long) n); res += (-(res >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n); #else if (res >> (NTL_BITS_PER_LONG-1)) res += ((unsigned long) n); else if (((long) res) >= n) res -= ((unsigned long) n); #endif return ((long) res); } static inline long MulDivRem(long& qq, long a, long b, long n, double bninv) { long q; unsigned long res; q = (long) (((double) a) * bninv); res = ((unsigned long) a)*((unsigned long) b) - ((unsigned long) q)*((unsigned long) n); if (res >> (NTL_BITS_PER_LONG-1)) { res += n; q--; } else if (((long) res) >= n) { res -= n; q++; } qq = q; return ((long) res); } #endif // These MulMod routines (with preconditioning) are sometimes // significantly faster. There are four possible implementations: // - default: uses MulMod2 above (lots of floating point) // - NTL_SPMM_ULL: uses unsigned long long (if possible) // - NTL_SPMM_ASM: uses assembly language (if possible) // - NTL_SPMM_UL: uses only unsigned long arithmetic (portable, slower). #if ((defined(NTL_SPMM_ULL) || defined(NTL_SPMM_ASM))) // unsigned long long / asm versions typedef unsigned long mulmod_precon_t; #define NTL_SPMM_VEC_T vec_ulong #if (!defined(NTL_CLEAN_SPMM)) static inline unsigned long PrepMulModPrecon(long b, long n, double ninv) { long q, r; q = (long) ( (((double) b) * NTL_SP_FBOUND) * ninv ); r = (b << NTL_SP_NBITS) - q*n; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING)) q += 1 + (r >> (NTL_BITS_PER_LONG-1)) + ((r - n) >> (NTL_BITS_PER_LONG-1)); #else if (r >= n) q++; else if (r < 0) q--; #endif return ((unsigned long) q) << (NTL_BITS_PER_LONG - NTL_SP_NBITS); } #else /* * clean int version -- this should be completely portable. */ static inline unsigned long PrepMulModPrecon(long b, long n, double ninv) { unsigned long q, r; q = (long) ( (((double) b) * NTL_SP_FBOUND) * ninv ); r = (((unsigned long) b) << NTL_SP_NBITS ) - q * ((unsigned long) n); #if (defined(NTL_AVOID_BRANCHING)) q += 1UL - (r >> (NTL_BITS_PER_LONG-1)) - ((r - ((unsigned long) n)) >> (NTL_BITS_PER_LONG-1)); #else if (r >> (NTL_BITS_PER_LONG-1)) q--; else if (((long) r) >= n) q++; #endif return q << (NTL_BITS_PER_LONG - NTL_SP_NBITS); } #endif #if (defined(NTL_SPMM_ULL)) static inline unsigned long MulHiUL(unsigned long a, unsigned long b) { return (((NTL_ULL_TYPE)(a)) * ((NTL_ULL_TYPE)(b))) >> NTL_BITS_PER_LONG; } #else // assmbly code versions #include #endif #if (!defined(NTL_CLEAN_SPMM)) static inline long MulModPrecon(long a, long b, long n, unsigned long bninv) { long q, res; q = (long) MulHiUL(a, bninv); res = a*b - q*n; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING)) res -= n; res += (res >> (NTL_BITS_PER_LONG-1)) & n; #else if (res >= n) res -= n; #endif return res; } #else static inline long MulModPrecon(long a, long b, long n, unsigned long bninv) { unsigned long q, res; q = MulHiUL(a, bninv); res = ((unsigned long) a)*((unsigned long) b) - q*((unsigned long) n); #if (defined(NTL_AVOID_BRANCHING)) res -= ((unsigned long) n); res += (-(res >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n); #else if (((long) res) >= n) res -= ((unsigned long) n); #endif return (long) res; } #endif #elif (defined(NTL_SPMM_UL)) // plain, portable (but slower) int version typedef long mulmod_precon_t; #define NTL_SPMM_VEC_T vec_long #if (!defined(NTL_CLEAN_SPMM)) static inline long PrepMulModPrecon(long b, long n, double ninv) { long q, r; q = (long) ( (((double) b) * NTL_SP_FBOUND) * ninv ); r = (b << NTL_SP_NBITS) - q*n; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING)) q += 1 + (r >> (NTL_BITS_PER_LONG-1)) + ((r - n) >> (NTL_BITS_PER_LONG-1)); #else if (r >= n) q++; else if (r < 0) q--; #endif return q; } #else static inline long PrepMulModPrecon(long b, long n, double ninv) { unsigned long q, r; q = (long) ( (((double) b) * NTL_SP_FBOUND) * ninv ); r = (((unsigned long) b) << NTL_SP_NBITS ) - q * ((unsigned long) n); #if (defined(NTL_AVOID_BRANCHING)) q += 1UL - (r >> (NTL_BITS_PER_LONG-1)) - ((r - ((unsigned long) n)) >> (NTL_BITS_PER_LONG-1)); #else if (r >> (NTL_BITS_PER_LONG-1)) q--; else if (((long) r) >= n) q++; #endif return ((long) q); } #endif static inline long MulHiSP(long b, long d) { unsigned long _b1 = b & ((1UL << (NTL_SP_NBITS/2)) - 1UL); unsigned long _d1 = d & ((1UL << (NTL_SP_NBITS/2)) - 1UL); unsigned long _bd,_b1d1,_m,_aa; unsigned long _ld = (d>>(NTL_SP_NBITS/2)); unsigned long _lb = (b>>(NTL_SP_NBITS/2)); _bd=_lb*_ld; _b1d1=_b1*_d1; _m=(_lb+_b1)*(_ld+_d1) - _bd - _b1d1; _aa = ( _b1d1+ ((_m&((1UL << (NTL_SP_NBITS/2)) - 1UL))<<(NTL_SP_NBITS/2))); return (_aa >> NTL_SP_NBITS) + _bd + (_m>>(NTL_SP_NBITS/2)); } #if (!defined(NTL_CLEAN_SPMM)) static inline long MulModPrecon(long a, long b, long n, long bninv) { long q, res; q = MulHiSP(a, bninv); res = a*b - q*n; #if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING)) res -= n; res += (res >> (NTL_BITS_PER_LONG-1)) & n; #else if (res >= n) res -= n; #endif return res; } #else static inline long MulModPrecon(long a, long b, long n, long bninv) { unsigned long q, res; q = MulHiSP(a, bninv); res = ((unsigned long) a)*((unsigned long) b) - q*((unsigned long) n); #if (defined(NTL_AVOID_BRANCHING)) res -= ((unsigned long) n); res += (-(res >> (NTL_BITS_PER_LONG-1))) & ((unsigned long) n); #else if (((long) res) >= n) res -= ((unsigned long) n); #endif return (long) res; } #endif #else // default, double version typedef double mulmod_precon_t; #define NTL_SPMM_VEC_T vec_double static inline double PrepMulModPrecon(long b, long n, double ninv) { return ((double) b) * ninv; } static inline long MulModPrecon(long a, long b, long n, double bninv) { return MulMod2(a, b, n, bninv); } #endif long InvMod(long a, long n); // computes a^{-1} mod n. Error is raised if undefined. long PowerMod(long a, long e, long n); // computes a^e mod n, e >= 0 inline void VectorMulModPrecon(long k, long *x, const long *a, long b, long n, mulmod_precon_t bninv) { for (long i = 0; i < k; i++) x[i] = MulModPrecon(a[i], b, n, bninv); } inline void VectorMulMod(long k, long *x, const long *a, long b, long n, double ninv) { mulmod_precon_t bninv; bninv = PrepMulModPrecon(b, n, ninv); VectorMulModPrecon(k, x, a, b, n, bninv); } inline void VectorMulMod(long k, long *x, const long *a, long b, long n) { double ninv = 1/((double) n); VectorMulMod(k, x, a, b, n, ninv); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZVec.h000644 000765 000024 00000002603 12377144457 016067 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZVec__H #define NTL_ZZVec__H #include NTL_OPEN_NNS /***************************************************************** The class ZZVec implements vectors of fixed-length ZZ's. You can allocate a vector of ZZ's of a specified length, where the maximum size of each ZZ is also specified. These parameters can be specified once, either with a constructor, or with SetSize. It is an error to try to re-size a vector, or store a ZZ that doesn't fit. The space can be released with "kill", and then you are free to call SetSize again. If you want more flexible---but less efficient---vectors, use vec_ZZ. *****************************************************************/ class ZZVec { private: ZZ* v; long len; long bsize; public: ZZVec& operator=(const ZZVec&); ZZVec(const ZZVec&); long length() const { return len; } long BaseSize() const { return bsize; } void SetSize(long n, long d); void kill(); ZZVec() { v = 0; len = 0; bsize = 0; } ZZVec(long n, long d) { v = 0; len = 0; bsize = 0; SetSize(n, d); } ~ZZVec() { kill(); }; ZZ* elts() { return v; } const ZZ* elts() const { return v; } ZZ& operator[](long i) { return v[i]; } const ZZ& operator[](long i) const { return v[i]; } static void swap_impl(ZZVec& x, ZZVec& y); }; inline void swap(ZZVec& x, ZZVec& y) { ZZVec::swap_impl(x, y); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZX.h000644 000765 000024 00000046271 12377144457 015572 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZX__H #define NTL_ZZX__H #include #include #include NTL_OPEN_NNS class ZZX { public: vec_ZZ rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ ZZX() { } // initial value 0 explicit ZZX(long a) { *this = a; } explicit ZZX(const ZZ& a) { *this = a; } ZZX(INIT_SIZE_TYPE, long n) // initial value 0, but space is pre-allocated for n coefficients { rep.SetMaxLength(n); } ZZX(const ZZX& a) : rep(a.rep) { } // initial value is a ZZX& operator=(const ZZX& a) { rep = a.rep; return *this; } ~ZZX() { } void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } typedef ZZ coeff_type; void SetLength(long n) { rep.SetLength(n); } ZZ& operator[](long i) { return rep[i]; } const ZZ& operator[](long i) const { return rep[i]; } static const ZZX& zero(); inline ZZX(long i, const ZZ& c); inline ZZX(long i, long c); inline ZZX(INIT_MONO_TYPE, long i, const ZZ& c); inline ZZX(INIT_MONO_TYPE, long i, long c); inline ZZX(INIT_MONO_TYPE, long i); inline ZZX& operator=(long a); inline ZZX& operator=(const ZZ& a); ZZX(ZZX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } }; /******************************************************************** input and output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, amd a_n not zero (the zero polynomial is [ ]). Leading zeroes are stripped. *********************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const ZZX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const ZZ& coeff(const ZZX& a, long i); // zero if i not in range void GetCoeff(ZZ& x, const ZZX& a, long i); // x = a[i], or zero if i not in range const ZZ& LeadCoeff(const ZZX& a); // zero if a == 0 const ZZ& ConstTerm(const ZZX& a); // zero if a == 0 void SetCoeff(ZZX& x, long i, const ZZ& a); // x[i] = a, error is raised if i < 0 void SetCoeff(ZZX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(ZZX& x, long i); // x[i] = 1, error is raised if i < 0 inline ZZX::ZZX(long i, const ZZ& a) { SetCoeff(*this, i, a); } inline ZZX::ZZX(long i, long a) { SetCoeff(*this, i, a); } inline ZZX::ZZX(INIT_MONO_TYPE, long i, const ZZ& a) { SetCoeff(*this, i, a); } inline ZZX::ZZX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline ZZX::ZZX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(ZZX& x); // x is set to the monomial X long IsX(const ZZX& a); // test if x = X inline void clear(ZZX& x) // x = 0 { x.rep.SetLength(0); } inline void set(ZZX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(ZZX& x, ZZX& y) // swap x & y (only pointers are swapped) { swap(x.rep, y.rep); } void trunc(ZZX& x, const ZZX& a, long m); // x = a % X^m inline ZZX trunc(const ZZX& a, long m) { ZZX x; trunc(x, a, m); NTL_OPT_RETURN(ZZX, x); } void RightShift(ZZX& x, const ZZX& a, long n); // x = a/X^n inline ZZX RightShift(const ZZX& a, long n) { ZZX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZX, x); } void LeftShift(ZZX& x, const ZZX& a, long n); // x = a*X^n inline ZZX LeftShift(const ZZX& a, long n) { ZZX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZX, x); } #ifndef NTL_TRANSITION inline ZZX operator>>(const ZZX& a, long n) { ZZX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator<<(const ZZX& a, long n) { ZZX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator<<=(ZZX& x, long n) { LeftShift(x, x, n); return x; } inline ZZX& operator>>=(ZZX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(ZZX& x, const ZZX& a); // x = derivative of a inline ZZX diff(const ZZX& a) { ZZX x; diff(x, a); NTL_OPT_RETURN(ZZX, x); } void InvTrunc(ZZX& x, const ZZX& a, long m); // computes x = a^{-1} % X^m // constant term must be non-zero inline ZZX InvTrunc(const ZZX& a, long m) { ZZX x; InvTrunc(x, a, m); NTL_OPT_RETURN(ZZX, x); } void MulTrunc(ZZX& x, const ZZX& a, const ZZX& b, long n); // x = a * b % X^n inline ZZX MulTrunc(const ZZX& a, const ZZX& b, long n) { ZZX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(ZZX, x); } void SqrTrunc(ZZX& x, const ZZX& a, long n); // x = a^2 % X^n inline ZZX SqrTrunc(const ZZX& a, long n) { ZZX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(ZZX, x); } void reverse(ZZX& c, const ZZX& a, long hi); inline ZZX reverse(const ZZX& a, long hi) { ZZX x; reverse(x, a, hi); NTL_OPT_RETURN(ZZX, x); } inline void reverse(ZZX& c, const ZZX& a) { reverse(c, a, deg(a)); } inline ZZX reverse(const ZZX& a) { ZZX x; reverse(x, a); NTL_OPT_RETURN(ZZX, x); } inline void VectorCopy(vec_ZZ& x, const ZZX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_ZZ VectorCopy(const ZZX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(ZZX& x, long a); inline ZZX to_ZZX(long a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } inline ZZX& ZZX::operator=(long a) { conv(*this, a); return *this; } void conv(ZZX& x, const ZZ& a); inline ZZX to_ZZX(const ZZ& a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } inline ZZX& ZZX::operator=(const ZZ& a) { conv(*this, a); return *this; } void conv(ZZX& x, const vec_ZZ& a); inline ZZX to_ZZX(const vec_ZZ& a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } void conv(zz_pX& x, const ZZX& a); inline zz_pX to_zz_pX(const ZZX& a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } void conv(ZZ_pX& x, const ZZX& a); inline ZZ_pX to_ZZ_pX(const ZZX& a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } void conv(ZZX& x, const ZZ_pX& a); inline ZZX to_ZZX(const ZZ_pX& a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } void conv(ZZX& x, const zz_pX& a); inline ZZX to_ZZX(const zz_pX& a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } /* additional legacy conversions for v6 conversion regime */ inline void conv(ZZX& x, const ZZX& a) { x = a; } inline void conv(vec_ZZ& x, const ZZX& a) { x = a.rep; } /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const ZZX& a); long IsOne(const ZZX& a); long operator==(const ZZX& a, const ZZX& b); inline long operator!=(const ZZX& a, const ZZX& b) { return !(a == b); } long operator==(const ZZX& a, const ZZ& b); long operator==(const ZZX& a, long b); inline long operator==(const ZZ& a, const ZZX& b) { return b == a; } inline long operator==(long a, const ZZX& b) { return b == a; } inline long operator!=(const ZZX& a, const ZZ& b) { return !(a == b); } inline long operator!=(const ZZX& a, long b) { return !(a == b); } inline long operator!=(const ZZ& a, const ZZX& b) { return !(a == b); } inline long operator!=(long a, const ZZX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(ZZX& x, const ZZX& a, const ZZX& b); // x = a + b void sub(ZZX& x, const ZZX& a, const ZZX& b); // x = a - b void negate(ZZX& x, const ZZX& a); // x = -a // scalar versions void add(ZZX & x, const ZZX& a, const ZZ& b); // x = a + b void add(ZZX& x, const ZZX& a, long b); inline void add(ZZX& x, const ZZ& a, const ZZX& b) { add(x, b, a); } inline void add(ZZX& x, long a, const ZZX& b) { add(x, b, a); } void sub(ZZX & x, const ZZX& a, const ZZ& b); // x = a - b void sub(ZZX& x, const ZZX& a, long b); void sub(ZZX& x, const ZZ& a, const ZZX& b); void sub(ZZX& x, long a, const ZZX& b); inline ZZX operator+(const ZZX& a, const ZZX& b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator+(const ZZX& a, const ZZ& b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator+(const ZZX& a, long b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator+(const ZZ& a, const ZZX& b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator+(long a, const ZZX& b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(const ZZX& a, const ZZX& b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(const ZZX& a, const ZZ& b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(const ZZX& a, long b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(const ZZ& a, const ZZX& b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(long a, const ZZX& b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator+=(ZZX& x, const ZZX& b) { add(x, x, b); return x; } inline ZZX& operator+=(ZZX& x, const ZZ& b) { add(x, x, b); return x; } inline ZZX& operator+=(ZZX& x, long b) { add(x, x, b); return x; } inline ZZX& operator-=(ZZX& x, const ZZX& b) { sub(x, x, b); return x; } inline ZZX& operator-=(ZZX& x, const ZZ& b) { sub(x, x, b); return x; } inline ZZX& operator-=(ZZX& x, long b) { sub(x, x, b); return x; } inline ZZX operator-(const ZZX& a) { ZZX x; negate(x, a); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator++(ZZX& x) { add(x, x, 1); return x; } inline void operator++(ZZX& x, int) { add(x, x, 1); } inline ZZX& operator--(ZZX& x) { sub(x, x, 1); return x; } inline void operator--(ZZX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(ZZX& x, const ZZX& a, const ZZX& b); // x = a * b void sqr(ZZX& x, const ZZX& a); inline ZZX sqr(const ZZX& a) { ZZX x; sqr(x, a); NTL_OPT_RETURN(ZZX, x); } // x = a^2 void PlainMul(ZZX& x, const ZZX& a, const ZZX& b); void PlainSqr(ZZX& x, const ZZX& a); void KarMul(ZZX& x, const ZZX& a, const ZZX& b); void KarSqr(ZZX& x, const ZZX& a); void HomMul(ZZX& x, const ZZX& a, const ZZX& b); void HomSqr(ZZX& x, const ZZX& a); void SSMul(ZZX& x, const ZZX& a, const ZZX& b); void SSSqr(ZZX& x, const ZZX& a); double SSRatio(long na, long maxa, long nb, long maxb); void mul(ZZX & x, const ZZX& a, const ZZ& b); void mul(ZZX& x, const ZZX& a, long b); inline void mul(ZZX& x, const ZZ& a, const ZZX& b) { mul(x, b, a); } inline void mul(ZZX& x, long a, const ZZX& b) { mul(x, b, a); } inline ZZX operator*(const ZZX& a, const ZZX& b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator*(const ZZX& a, const ZZ& b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator*(const ZZX& a, long b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator*(const ZZ& a, const ZZX& b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator*(long a, const ZZX& b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator*=(ZZX& x, const ZZX& b) { mul(x, x, b); return x; } inline ZZX& operator*=(ZZX& x, const ZZ& b) { mul(x, x, b); return x; } inline ZZX& operator*=(ZZX& x, long b) { mul(x, x, b); return x; } /************************************************************* Division **************************************************************/ // "plain" versions void PlainPseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); void PlainPseudoDiv(ZZX& q, const ZZX& a, const ZZX& b); void PlainPseudoRem(ZZX& r, const ZZX& a, const ZZX& b); // "homomorphic imaging" versions void HomPseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); void HomPseudoDiv(ZZX& q, const ZZX& a, const ZZX& b); void HomPseudoRem(ZZX& r, const ZZX& a, const ZZX& b); inline void PseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b) // performs pseudo-division: computes q and r // with deg(r) < deg(b), and LeadCoeff(b)^(deg(a)-deg(b)+1) a = b q + r. // current implementation always defaults to "plain" { PlainPseudoDivRem(q, r, a, b); } inline void PseudoDiv(ZZX& q, const ZZX& a, const ZZX& b) { PlainPseudoDiv(q, a, b); } inline void PseudoRem(ZZX& r, const ZZX& a, const ZZX& b) { PlainPseudoRem(r, a, b); } inline ZZX PseudoDiv(const ZZX& a, const ZZX& b) { ZZX x; PseudoDiv(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX PseudoRem(const ZZX& a, const ZZX& b) { ZZX x; PseudoRem(x, a, b); NTL_OPT_RETURN(ZZX, x); } #ifndef NTL_TRANSITION void DivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); void div(ZZX& q, const ZZX& a, const ZZX& b); void div(ZZX& q, const ZZX& a, const ZZ& b); void div(ZZX& q, const ZZX& a, long b); void rem(ZZX& r, const ZZX& a, const ZZX& b); inline ZZX operator/(const ZZX& a, const ZZX& b) { ZZX x; div(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator/(const ZZX& a, const ZZ& b) { ZZX x; div(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator/(const ZZX& a, long b) { ZZX x; div(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator/=(ZZX& x, const ZZ& b) { div(x, x, b); return x; } inline ZZX& operator/=(ZZX& x, long b) { div(x, x, b); return x; } inline ZZX& operator/=(ZZX& x, const ZZX& b) { div(x, x, b); return x; } inline ZZX operator%(const ZZX& a, const ZZX& b) { ZZX x; rem(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator%=(ZZX& x, const ZZX& b) { rem(x, x, b); return x; } #endif // Modular arithemtic---f must be monic, and other args // must have degree less than that of f void MulMod(ZZX& x, const ZZX& a, const ZZX& b, const ZZX& f); inline ZZX MulMod(const ZZX& a, const ZZX& b, const ZZX& f) { ZZX x; MulMod(x, a, b, f); NTL_OPT_RETURN(ZZX, x); } void SqrMod(ZZX& x, const ZZX& a, const ZZX& f); inline ZZX SqrMod(const ZZX& a, const ZZX& f) { ZZX x; SqrMod(x, a, f); NTL_OPT_RETURN(ZZX, x); } void MulByXMod(ZZX& x, const ZZX& a, const ZZX& f); inline ZZX MulByXMod(const ZZX& a, const ZZX& f) { ZZX x; MulByXMod(x, a, f); NTL_OPT_RETURN(ZZX, x); } // these always use "plain" division long PlainDivide(ZZX& q, const ZZX& a, const ZZX& b); long PlainDivide(const ZZX& a, const ZZX& b); // these always use "homomorphic imaging" long HomDivide(ZZX& q, const ZZX& a, const ZZX& b); long HomDivide(const ZZX& a, const ZZX& b); long divide(ZZX& q, const ZZX& a, const ZZX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZX& a, const ZZX& b); long divide(ZZX& q, const ZZX& a, const ZZ& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZX& a, const ZZ& b); // if b | a, returns 1; otherwise returns 0 //single-precision versions long divide(ZZX& q, const ZZX& a, long b); long divide(const ZZX& a, long b); void content(ZZ& d, const ZZX& f); // d = content of f, sign(d) == sign(LeadCoeff(f)) inline ZZ content(const ZZX& f) { ZZ x; content(x, f); NTL_OPT_RETURN(ZZ, x); } void PrimitivePart(ZZX& pp, const ZZX& f); // pp = primitive part of f, LeadCoeff(pp) >= 0 inline ZZX PrimitivePart(const ZZX& f) { ZZX x; PrimitivePart(x, f); NTL_OPT_RETURN(ZZX, x); } void GCD(ZZX& d, const ZZX& a, const ZZX& b); // d = gcd(a, b), LeadCoeff(d) >= 0 inline ZZX GCD(const ZZX& a, const ZZX& b) { ZZX x; GCD(x, a, b); NTL_OPT_RETURN(ZZX, x); } long MaxBits(const ZZX& f); // returns max NumBits of coefficients of f long CharPolyBound(const ZZX& a, const ZZX& f); /*************************************************************** traces, norms, resultants ****************************************************************/ void TraceVec(vec_ZZ& S, const ZZX& f); // S[i] = Trace(X^i mod f), for i = 0..deg(f)-1. // f must be a monic polynomial. inline vec_ZZ TraceVec(const ZZX& f) { vec_ZZ x; TraceVec(x, f); NTL_OPT_RETURN(vec_ZZ, x); } void TraceMod(ZZ& res, const ZZX& a, const ZZX& f); inline ZZ TraceMod(const ZZX& a, const ZZX& f) { ZZ x; TraceMod(x, a, f); NTL_OPT_RETURN(ZZ, x); } // res = trace of (a mod f) // f must be monic void resultant(ZZ& res, const ZZX& a, const ZZX& b, long deterministic=0); inline ZZ resultant(const ZZX& a, const ZZX& b, long deterministic=0) { ZZ x; resultant(x, a, b, deterministic); NTL_OPT_RETURN(ZZ, x); } // res = resultant of a and b // if !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void NormMod(ZZ& res, const ZZX& a, const ZZX& f, long deterministic=0); inline ZZ NormMod(const ZZX& a, const ZZX& f, long deterministic=0) { ZZ x; NormMod(x, a, f, deterministic); NTL_OPT_RETURN(ZZ, x); } // res = norm of (a mod f) // f must be monic // if !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void discriminant(ZZ& d, const ZZX& a, long deterministic=0); inline ZZ discriminant(const ZZX& a, long deterministic=0) { ZZ x; discriminant(x, a, deterministic); NTL_OPT_RETURN(ZZ, x); } // d = discriminant of a // = (-1)^{m(m-1)/2} resultant(a, a')/lc(a), // where m = deg(a) // if !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void CharPolyMod(ZZX& g, const ZZX& a, const ZZX& f, long deterministic=0); inline ZZX CharPolyMod(const ZZX& a, const ZZX& f, long deterministic=0) { ZZX x; CharPolyMod(x, a, f, deterministic); NTL_OPT_RETURN(ZZX, x); } // g = char poly of (a mod f) // f must be monic // if !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void MinPolyMod(ZZX& g, const ZZX& a, const ZZX& f); inline ZZX MinPolyMod(const ZZX& a, const ZZX& f) { ZZX x; MinPolyMod(x, a, f); NTL_OPT_RETURN(ZZX, x); } // g = min poly of (a mod f) // f must be monic // may use a probabilistic strategy that errs with // probability no more than 2^{-80} void XGCD(ZZ& r, ZZX& s, ZZX& t, const ZZX& a, const ZZX& b, long deterministic=0); // r = resultant of a and b; // if r != 0, then computes s and t such that: // a*s + b*t = r; // otherwise s and t not affected. // if !deterministic, then resultant computation may use a randomized strategy // that errs with probability no more than 2^{-80}. /****************************************************** Incremental Chinese Remaindering *******************************************************/ long CRT(ZZX& a, ZZ& prod, const zz_pX& A); long CRT(ZZX& a, ZZ& prod, const ZZ_pX& A); // If p is the current modulus with (p, prod) = 1; // Computes b such that b = a mod prod and b = A mod p, // with coefficients in the interval (-p*prod/2, p*prod/2]; // Sets a = b, prod = p*prod, and returns 1 if a's value changed. typedef Vec vec_ZZX; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZXFactoring.h000644 000765 000024 00000003404 12377144457 017416 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZXFactoring__H #define NTL_ZZXFactoring__H #include #include NTL_OPEN_NNS void mul(ZZX& x, const vec_pair_ZZX_long& a); inline ZZX mul(const vec_pair_ZZX_long& v) { ZZX x; mul(x, v); return x; } void SquareFreeDecomp(vec_pair_ZZX_long& u, const ZZX& f); inline vec_pair_ZZX_long SquareFreeDecomp(const ZZX& f) { vec_pair_ZZX_long x; SquareFreeDecomp(x, f); return x; } // input is primitive, with positive leading coefficient void MultiLift(vec_ZZX& A, const vec_zz_pX& a, const ZZX& f, long e, long verbose=0); // Using current value p of zz_p::modulus(), this lifts // the square-free factorization a mod p of f to a factorization // A mod p^e of f. // It is required that f and all the polynomials in a are monic. void SFFactor(vec_ZZX& factors, const ZZX& f, long verbose=0, long bnd=0); inline vec_ZZX SFFactor(const ZZX& f, long verbose=0, long bnd=0) { vec_ZZX x; SFFactor(x, f, verbose, bnd); return x; } // input f is primitive and square-free, with positive leading // coefficient. // bnd, if not zero, indicates that // f divides a polynomial h whose Euclidean norm // is bounded by 2^{bnd} in absolute value. NTL_THREAD_LOCAL extern long ZZXFac_MaxPrune; NTL_THREAD_LOCAL extern long ZZXFac_InitNumPrimes; NTL_THREAD_LOCAL extern long ZZXFac_MaxNumPrimes; NTL_THREAD_LOCAL extern long ZZXFac_PowerHack; NTL_THREAD_LOCAL extern long ZZXFac_van_Hoeij; void factor(ZZ& c, vec_pair_ZZX_long& factors, const ZZX& f, long verbose=0, long bnd=0); // input f is is an arbitrary polynomial. // c is the content of f, and factors is the factorization // of its primitive part. // bnd is as in SFFactor. NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZ_p.h000644 000765 000024 00000026627 12377144457 015764 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZ_p__H #define NTL_ZZ_p__H #include #include NTL_OPEN_NNS // ZZ_p representation: each ZZ_p is represented by a ZZ in the range 0..p-1. // The constructor for a ZZ_p pre-allocates space for the underlying ZZ, // and initializes it to zero. const int MAX_ZZ_p_TEMPS = 16; class ZZ_p; class ZZ_pInfoT { private: ZZ_pInfoT(); // disabled ZZ_pInfoT(const ZZ_pInfoT&); // disabled void operator=(const ZZ_pInfoT&); // disabled public: ZZ_pInfoT(const ZZ& NewP); ~ZZ_pInfoT(); long ref_count; // reference count for gargabge collection ZZ p; // the modulus long size; // p.size() long ExtendedModulusSize; // FIXME: in a thread safe version, this lazy initialization // needs to be in some kind of mutex // the following implement a "lazy" initialization strategy long initialized; // flag if initialization really was done void init(); void check() { if (!initialized) init(); } long NumPrimes; long MaxRoot; long QuickCRT; ZZ MinusMModP; // -M mod p, M = product of primes void *crt_struct; void *rem_struct; // the following arrays are indexed 0..NumPrimes-1 // q = FFTPrime[i] double *x; // u/q, where u = (M/q)^{-1} mod q long *u; // u, as above }; NTL_THREAD_LOCAL extern ZZ_pInfoT *ZZ_pInfo; // info for current modulus, initially null class ZZ_pContext { private: ZZ_pInfoT *ptr; public: void save(); void restore() const; ZZ_pContext() { ptr = 0; } explicit ZZ_pContext(const ZZ& p); ZZ_pContext(const ZZ_pContext&); ZZ_pContext& operator=(const ZZ_pContext&); ~ZZ_pContext(); }; class ZZ_pBak { private: long MustRestore; ZZ_pInfoT *ptr; ZZ_pBak(const ZZ_pBak&); // disabled void operator=(const ZZ_pBak&); // disabled public: void save(); void restore(); ZZ_pBak() { MustRestore = 0; ptr = 0; } ~ZZ_pBak(); }; class ZZ_pPush { private: ZZ_pBak bak; ZZ_pPush(const ZZ_pPush&); // disabled void operator=(const ZZ_pPush&); // disabled public: ZZ_pPush() { bak.save(); } explicit ZZ_pPush(const ZZ_pContext& context) { bak.save(); context.restore(); } explicit ZZ_pPush(const ZZ& p) { bak.save(); ZZ_pContext c(p); c.restore(); } }; // FIXME: in a thread safe version, these reference counted // pointers should be replaced by shared_ptr's (which are // thread safe) class ZZ_pX; // forward declaration class ZZ_p { public: typedef ZZ rep_type; typedef ZZ_pContext context_type; typedef ZZ_pBak bak_type; typedef ZZ_pPush push_type; typedef ZZ_pX poly_type; ZZ _ZZ_p__rep; static void init(const ZZ&); typedef void (*DivHandlerPtr)(const ZZ_p& a); // error-handler for division NTL_THREAD_LOCAL static DivHandlerPtr DivHandler; // ****** constructors and assignment ZZ_p() { } // NO_ALLOC explicit ZZ_p(long a) { *this = a; } ZZ_p(const ZZ_p& a) { _ZZ_p__rep = a._ZZ_p__rep; } // NO_ALLOC ZZ_p(INIT_NO_ALLOC_TYPE) { } // allocates no space ZZ_p(INIT_ALLOC_TYPE) { _ZZ_p__rep.SetSize(ZZ_pInfo->size); } // allocates space ~ZZ_p() { } ZZ_p& operator=(const ZZ_p& a) { _ZZ_p__rep = a._ZZ_p__rep; return *this; } inline ZZ_p& operator=(long a); // You can always access the _ZZ_p__representation directly...if you dare. ZZ& LoopHole() { return _ZZ_p__rep; } ZZ_p(ZZ_p& x, INIT_TRANS_TYPE) : _ZZ_p__rep(x._ZZ_p__rep, INIT_TRANS) { } static const ZZ& modulus() { return ZZ_pInfo->p; } static long ModulusSize() { return ZZ_pInfo->size; } static long storage() { return ZZ_storage(ZZ_pInfo->size); } static const ZZ_p& zero(); ZZ_p(INIT_VAL_TYPE, const ZZ& a); ZZ_p(INIT_VAL_TYPE, long a); void allocate() { long sz = ZZ_pInfo->size; if (_ZZ_p__rep.MaxAlloc() < sz) _ZZ_p__rep.SetSize(sz); } // mainly for internal consumption by the ZZ_pWatcher class below void release() { _ZZ_p__rep.release(); } }; // read-only access to _ZZ_p__representation inline const ZZ& rep(const ZZ_p& a) { return a._ZZ_p__rep; } // ****** conversion inline void conv(ZZ_p& x, const ZZ& a) { rem(x._ZZ_p__rep, a, ZZ_p::modulus()); } inline ZZ_p to_ZZ_p(const ZZ& a) { return ZZ_p(INIT_VAL, a); } void conv(ZZ_p& x, long a); inline ZZ_p to_ZZ_p(long a) { return ZZ_p(INIT_VAL, a); } // ****** some basics inline void clear(ZZ_p& x) // x = 0 { clear(x._ZZ_p__rep); } inline void set(ZZ_p& x) // x = 1 { set(x._ZZ_p__rep); } inline void swap(ZZ_p& x, ZZ_p& y) // swap x and y { swap(x._ZZ_p__rep, y._ZZ_p__rep); } // ****** addition inline void add(ZZ_p& x, const ZZ_p& a, const ZZ_p& b) // x = a + b { AddMod(x._ZZ_p__rep, a._ZZ_p__rep, b._ZZ_p__rep, ZZ_p::modulus()); } inline void sub(ZZ_p& x, const ZZ_p& a, const ZZ_p& b) // x = a - b { SubMod(x._ZZ_p__rep, a._ZZ_p__rep, b._ZZ_p__rep, ZZ_p::modulus()); } inline void negate(ZZ_p& x, const ZZ_p& a) // x = -a { NegateMod(x._ZZ_p__rep, a._ZZ_p__rep, ZZ_p::modulus()); } // scalar versions void add(ZZ_p& x, const ZZ_p& a, long b); inline void add(ZZ_p& x, long a, const ZZ_p& b) { add(x, b, a); } void sub(ZZ_p& x, const ZZ_p& a, long b); void sub(ZZ_p& x, long a, const ZZ_p& b); // ****** multiplication inline void mul(ZZ_p& x, const ZZ_p& a, const ZZ_p& b) // x = a*b { MulMod(x._ZZ_p__rep, a._ZZ_p__rep, b._ZZ_p__rep, ZZ_p::modulus()); } inline void sqr(ZZ_p& x, const ZZ_p& a) // x = a^2 { SqrMod(x._ZZ_p__rep, a._ZZ_p__rep, ZZ_p::modulus()); } inline ZZ_p sqr(const ZZ_p& a) { ZZ_p x; sqr(x, a); NTL_OPT_RETURN(ZZ_p, x); } // scalar versions void mul(ZZ_p& x, const ZZ_p& a, long b); inline void mul(ZZ_p& x, long a, const ZZ_p& b) { mul(x, b, a); } // ****** division void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a/b // If b != 0 & b not invertible & DivHandler != 0, // then DivHandler will be called with the offending b. // In this case, of course, p is not really prime, and one // can factor p by taking a gcd with rep(b). // Otherwise, if b is not invertible, an error occurs. void inv(ZZ_p& x, const ZZ_p& a); // x = 1/a // Error handling is the same as above. inline ZZ_p inv(const ZZ_p& a) { ZZ_p x; inv(x, a); NTL_OPT_RETURN(ZZ_p, x); } void div(ZZ_p& x, const ZZ_p& a, long b); void div(ZZ_p& x, long a, const ZZ_p& b); // operator notation: inline ZZ_p operator+(const ZZ_p& a, const ZZ_p& b) { ZZ_p x; add(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator+(const ZZ_p& a, long b) { ZZ_p x; add(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator+(long a, const ZZ_p& b) { ZZ_p x; add(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator+=(ZZ_p& x, const ZZ_p& b) { add(x, x, b); return x; } inline ZZ_p& operator+=(ZZ_p& x, long b) { add(x, x, b); return x; } inline ZZ_p operator-(const ZZ_p& a, const ZZ_p& b) { ZZ_p x; sub(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator-(const ZZ_p& a, long b) { ZZ_p x; sub(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator-(long a, const ZZ_p& b) { ZZ_p x; sub(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator-=(ZZ_p& x, const ZZ_p& b) { sub(x, x, b); return x; } inline ZZ_p& operator-=(ZZ_p& x, long b) { sub(x, x, b); return x; } inline ZZ_p operator*(const ZZ_p& a, const ZZ_p& b) { ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator*(const ZZ_p& a, long b) { ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator*(long a, const ZZ_p& b) { ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator*=(ZZ_p& x, const ZZ_p& b) { mul(x, x, b); return x; } inline ZZ_p& operator*=(ZZ_p& x, long b) { mul(x, x, b); return x; } inline ZZ_p operator/(const ZZ_p& a, const ZZ_p& b) { ZZ_p x; div(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator/(const ZZ_p& a, long b) { ZZ_p x; div(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator/(long a, const ZZ_p& b) { ZZ_p x; div(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator/=(ZZ_p& x, const ZZ_p& b) { div(x, x, b); return x; } inline ZZ_p& operator/=(ZZ_p& x, long b) { div(x, x, b); return x; } inline ZZ_p operator-(const ZZ_p& a) { ZZ_p x; negate(x, a); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator++(ZZ_p& x) { add(x, x, 1); return x; } inline void operator++(ZZ_p& x, int) { add(x, x, 1); } inline ZZ_p& operator--(ZZ_p& x) { sub(x, x, 1); return x; } inline void operator--(ZZ_p& x, int) { sub(x, x, 1); } // ****** exponentiation inline void power(ZZ_p& x, const ZZ_p& a, const ZZ& e) { PowerMod(x._ZZ_p__rep, a._ZZ_p__rep, e, ZZ_p::modulus()); } inline ZZ_p power(const ZZ_p& a, const ZZ& e) { ZZ_p x; power(x, a, e); NTL_OPT_RETURN(ZZ_p, x); } inline void power(ZZ_p& x, const ZZ_p& a, long e) { PowerMod(x._ZZ_p__rep, a._ZZ_p__rep, e, ZZ_p::modulus()); } inline ZZ_p power(const ZZ_p& a, long e) { ZZ_p x; power(x, a, e); NTL_OPT_RETURN(ZZ_p, x); } // ****** comparison inline long IsZero(const ZZ_p& a) { return IsZero(a._ZZ_p__rep); } inline long IsOne(const ZZ_p& a) { return IsOne(a._ZZ_p__rep); } inline long operator==(const ZZ_p& a, const ZZ_p& b) { return a._ZZ_p__rep == b._ZZ_p__rep; } inline long operator!=(const ZZ_p& a, const ZZ_p& b) { return !(a == b); } long operator==(const ZZ_p& a, long b); inline long operator==(long a, const ZZ_p& b) { return b == a; } inline long operator!=(const ZZ_p& a, long b) { return !(a == b); } inline long operator!=(long a, const ZZ_p& b) { return !(a == b); } // ****** random numbers inline void random(ZZ_p& x) // x = random element in ZZ_p { RandomBnd(x._ZZ_p__rep, ZZ_p::modulus()); } inline ZZ_p random_ZZ_p() { ZZ_p x; random(x); NTL_OPT_RETURN(ZZ_p, x); } // ****** input/output inline NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ_p& a) { return s << a._ZZ_p__rep; } NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ_p& x); inline ZZ_p& ZZ_p::operator=(long a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(int& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(unsigned int& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(long& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(unsigned long& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(ZZ& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(ZZ_p& x, const ZZ_p& a) { x = a; } /* ------------------------------------- */ // overload these functions for Vec. // They are defined in vec_ZZ_p.c void BlockConstruct(ZZ_p* p, long n); void BlockConstructFromVec(ZZ_p* p, long n, const ZZ_p* q); void BlockConstructFromObj(ZZ_p* p, long n, const ZZ_p& q); void BlockDestroy(ZZ_p* p, long n); // ZZ_p scratch variables class ZZ_pWatcher { public: ZZ_p *watched; explicit ZZ_pWatcher(ZZ_p *_watched) : watched(_watched) { watched->allocate(); } ~ZZ_pWatcher() { watched->release(); } }; #define NTL_ZZ_pRegister(x) NTL_THREAD_LOCAL static ZZ_p x; ZZ_pWatcher _WATCHER__ ## x(&x) // FIXME: register variables that are allocated with respect to one modulus // and then reused with another modulus may have initial values that are // not in the correct range. This should not cause any problems, though, // as these register values should always be written to before being read. // Note also that the underlying integer reps may have space // allocated that is smaller or *bigger* than the current modulus. // This may impact future interface design changes --- especially // one that tries to make "out of context" copy constructors // safe by reading the allocated space of the source. NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZ_pE.h000644 000765 000024 00000030400 12377144457 016051 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZ_pE__H #define NTL_ZZ_pE__H #include #include #include #include NTL_OPEN_NNS class ZZ_pEInfoT { private: ZZ_pEInfoT(); // disabled ZZ_pEInfoT(const ZZ_pEInfoT&); // disabled void operator=(const ZZ_pEInfoT&); // disabled public: long ref_count; ZZ_pEInfoT(const ZZ_pX&); ~ZZ_pEInfoT() { } ZZ_pXModulus p; ZZ _card; long _card_init; ZZ _card_base; long _card_exp; }; NTL_THREAD_LOCAL extern ZZ_pEInfoT *ZZ_pEInfo; // info for current modulus, initially null // FIXME: in a thread-safe impl, we will need to use shared_ptr's // for reference counted pointers class ZZ_pEContext { private: ZZ_pEInfoT *ptr; public: void save(); void restore() const; ZZ_pEContext() { ptr = 0; } explicit ZZ_pEContext(const ZZ_pX& p); ZZ_pEContext(const ZZ_pEContext&); ZZ_pEContext& operator=(const ZZ_pEContext&); ~ZZ_pEContext(); }; class ZZ_pEBak { private: long MustRestore; ZZ_pEInfoT *ptr; ZZ_pEBak(const ZZ_pEBak&); // disabled void operator=(const ZZ_pEBak&); // disabled public: void save(); void restore(); ZZ_pEBak() { MustRestore = 0; ptr = 0; } ~ZZ_pEBak(); }; class ZZ_pEPush { private: ZZ_pEBak bak; ZZ_pEPush(const ZZ_pEPush&); // disabled void operator=(const ZZ_pEPush&); // disabled public: ZZ_pEPush() { bak.save(); } explicit ZZ_pEPush(const ZZ_pEContext& context) { bak.save(); context.restore(); } explicit ZZ_pEPush(const ZZ_pX& p) { bak.save(); ZZ_pEContext c(p); c.restore(); } }; class ZZ_pEX; // forward declaration class ZZ_pE { public: typedef ZZ_pX rep_type; typedef ZZ_pEContext context_type; typedef ZZ_pEBak bak_type; typedef ZZ_pEPush push_type; typedef ZZ_pEX poly_type; ZZ_pX _ZZ_pE__rep; // static data static long DivCross() { return 16; } static long ModCross() { return 8; } // ****** constructors and assignment ZZ_pE() { } // NO_ALLOC explicit ZZ_pE(long a) { *this = a; } // NO_ALLOC explicit ZZ_pE(const ZZ_p& a) { *this = a; } // NO_ALLOC ZZ_pE(const ZZ_pE& a) { _ZZ_pE__rep = a._ZZ_pE__rep; } // NO_ALLOC ZZ_pE(INIT_NO_ALLOC_TYPE) { } // allocates no space ZZ_pE(INIT_ALLOC_TYPE) {_ZZ_pE__rep.rep.SetMaxLength(ZZ_pE::degree()); } // allocates space void allocate() { _ZZ_pE__rep.rep.SetMaxLength(ZZ_pE::degree()); } ~ZZ_pE() { } ZZ_pE& operator=(const ZZ_pE& a) { _ZZ_pE__rep = a._ZZ_pE__rep; return *this; } inline ZZ_pE& operator=(long a); inline ZZ_pE& operator=(const ZZ_p& a); ZZ_pE(ZZ_pE& x, INIT_TRANS_TYPE) : _ZZ_pE__rep(x._ZZ_pE__rep, INIT_TRANS) { } // You can always access the _ZZ_pE__representation directly...if you dare. ZZ_pX& LoopHole() { return _ZZ_pE__rep; } static const ZZ_pXModulus& modulus() { return ZZ_pEInfo->p; } static long degree() { return deg(ZZ_pEInfo->p); } static const ZZ& cardinality(); static const ZZ_pE& zero(); static long initialized() { return (ZZ_pEInfo != 0); } static void init(const ZZ_pX&); }; // read-only access to _ZZ_pE__representation inline const ZZ_pX& rep(const ZZ_pE& a) { return a._ZZ_pE__rep; } inline void clear(ZZ_pE& x) // x = 0 { clear(x._ZZ_pE__rep); } inline void set(ZZ_pE& x) // x = 1 { set(x._ZZ_pE__rep); } inline void swap(ZZ_pE& x, ZZ_pE& y) // swap x and y { swap(x._ZZ_pE__rep, y._ZZ_pE__rep); } // ****** addition inline void add(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b) // x = a + b { add(x._ZZ_pE__rep, a._ZZ_pE__rep, b._ZZ_pE__rep); } inline void sub(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b) // x = a - b { sub(x._ZZ_pE__rep, a._ZZ_pE__rep, b._ZZ_pE__rep); } inline void negate(ZZ_pE& x, const ZZ_pE& a) { negate(x._ZZ_pE__rep, a._ZZ_pE__rep); } inline void add(ZZ_pE& x, const ZZ_pE& a, long b) { add(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void add(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b) { add(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void add(ZZ_pE& x, long a, const ZZ_pE& b) { add(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } inline void add(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b) { add(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } inline void sub(ZZ_pE& x, const ZZ_pE& a, long b) { sub(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void sub(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b) { sub(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void sub(ZZ_pE& x, long a, const ZZ_pE& b) { sub(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } inline void sub(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b) { sub(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } // ****** multiplication inline void mul(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b) // x = a*b { MulMod(x._ZZ_pE__rep, a._ZZ_pE__rep, b._ZZ_pE__rep, ZZ_pE::modulus()); } inline void sqr(ZZ_pE& x, const ZZ_pE& a) // x = a^2 { SqrMod(x._ZZ_pE__rep, a._ZZ_pE__rep, ZZ_pE::modulus()); } inline ZZ_pE sqr(const ZZ_pE& a) { ZZ_pE x; sqr(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline void mul(ZZ_pE& x, const ZZ_pE& a, long b) { mul(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void mul(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b) { mul(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void mul(ZZ_pE& x, long a, const ZZ_pE& b) { mul(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } inline void mul(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b) { mul(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } // ****** division void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); void div(ZZ_pE& x, const ZZ_pE& a, long b); void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b); void div(ZZ_pE& x, long a, const ZZ_pE& b); void div(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b); void inv(ZZ_pE& x, const ZZ_pE& a); inline ZZ_pE inv(const ZZ_pE& a) { ZZ_pE x; inv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } // ****** exponentiation inline void power(ZZ_pE& x, const ZZ_pE& a, const ZZ& e) // x = a^e { PowerMod(x._ZZ_pE__rep, a._ZZ_pE__rep, e, ZZ_pE::modulus()); } inline ZZ_pE power(const ZZ_pE& a, const ZZ& e) { ZZ_pE x; power(x, a, e); NTL_OPT_RETURN(ZZ_pE, x); } inline void power(ZZ_pE& x, const ZZ_pE& a, long e) { power(x, a, ZZ_expo(e)); } inline ZZ_pE power(const ZZ_pE& a, long e) { ZZ_pE x; power(x, a, e); NTL_OPT_RETURN(ZZ_pE, x); } // ****** conversion inline void conv(ZZ_pE& x, const ZZ_pX& a) { rem(x._ZZ_pE__rep, a, ZZ_pE::modulus()); } inline void conv(ZZ_pE& x, long a) { conv(x._ZZ_pE__rep, a); } inline void conv(ZZ_pE& x, const ZZ_p& a) { conv(x._ZZ_pE__rep, a); } inline void conv(ZZ_pE& x, const ZZ& a) { conv(x._ZZ_pE__rep, a); } inline ZZ_pE to_ZZ_pE(const ZZ_pX& a) { ZZ_pE x; conv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE to_ZZ_pE(long a) { ZZ_pE x; conv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE to_ZZ_pE(const ZZ_p& a) { ZZ_pE x; conv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE to_ZZ_pE(const ZZ& a) { ZZ_pE x; conv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } // ****** comparison inline long IsZero(const ZZ_pE& a) { return IsZero(a._ZZ_pE__rep); } inline long IsOne(const ZZ_pE& a) { return IsOne(a._ZZ_pE__rep); } inline long operator==(const ZZ_pE& a, const ZZ_pE& b) { return a._ZZ_pE__rep == b._ZZ_pE__rep; } inline long operator==(const ZZ_pE& a, long b) { return a._ZZ_pE__rep == b; } inline long operator==(const ZZ_pE& a, const ZZ_p& b) { return a._ZZ_pE__rep == b; } inline long operator==(long a, const ZZ_pE& b) { return a == b._ZZ_pE__rep; } inline long operator==(const ZZ_p& a, const ZZ_pE& b) { return a == b._ZZ_pE__rep; } inline long operator!=(const ZZ_pE& a, const ZZ_pE& b) { return !(a == b); } inline long operator!=(const ZZ_pE& a, long b) { return !(a == b); } inline long operator!=(const ZZ_pE& a, const ZZ_p& b) { return !(a == b); } inline long operator!=(long a, const ZZ_pE& b) { return !(a == b); } inline long operator!=(const ZZ_p& a, const ZZ_pE& b) { return !(a == b); } // ****** norm and trace inline void trace(ZZ_p& x, const ZZ_pE& a) { TraceMod(x, a._ZZ_pE__rep, ZZ_pE::modulus()); } inline ZZ_p trace(const ZZ_pE& a) { return TraceMod(a._ZZ_pE__rep, ZZ_pE::modulus()); } inline void norm(ZZ_p& x, const ZZ_pE& a) { NormMod(x, a._ZZ_pE__rep, ZZ_pE::modulus()); } inline ZZ_p norm(const ZZ_pE& a) { return NormMod(a._ZZ_pE__rep, ZZ_pE::modulus()); } // ****** random numbers inline void random(ZZ_pE& x) // x = random element in ZZ_pE { random(x._ZZ_pE__rep, ZZ_pE::degree()); } inline ZZ_pE random_ZZ_pE() { ZZ_pE x; random(x); NTL_OPT_RETURN(ZZ_pE, x); } // ****** input/output inline NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ_pE& a) { return s << a._ZZ_pE__rep; } NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ_pE& x); inline ZZ_pE& ZZ_pE::operator=(long a) { conv(*this, a); return *this; } inline ZZ_pE& ZZ_pE::operator=(const ZZ_p& a) { conv(*this, a); return *this; } inline ZZ_pE operator+(const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator+(const ZZ_pE& a, const ZZ_p& b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator+(const ZZ_pE& a, long b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator+(const ZZ_p& a, const ZZ_pE& b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator+(long a, const ZZ_pE& b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_pE& a, const ZZ_p& b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_pE& a, long b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_p& a, const ZZ_pE& b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(long a, const ZZ_pE& b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_pE& a) { ZZ_pE x; negate(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE& operator+=(ZZ_pE& x, const ZZ_pE& b) { add(x, x, b); return x; } inline ZZ_pE& operator+=(ZZ_pE& x, const ZZ_p& b) { add(x, x, b); return x; } inline ZZ_pE& operator+=(ZZ_pE& x, long b) { add(x, x, b); return x; } inline ZZ_pE& operator-=(ZZ_pE& x, const ZZ_pE& b) { sub(x, x, b); return x; } inline ZZ_pE& operator-=(ZZ_pE& x, const ZZ_p& b) { sub(x, x, b); return x; } inline ZZ_pE& operator-=(ZZ_pE& x, long b) { sub(x, x, b); return x; } inline ZZ_pE& operator++(ZZ_pE& x) { add(x, x, 1); return x; } inline void operator++(ZZ_pE& x, int) { add(x, x, 1); } inline ZZ_pE& operator--(ZZ_pE& x) { sub(x, x, 1); return x; } inline void operator--(ZZ_pE& x, int) { sub(x, x, 1); } inline ZZ_pE operator*(const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator*(const ZZ_pE& a, const ZZ_p& b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator*(const ZZ_pE& a, long b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator*(const ZZ_p& a, const ZZ_pE& b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator*(long a, const ZZ_pE& b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE& operator*=(ZZ_pE& x, const ZZ_pE& b) { mul(x, x, b); return x; } inline ZZ_pE& operator*=(ZZ_pE& x, const ZZ_p& b) { mul(x, x, b); return x; } inline ZZ_pE& operator*=(ZZ_pE& x, long b) { mul(x, x, b); return x; } inline ZZ_pE operator/(const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator/(const ZZ_pE& a, const ZZ_p& b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator/(const ZZ_pE& a, long b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator/(const ZZ_p& a, const ZZ_pE& b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator/(long a, const ZZ_pE& b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE& operator/=(ZZ_pE& x, const ZZ_pE& b) { div(x, x, b); return x; } inline ZZ_pE& operator/=(ZZ_pE& x, const ZZ_p& b) { div(x, x, b); return x; } inline ZZ_pE& operator/=(ZZ_pE& x, long b) { div(x, x, b); return x; } /* additional legacy conversions for v6 conversion regime */ inline void conv(ZZ_pX& x, const ZZ_pE& a) { x = rep(a); } inline void conv(ZZ_pE& x, const ZZ_pE& a) { x = a; } /* ------------------------------------- */ NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZ_pEX.h000644 000765 000024 00000074762 12377144457 016224 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZ_pEX__H #define NTL_ZZ_pEX__H #include NTL_OPEN_NNS class ZZ_pEXModulus; // forward declaration class ZZ_pEX { public: typedef ZZ_pE coeff_type; typedef ZZ_pEXModulus modulus_type; vec_ZZ_pE rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ ZZ_pEX() { } // initial value 0 explicit ZZ_pEX(long a) { *this = a; } explicit ZZ_pEX(const ZZ_p& a) { *this = a; } explicit ZZ_pEX(const ZZ_pE& a) { *this = a; } ZZ_pEX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } ~ZZ_pEX() { } void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } ZZ_pE& operator[](long i) { return rep[i]; } const ZZ_pE& operator[](long i) const { return rep[i]; } static const ZZ_pEX& zero(); inline ZZ_pEX(long i, const ZZ_pE& c); inline ZZ_pEX(long i, const ZZ_p& c); inline ZZ_pEX(long i, long c); inline ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_pE& c); inline ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_p& c); inline ZZ_pEX(INIT_MONO_TYPE, long i, long c); inline ZZ_pEX(INIT_MONO_TYPE, long i); inline ZZ_pEX& operator=(long a); inline ZZ_pEX& operator=(const ZZ_p& a); inline ZZ_pEX& operator=(const ZZ_pE& a); ZZ_pEX(ZZ_pEX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } }; NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ_pEX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ_pEX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const ZZ_pEX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const ZZ_pE& coeff(const ZZ_pEX& a, long i); // zero if i not in range const ZZ_pE& LeadCoeff(const ZZ_pEX& a); // zero if a == 0 const ZZ_pE& ConstTerm(const ZZ_pEX& a); // zero if a == 0 void SetCoeff(ZZ_pEX& x, long i, const ZZ_pE& a); void SetCoeff(ZZ_pEX& x, long i, const ZZ_p& a); void SetCoeff(ZZ_pEX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(ZZ_pEX& x, long i); // x[i] = 1, error is raised if i < 0 inline ZZ_pEX::ZZ_pEX(long i, const ZZ_pE& a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(long i, const ZZ_p& a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(long i, long a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_pE& a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_p& a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(ZZ_pEX& x); // x is set to the monomial X long IsX(const ZZ_pEX& a); // test if x = X inline void clear(ZZ_pEX& x) // x = 0 { x.rep.SetLength(0); } inline void set(ZZ_pEX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(ZZ_pEX& x, ZZ_pEX& y) // swap x & y (only pointers are swapped) { swap(x.rep, y.rep); } void random(ZZ_pEX& x, long n); inline ZZ_pEX random_ZZ_pEX(long n) { ZZ_pEX x; random(x, n); NTL_OPT_RETURN(ZZ_pEX, x); } // generate a random polynomial of degree < n void trunc(ZZ_pEX& x, const ZZ_pEX& a, long m); inline ZZ_pEX trunc(const ZZ_pEX& a, long m) { ZZ_pEX x; trunc(x, a, m); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a % X^m void RightShift(ZZ_pEX& x, const ZZ_pEX& a, long n); inline ZZ_pEX RightShift(const ZZ_pEX& a, long n) { ZZ_pEX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a/X^n void LeftShift(ZZ_pEX& x, const ZZ_pEX& a, long n); inline ZZ_pEX LeftShift(const ZZ_pEX& a, long n) { ZZ_pEX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a*X^n #ifndef NTL_TRANSITION inline ZZ_pEX operator>>(const ZZ_pEX& a, long n) { ZZ_pEX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator<<(const ZZ_pEX& a, long n) { ZZ_pEX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator<<=(ZZ_pEX& x, long n) { LeftShift(x, x, n); return x; } inline ZZ_pEX& operator>>=(ZZ_pEX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(ZZ_pEX& x, const ZZ_pEX& a); inline ZZ_pEX diff(const ZZ_pEX& a) { ZZ_pEX x; diff(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } // x = derivative of a void MakeMonic(ZZ_pEX& x); void reverse(ZZ_pEX& c, const ZZ_pEX& a, long hi); inline ZZ_pEX reverse(const ZZ_pEX& a, long hi) { ZZ_pEX x; reverse(x, a, hi); NTL_OPT_RETURN(ZZ_pEX, x); } inline void reverse(ZZ_pEX& c, const ZZ_pEX& a) { reverse(c, a, deg(a)); } inline ZZ_pEX reverse(const ZZ_pEX& a) { ZZ_pEX x; reverse(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline void VectorCopy(vec_ZZ_pE& x, const ZZ_pEX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_ZZ_pE VectorCopy(const ZZ_pEX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(ZZ_pEX& x, long a); void conv(ZZ_pEX& x, const ZZ& a); void conv(ZZ_pEX& x, const ZZ_p& a); void conv(ZZ_pEX& x, const ZZ_pX& a); void conv(ZZ_pEX& x, const ZZ_pE& a); void conv(ZZ_pEX& x, const vec_ZZ_pE& a); inline ZZ_pEX to_ZZ_pEX(long a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const ZZ& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const ZZ_p& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const ZZ_pX& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const ZZ_pE& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const vec_ZZ_pE& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& ZZ_pEX::operator=(long a) { conv(*this, a); return *this; } inline ZZ_pEX& ZZ_pEX::operator=(const ZZ_p& a) { conv(*this, a); return *this; } inline ZZ_pEX& ZZ_pEX::operator=(const ZZ_pE& a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(ZZ_pEX& x, const ZZ_pEX& a) { x = a; } inline void conv(vec_ZZ_pE& x, const ZZ_pEX& a) { x = a.rep; } class ZZX; void conv(ZZ_pEX& x, const ZZX& a); /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const ZZ_pEX& a); long IsOne(const ZZ_pEX& a); inline long operator==(const ZZ_pEX& a, const ZZ_pEX& b) { return a.rep == b.rep; } long operator==(const ZZ_pEX& a, long b); long operator==(const ZZ_pEX& a, const ZZ_p& b); long operator==(const ZZ_pEX& a, const ZZ_pE& b); inline long operator==(long a, const ZZ_pEX& b) { return (b == a); } inline long operator==(const ZZ_p& a, const ZZ_pEX& b) { return (b == a); } inline long operator==(const ZZ_pE& a, const ZZ_pEX& b) { return (b == a); } inline long operator!=(const ZZ_pEX& a, const ZZ_pEX& b) { return !(a == b); } inline long operator!=(const ZZ_pEX& a, long b) { return !(a == b); } inline long operator!=(const ZZ_pEX& a, const ZZ_p& b) { return !(a == b); } inline long operator!=(const ZZ_pEX& a, const ZZ_pE& b) { return !(a == b); } inline long operator!=(const long a, const ZZ_pEX& b) { return !(a == b); } inline long operator!=(const ZZ_p& a, const ZZ_pEX& b) { return !(a == b); } inline long operator!=(const ZZ_pE& a, const ZZ_pEX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); void negate(ZZ_pEX& x, const ZZ_pEX& a); // scalar versions void add(ZZ_pEX & x, const ZZ_pEX& a, long b); void add(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_p& b); void add(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_pE& b); inline void add(ZZ_pEX& x, const ZZ_pE& a, const ZZ_pEX& b) { add(x, b, a); } inline void add(ZZ_pEX& x, const ZZ_p& a, const ZZ_pEX& b) { add(x, b, a); } inline void add(ZZ_pEX& x, long a, const ZZ_pEX& b) { add(x, b, a); } void sub(ZZ_pEX & x, const ZZ_pEX& a, long b); void sub(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_p& b); void sub(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_pE& b); void sub(ZZ_pEX& x, const ZZ_pE& a, const ZZ_pEX& b); void sub(ZZ_pEX& x, const ZZ_p& a, const ZZ_pEX& b); void sub(ZZ_pEX& x, long a, const ZZ_pEX& b); inline ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_p& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_pEX& a, long b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_pE& a, const ZZ_pEX& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_p& a, const ZZ_pEX& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(long a, const ZZ_pEX& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_p& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pEX& a, long b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pE& a, const ZZ_pEX& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_p& a, const ZZ_pEX& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(long a, const ZZ_pEX& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pEX& b) { add(x, x, b); return x; } inline ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pE& b) { add(x, x, b); return x; } inline ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_p& b) { add(x, x, b); return x; } inline ZZ_pEX& operator+=(ZZ_pEX& x, long b) { add(x, x, b); return x; } inline ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pEX& b) { sub(x, x, b); return x; } inline ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pE& b) { sub(x, x, b); return x; } inline ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_p& b) { sub(x, x, b); return x; } inline ZZ_pEX& operator-=(ZZ_pEX& x, long b) { sub(x, x, b); return x; } inline ZZ_pEX operator-(const ZZ_pEX& a) { ZZ_pEX x; negate(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator++(ZZ_pEX& x) { add(x, x, 1); return x; } inline void operator++(ZZ_pEX& x, int) { add(x, x, 1); } inline ZZ_pEX& operator--(ZZ_pEX& x) { sub(x, x, 1); return x; } inline void operator--(ZZ_pEX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a * b void sqr(ZZ_pEX& x, const ZZ_pEX& a); inline ZZ_pEX sqr(const ZZ_pEX& a) { ZZ_pEX x; sqr(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a^2 void mul(ZZ_pEX & x, const ZZ_pEX& a, long b); void mul(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_p& b); void mul(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_pE& b); inline void mul(ZZ_pEX& x, long a, const ZZ_pEX& b) { mul(x, b, a); } inline void mul(ZZ_pEX& x, const ZZ_p& a, const ZZ_pEX& b) { mul(x, b, a); } inline void mul(ZZ_pEX& x, const ZZ_pE& a, const ZZ_pEX& b) { mul(x, b, a); } void MulTrunc(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, long n); inline ZZ_pEX MulTrunc(const ZZ_pEX& a, const ZZ_pEX& b, long n) { ZZ_pEX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a * b % X^n void SqrTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n); inline ZZ_pEX SqrTrunc(const ZZ_pEX& a, long n) { ZZ_pEX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a*a % X^n inline ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_p& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_pEX& a, long b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_pE& a, const ZZ_pEX& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_p& a, const ZZ_pEX& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(long a, const ZZ_pEX& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pEX& b) { mul(x, x, b); return x; } inline ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pE& b) { mul(x, x, b); return x; } inline ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_p& b) { mul(x, x, b); return x; } inline ZZ_pEX& operator*=(ZZ_pEX& x, long b) { mul(x, x, b); return x; } void power(ZZ_pEX& x, const ZZ_pEX& a, long e); inline ZZ_pEX power(const ZZ_pEX& a, long e) { ZZ_pEX x; power(x, a, e); NTL_OPT_RETURN(ZZ_pEX, x); } /************************************************************* Division **************************************************************/ void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b); // q = a/b, r = a%b void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pE& b); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_p& b); void div(ZZ_pEX& q, const ZZ_pEX& a, long b); // q = a/b void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b); // r = a%b long divide(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZ_pEX& a, const ZZ_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long m); inline ZZ_pEX InvTrunc(const ZZ_pEX& a, long m) { ZZ_pEX x; InvTrunc(x, a, m); NTL_OPT_RETURN(ZZ_pEX, x); } // computes x = a^{-1} % X^m // constant term must be invertible inline ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pEX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_p& b) { ZZ_pEX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator/(const ZZ_pEX& a, long b) { ZZ_pEX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEX& b) { div(x, x, b); return x; } inline ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pE& b) { div(x, x, b); return x; } inline ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_p& b) { div(x, x, b); return x; } inline ZZ_pEX& operator/=(ZZ_pEX& x, long b) { div(x, x, b); return x; } inline ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; rem(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); inline ZZ_pEX GCD(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; GCD(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(ZZ_pEX& d, ZZ_pEX& s, ZZ_pEX& t, const ZZ_pEX& a, const ZZ_pEX& b); // d = gcd(a,b), a s + b t = d /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the ZZ_pEXModulus data structure and associated routines below. void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f); inline ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f) { ZZ_pEX x; MulMod(x, a, b, f); NTL_OPT_RETURN(ZZ_pEX, x); } // x = (a * b) % f void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pEX x; SqrMod(x, a, f); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a^2 % f void MulByXMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pEX MulByXMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pEX x; MulByXMod(x, a, f); NTL_OPT_RETURN(ZZ_pEX, x); } // x = (a * X) mod f void InvMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pEX InvMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pEX x; InvMod(x, a, f); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a^{-1} % f, error is a is not invertible long InvModStatus(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build ZZ_pEXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class ZZ_pEXModulus { public: ZZ_pEXModulus(); ~ZZ_pEXModulus(); ZZ_pEXModulus(const ZZ_pEX& ff); ZZ_pEX f; // the modulus operator const ZZ_pEX& () const { return f; } const ZZ_pEX& val() const { return f; } long n; // deg(f) long method; ZZ_pEX h0; ZZ_pE hlc; ZZ_pEX f0; vec_ZZ_pE tracevec; // mutable }; inline long deg(const ZZ_pEXModulus& F) { return F.n; } void build(ZZ_pEXModulus& F, const ZZ_pEX& f); void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F); void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F); void MulMod(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F); inline ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F) { ZZ_pEX x; MulMod(x, a, b, F); NTL_OPT_RETURN(ZZ_pEX, x); } void SqrMod(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEXModulus& F); inline ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX x; SqrMod(x, a, F); NTL_OPT_RETURN(ZZ_pEX, x); } void PowerMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ& e, const ZZ_pEXModulus& F); inline void PowerMod(ZZ_pEX& h, const ZZ_pEX& g, long e, const ZZ_pEXModulus& F) { PowerMod(h, g, ZZ_expo(e), F); } inline ZZ_pEX PowerMod(const ZZ_pEX& g, const ZZ& e, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX PowerMod(const ZZ_pEX& g, long e, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(ZZ_pEX, x); } void PowerXMod(ZZ_pEX& hh, const ZZ& e, const ZZ_pEXModulus& F); inline void PowerXMod(ZZ_pEX& h, long e, const ZZ_pEXModulus& F) { PowerXMod(h, ZZ_expo(e), F); } inline ZZ_pEX PowerXMod(const ZZ& e, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerXMod(x, e, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX PowerXMod(long e, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerXMod(x, e, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX x; rem(x, a, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEXModulus& F) { rem(x, x, F); return x; } inline ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX x; div(x, a, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEXModulus& F) { div(x, x, F); return x; } /***************************************************************** vectors of ZZ_pEX's *****************************************************************/ typedef Vec vec_ZZ_pEX; /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(ZZ_pEX& x, const vec_ZZ_pE& a); inline ZZ_pEX BuildFromRoots(const vec_ZZ_pE& a) { ZZ_pEX x; BuildFromRoots(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(ZZ_pE& b, const ZZ_pEX& f, const ZZ_pE& a); inline ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a) { ZZ_pE x; eval(x, f, a); NTL_OPT_RETURN(ZZ_pE, x); } // b = f(a) void eval(vec_ZZ_pE& b, const ZZ_pEX& f, const vec_ZZ_pE& a); inline vec_ZZ_pE eval(const ZZ_pEX& f, const vec_ZZ_pE& a) { vec_ZZ_pE x; eval(x, f, a); NTL_OPT_RETURN(vec_ZZ_pE, x); } // b[i] = f(a[i]) inline void eval(ZZ_pE& b, const ZZ_pX& f, const ZZ_pE& a) { conv(b, CompMod(f, rep(a), ZZ_pE::modulus())); } inline ZZ_pE eval(const ZZ_pX& f, const ZZ_pE& a) { ZZ_pE x; eval(x, f, a); NTL_OPT_RETURN(ZZ_pE, x); } // b = f(a) void interpolate(ZZ_pEX& f, const vec_ZZ_pE& a, const vec_ZZ_pE& b); inline ZZ_pEX interpolate(const vec_ZZ_pE& a, const vec_ZZ_pE& b) { ZZ_pEX x; interpolate(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } // computes f such that f(a[i]) = b[i] /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); inline ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F) { ZZ_pEX x; CompMod(x, g, h, F); NTL_OPT_RETURN(ZZ_pEX, x); } // x = g(h) mod f void Comp2Mod(ZZ_pEX& x1, ZZ_pEX& x2, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& h, const ZZ_pEXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(ZZ_pEX& x1, ZZ_pEX& x2, ZZ_pEX& x3, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& g3, const ZZ_pEX& h, const ZZ_pEXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If ZZ_pEXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If ZZ_pEXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, ZZ_pEXArgBound = 0. // If a single h is going to be used with many g's // then you should build a ZZ_pEXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If ZZ_pEXArgBound > 0, a table of size less than m may be built. struct ZZ_pEXArgument { vec_ZZ_pEX H; }; NTL_THREAD_LOCAL extern long ZZ_pEXArgBound; void build(ZZ_pEXArgument& H, const ZZ_pEX& h, const ZZ_pEXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); inline ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F) { ZZ_pEX x; CompMod(x, g, H, F); NTL_OPT_RETURN(ZZ_pEX, x); } void MinPolySeq(ZZ_pEX& h, const vec_ZZ_pE& a, long m); inline ZZ_pEX MinPolySeq(const vec_ZZ_pE& a, long m) { ZZ_pEX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(ZZ_pEX, x); } void MinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F); inline ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pEX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pEX, x); } void MinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pEX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pEX, x); } void ProbMinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F); inline ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pEX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pEX, x); } void ProbMinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pEX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pEX, x); } void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); inline ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pEX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pEX, x); } void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pEX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pEX, x); } struct ZZ_pEXTransMultiplier { ZZ_pEX f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(ZZ_pEXTransMultiplier& B, const ZZ_pEX& b, const ZZ_pEXModulus& F); void TransMulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F); void UpdateMap(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F); inline vec_ZZ_pE UpdateMap(const vec_ZZ_pE& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F) { vec_ZZ_pE x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_ZZ_pE, x); } void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); inline vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F) { vec_ZZ_pE x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_ZZ_pE, x); } void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F); inline vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k, const ZZ_pEX& H, const ZZ_pEXModulus& F) { vec_ZZ_pE x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline void project(ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pEX& b) { InnerProduct(x, a, b.rep); } inline ZZ_pE project(const vec_ZZ_pE& a, const ZZ_pEX& b) { ZZ_pE x; InnerProduct(x, a, b.rep); NTL_OPT_RETURN(ZZ_pE, x); } /***************************************************************** modular composition and minimal polynonomials in towers ******************************************************************/ // composition void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEXArgument& A, const ZZ_pEXModulus& F); inline ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEXArgument& A, const ZZ_pEXModulus& F) { ZZ_pEX x; CompTower(x, g, A, F); NTL_OPT_RETURN(ZZ_pEX, x); } void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); inline ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F) { ZZ_pEX x; CompTower(x, g, h, F); NTL_OPT_RETURN(ZZ_pEX, x); } // prob min poly void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pX x; ProbMinPolyTower(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { ProbMinPolyTower(h, g, F, deg(F)*ZZ_pE::degree()); } inline ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pX x; ProbMinPolyTower(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // min poly void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pX x; MinPolyTower(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { MinPolyTower(h, g, F, deg(F)*ZZ_pE::degree()); } inline ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pX x; MinPolyTower(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // irred poly void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pX x; IrredPolyTower(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { IrredPolyTower(h, g, F, deg(F)*ZZ_pE::degree()); } inline ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pX x; IrredPolyTower(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_ZZ_pE& S, const ZZ_pEX& f); inline vec_ZZ_pE TraceVec(const ZZ_pEX& f) { vec_ZZ_pE x; TraceVec(x, f); NTL_OPT_RETURN(vec_ZZ_pE, x); } void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEXModulus& F); inline ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pE x; TraceMod(x, a, F); NTL_OPT_RETURN(ZZ_pE, x); } void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pE x; TraceMod(x, a, f); NTL_OPT_RETURN(ZZ_pE, x); } void NormMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pE NormMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pE x; NormMod(x, a, f); NTL_OPT_RETURN(ZZ_pE, x); } void resultant(ZZ_pE& rres, const ZZ_pEX& a, const ZZ_pEX& b); inline ZZ_pE resultant(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pE x; resultant(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZ_pEXFactoring.h000644 000765 000024 00000012467 12377144457 020053 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZ_pEXFactoring__H #define NTL_ZZ_pEXFactoring__H #include NTL_OPEN_NNS void SquareFreeDecomp(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& f); inline vec_pair_ZZ_pEX_long SquareFreeDecomp(const ZZ_pEX& f) { vec_pair_ZZ_pEX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_ZZ_pE& x, const ZZ_pEX& f); inline vec_ZZ_pE FindRoots(const ZZ_pEX& f) { vec_ZZ_pE x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(ZZ_pE& root, const ZZ_pEX& f); inline ZZ_pE FindRoot(const ZZ_pEX& f) { ZZ_pE x; FindRoot(x, f); return x; } // finds a single root of f. // assumes that f is monic and splits into distinct linear factors NTL_THREAD_LOCAL extern long ZZ_pEX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF NTL_THREAD_LOCAL extern char ZZ_pEX_stem[]; // Determines filename stem for external storage in NewDDF. NTL_THREAD_LOCAL extern double ZZ_pEXFileThresh; // of these tables exceeds ZZ_pEXFileThresh KB. void NewDDF(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, const ZZ_pEX& h, long verbose=0); inline vec_pair_ZZ_pEX_long NewDDF(const ZZ_pEX& f, const ZZ_pEX& h, long verbose=0) { vec_pair_ZZ_pEX_long x; NewDDF(x, f, h, verbose); return x; } void EDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& b, long d, long verbose=0); inline vec_ZZ_pEX EDF(const ZZ_pEX& f, const ZZ_pEX& b, long d, long verbose=0) { vec_ZZ_pEX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0); inline vec_ZZ_pEX RootEDF(const ZZ_pEX& f, long verbose=0) { vec_ZZ_pEX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0); inline vec_ZZ_pEX SFCanZass(const ZZ_pEX& f, long verbose=0) { vec_ZZ_pEX x; SFCanZass(x, f, verbose); return x; } // Assumes f is monic and square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void CanZass(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, long verbose=0); inline vec_pair_ZZ_pEX_long CanZass(const ZZ_pEX& f, long verbose=0) { vec_pair_ZZ_pEX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(ZZ_pEX& f, const vec_pair_ZZ_pEX_long& v); inline ZZ_pEX mul(const vec_pair_ZZ_pEX_long& v) { ZZ_pEX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const ZZ_pEX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const ZZ_pEX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const ZZ_pEX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(ZZ_pEX& f, long n); inline ZZ_pEX BuildIrred_ZZ_pEX(long n) { ZZ_pEX x; BuildIrred(x, n); NTL_OPT_RETURN(ZZ_pEX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(ZZ_pEX& f, const ZZ_pEX& g); inline ZZ_pEX BuildRandomIrred(const ZZ_pEX& g) { ZZ_pEX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(ZZ_pEX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long RecComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long IterComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F); void TraceMap(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& b); inline ZZ_pEX TraceMap(const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& b) { ZZ_pEX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) void PowerCompose(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F); inline ZZ_pEX PowerCompose(const ZZ_pEX& a, long d, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZ_pX.h000644 000765 000024 00000106420 12377144457 016102 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZ_pX__H #define NTL_ZZ_pX__H #include #include #include #include #include NTL_OPEN_NNS // some cross-over points // macros are used so as to be consistent with zz_pX #define NTL_ZZ_pX_FFT_CROSSOVER (20) #define NTL_ZZ_pX_NEWTON_CROSSOVER (45) #define NTL_ZZ_pX_DIV_CROSSOVER (90) #define NTL_ZZ_pX_HalfGCD_CROSSOVER (25) #define NTL_ZZ_pX_GCD_CROSSOVER (180) #define NTL_ZZ_pX_BERMASS_CROSSOVER (90) #define NTL_ZZ_pX_TRACE_CROSSOVER (90) /************************************************************ ZZ_pX The class ZZ_pX implements polynomial arithmetic modulo p. Polynomials are represented as vec_ZZ_p's. If f is a ZZ_pX, then f.rep is a vec_ZZ_p. The zero polynomial is represented as a zero length vector. Otherwise. f.rep[0] is the constant-term, and f.rep[f.rep.length()-1] is the leading coefficient, which is always non-zero. The member f.rep is public, so the vector representation is fully accessible. Use the member function normalize() to strip leading zeros. **************************************************************/ class ZZ_pE; // forward declaration class ZZ_pXModulus; class FFTRep; class ZZ_pXMultiplier; class ZZ_pX { public: typedef ZZ_p coeff_type; typedef ZZ_pE residue_type; typedef ZZ_pXModulus modulus_type; typedef ZZ_pXMultiplier multiplier_type; typedef FFTRep fft_type; typedef vec_ZZ_p VectorBaseType; vec_ZZ_p rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ ZZ_pX() { } // initial value 0 explicit ZZ_pX(long a) { *this = a; } explicit ZZ_pX(const ZZ_p& a) { *this = a; } ZZ_pX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } ZZ_pX(const ZZ_pX& a) : rep(a.rep) { } // initial value is a ZZ_pX& operator=(const ZZ_pX& a) { rep = a.rep; return *this; } ~ZZ_pX() { } void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } ZZ_p& operator[](long i) { return rep[i]; } const ZZ_p& operator[](long i) const { return rep[i]; } static const ZZ_pX& zero(); ZZ_pX(ZZ_pX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } inline ZZ_pX(long i, const ZZ_p& c); inline ZZ_pX(long i, long c); inline ZZ_pX(INIT_MONO_TYPE, long i, const ZZ_p& c); inline ZZ_pX(INIT_MONO_TYPE, long i, long c); inline ZZ_pX(INIT_MONO_TYPE, long i); ZZ_pX& operator=(long a); ZZ_pX& operator=(const ZZ_p& a); }; /******************************************************************** input and output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, amd a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary integers which are then reduced modulo p, and leading zeros stripped. *********************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ_pX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ_pX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const ZZ_pX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const ZZ_p& coeff(const ZZ_pX& a, long i); // zero if i not in range void GetCoeff(ZZ_p& x, const ZZ_pX& a, long i); // x = a[i], or zero if i not in range const ZZ_p& LeadCoeff(const ZZ_pX& a); // zero if a == 0 const ZZ_p& ConstTerm(const ZZ_pX& a); // zero if a == 0 void SetCoeff(ZZ_pX& x, long i, const ZZ_p& a); // x[i] = a, error is raised if i < 0 void SetCoeff(ZZ_pX& x, long i, long a); void SetCoeff(ZZ_pX& x, long i); // x[i] = 1, error is raised if i < 0 inline ZZ_pX::ZZ_pX(long i, const ZZ_p& a) { SetCoeff(*this, i, a); } inline ZZ_pX::ZZ_pX(long i, long a) { SetCoeff(*this, i, a); } inline ZZ_pX::ZZ_pX(INIT_MONO_TYPE, long i, const ZZ_p& a) { SetCoeff(*this, i, a); } inline ZZ_pX::ZZ_pX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline ZZ_pX::ZZ_pX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(ZZ_pX& x); // x is set to the monomial X long IsX(const ZZ_pX& a); // test if a = X inline void clear(ZZ_pX& x) // x = 0 { x.rep.SetLength(0); } inline void set(ZZ_pX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(ZZ_pX& x, ZZ_pX& y) // swap x & y (only pointers are swapped) { swap(x.rep, y.rep); } void random(ZZ_pX& x, long n); inline ZZ_pX random_ZZ_pX(long n) { ZZ_pX x; random(x, n); NTL_OPT_RETURN(ZZ_pX, x); } // generate a random polynomial of degree < n void trunc(ZZ_pX& x, const ZZ_pX& a, long m); // x = a % X^m inline ZZ_pX trunc(const ZZ_pX& a, long m) { ZZ_pX x; trunc(x, a, m); NTL_OPT_RETURN(ZZ_pX, x); } void RightShift(ZZ_pX& x, const ZZ_pX& a, long n); // x = a/X^n inline ZZ_pX RightShift(const ZZ_pX& a, long n) { ZZ_pX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n); // x = a*X^n inline ZZ_pX LeftShift(const ZZ_pX& a, long n) { ZZ_pX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } #ifndef NTL_TRANSITION inline ZZ_pX operator>>(const ZZ_pX& a, long n) { ZZ_pX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator<<(const ZZ_pX& a, long n) { ZZ_pX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator<<=(ZZ_pX& x, long n) { LeftShift(x, x, n); return x; } inline ZZ_pX& operator>>=(ZZ_pX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(ZZ_pX& x, const ZZ_pX& a); // x = derivative of a inline ZZ_pX diff(const ZZ_pX& a) { ZZ_pX x; diff(x, a); NTL_OPT_RETURN(ZZ_pX, x); } void MakeMonic(ZZ_pX& x); void reverse(ZZ_pX& c, const ZZ_pX& a, long hi); inline ZZ_pX reverse(const ZZ_pX& a, long hi) { ZZ_pX x; reverse(x, a, hi); NTL_OPT_RETURN(ZZ_pX, x); } inline void reverse(ZZ_pX& c, const ZZ_pX& a) { reverse(c, a, deg(a)); } inline ZZ_pX reverse(const ZZ_pX& a) { ZZ_pX x; reverse(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline void VectorCopy(vec_ZZ_p& x, const ZZ_pX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_ZZ_p VectorCopy(const ZZ_pX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(ZZ_pX& x, long a); void conv(ZZ_pX& x, const ZZ& a); void conv(ZZ_pX& x, const ZZ_p& a); void conv(ZZ_pX& x, const vec_ZZ_p& a); inline ZZ_pX to_ZZ_pX(long a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX to_ZZ_pX(const ZZ& a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX to_ZZ_pX(const ZZ_p& a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX to_ZZ_pX(const vec_ZZ_p& a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } /* additional legacy conversions for v6 conversion regime */ inline void conv(ZZ_pX& x, const ZZ_pX& a) { x = a; } inline void conv(vec_ZZ_p& x, const ZZ_pX& a) { x = a.rep; } /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const ZZ_pX& a); long IsOne(const ZZ_pX& a); inline long operator==(const ZZ_pX& a, const ZZ_pX& b) { return a.rep == b.rep; } inline long operator!=(const ZZ_pX& a, const ZZ_pX& b) { return !(a == b); } long operator==(const ZZ_pX& a, long b); long operator==(const ZZ_pX& a, const ZZ_p& b); inline long operator==(long a, const ZZ_pX& b) { return b == a; } inline long operator==(const ZZ_p& a, const ZZ_pX& b) { return b == a; } inline long operator!=(const ZZ_pX& a, long b) { return !(a == b); } inline long operator!=(const ZZ_pX& a, const ZZ_p& b) { return !(a == b); } inline long operator!=(long a, const ZZ_pX& b) { return !(a == b); } inline long operator!=(const ZZ_p& a, const ZZ_pX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a + b void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a - b void negate(ZZ_pX& x, const ZZ_pX& a); // x = -a // scalar versions void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b); // x = a + b void add(ZZ_pX& x, const ZZ_pX& a, long b); inline void add(ZZ_pX& x, const ZZ_p& a, const ZZ_pX& b) { add(x, b, a); } inline void add(ZZ_pX& x, long a, const ZZ_pX& b) { add(x, b, a); } void sub(ZZ_pX & x, const ZZ_pX& a, const ZZ_p& b); // x = a - b void sub(ZZ_pX& x, const ZZ_pX& a, long b); void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b); void sub(ZZ_pX& x, long a, const ZZ_pX& b); void sub(ZZ_pX& x, const ZZ_p& a, const ZZ_pX& b); inline ZZ_pX operator+(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator+(const ZZ_pX& a, const ZZ_p& b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator+(const ZZ_pX& a, long b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator+(const ZZ_p& a, const ZZ_pX& b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator+(long a, const ZZ_pX& b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(const ZZ_pX& a, const ZZ_p& b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(const ZZ_pX& a, long b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(const ZZ_p& a, const ZZ_pX& b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(long a, const ZZ_pX& b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator+=(ZZ_pX& x, const ZZ_pX& b) { add(x, x, b); return x; } inline ZZ_pX& operator+=(ZZ_pX& x, const ZZ_p& b) { add(x, x, b); return x; } inline ZZ_pX& operator+=(ZZ_pX& x, long b) { add(x, x, b); return x; } inline ZZ_pX& operator-=(ZZ_pX& x, const ZZ_pX& b) { sub(x, x, b); return x; } inline ZZ_pX& operator-=(ZZ_pX& x, const ZZ_p& b) { sub(x, x, b); return x; } inline ZZ_pX& operator-=(ZZ_pX& x, long b) { sub(x, x, b); return x; } inline ZZ_pX operator-(const ZZ_pX& a) { ZZ_pX x; negate(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator++(ZZ_pX& x) { add(x, x, 1); return x; } inline void operator++(ZZ_pX& x, int) { add(x, x, 1); } inline ZZ_pX& operator--(ZZ_pX& x) { sub(x, x, 1); return x; } inline void operator--(ZZ_pX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a * b void sqr(ZZ_pX& x, const ZZ_pX& a); inline ZZ_pX sqr(const ZZ_pX& a) { ZZ_pX x; sqr(x, a); NTL_OPT_RETURN(ZZ_pX, x); } // x = a^2 void mul(ZZ_pX & x, const ZZ_pX& a, const ZZ_p& b); void mul(ZZ_pX& x, const ZZ_pX& a, long b); inline void mul(ZZ_pX& x, const ZZ_p& a, const ZZ_pX& b) { mul(x, b, a); } inline void mul(ZZ_pX& x, long a, const ZZ_pX& b) { mul(x, b, a); } inline ZZ_pX operator*(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator*(const ZZ_pX& a, const ZZ_p& b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator*(const ZZ_pX& a, long b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator*(const ZZ_p& a, const ZZ_pX& b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator*(long a, const ZZ_pX& b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator*=(ZZ_pX& x, const ZZ_pX& b) { mul(x, x, b); return x; } inline ZZ_pX& operator*=(ZZ_pX& x, const ZZ_p& b) { mul(x, x, b); return x; } inline ZZ_pX& operator*=(ZZ_pX& x, long b) { mul(x, x, b); return x; } void PlainMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // always uses the "classical" algorithm void PlainSqr(ZZ_pX& x, const ZZ_pX& a); // always uses the "classical" algorithm void FFTMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // always uses the FFT void FFTSqr(ZZ_pX& x, const ZZ_pX& a); // always uses the FFT void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n); // x = a * b % X^n inline ZZ_pX MulTrunc(const ZZ_pX& a, const ZZ_pX& b, long n) { ZZ_pX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(ZZ_pX, x); } void PlainMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n); void FFTMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n); void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n); // x = a^2 % X^n inline ZZ_pX SqrTrunc(const ZZ_pX& a, long n) { ZZ_pX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } void PlainSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n); void FFTSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n); void power(ZZ_pX& x, const ZZ_pX& a, long e); inline ZZ_pX power(const ZZ_pX& a, long e) { ZZ_pX x; power(x, a, e); NTL_OPT_RETURN(ZZ_pX, x); } // The following data structures and routines allow one // to hand-craft various algorithms, using the FFT convolution // algorithms directly. // Look in the file ZZ_pX.c for examples. // FFT representation of polynomials class FFTRep { public: long k; // a 2^k point representation long MaxK; // maximum space allocated long **tbl; long NumPrimes; void SetSize(long NewK); FFTRep(const FFTRep& R); FFTRep& operator=(const FFTRep& R); FFTRep() { k = MaxK = -1; tbl = 0; NumPrimes = 0; } FFTRep(INIT_SIZE_TYPE, long InitK) { k = MaxK = -1; tbl = 0; NumPrimes = 0; SetSize(InitK); } ~FFTRep(); }; void ToFFTRep(FFTRep& y, const ZZ_pX& x, long k, long lo, long hi); // computes an n = 2^k point convolution of x[lo..hi]. inline void ToFFTRep(FFTRep& y, const ZZ_pX& x, long k) { ToFFTRep(y, x, k, 0, deg(x)); } void RevToFFTRep(FFTRep& y, const vec_ZZ_p& x, long k, long lo, long hi, long offset); // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. void FromFFTRep(ZZ_pX& x, FFTRep& y, long lo, long hi); // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed // NOTE: this version destroys the data in y // non-destructive versions of the above void NDFromFFTRep(ZZ_pX& x, const FFTRep& y, long lo, long hi, FFTRep& temp); void NDFromFFTRep(ZZ_pX& x, const FFTRep& y, long lo, long hi); void RevFromFFTRep(vec_ZZ_p& x, FFTRep& y, long lo, long hi); // converts from FFT-representation to coefficient representation // using "inverted" evaluation points. // only the coefficients lo..hi are computed void FromFFTRep(ZZ_p* x, FFTRep& y, long lo, long hi); // convert out coefficients lo..hi of y, store result in x. // no normalization is done. // direct manipulation of FFT reps void mul(FFTRep& z, const FFTRep& x, const FFTRep& y); void sub(FFTRep& z, const FFTRep& x, const FFTRep& y); void add(FFTRep& z, const FFTRep& x, const FFTRep& y); void reduce(FFTRep& x, const FFTRep& a, long k); // reduces a 2^l point FFT-rep to a 2^k point FFT-rep void AddExpand(FFTRep& x, const FFTRep& a); // x = x + (an "expanded" version of a) // This data structure holds unconvoluted modular representations // of polynomials class ZZ_pXModRep { private: ZZ_pXModRep(const ZZ_pXModRep&); // disabled void operator=(const ZZ_pXModRep&); // disabled public: long n; long MaxN; long **tbl; long NumPrimes; void SetSize(long NewN); ZZ_pXModRep() { n = MaxN = 0; tbl = 0; NumPrimes = 0; } ZZ_pXModRep(INIT_SIZE_TYPE, long k) { n = MaxN = 0; tbl = 0; NumPrimes = 0; SetSize(k); } ~ZZ_pXModRep(); }; void ToZZ_pXModRep(ZZ_pXModRep& x, const ZZ_pX& a, long lo, long hi); void ToFFTRep(FFTRep& x, const ZZ_pXModRep& a, long k, long lo, long hi); // converts coefficients lo..hi to a 2^k-point FFTRep. // must have hi-lo+1 < 2^k /************************************************************* Division **************************************************************/ void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); // q = a/b, r = a%b void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); // q = a/b void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_p& b); void div(ZZ_pX& q, const ZZ_pX& a, long b); void rem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); // r = a%b long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZ_pX& a, const ZZ_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(ZZ_pX& x, const ZZ_pX& a, long m); // computes x = a^{-1} % X^m // constant term must be non-zero inline ZZ_pX InvTrunc(const ZZ_pX& a, long m) { ZZ_pX x; InvTrunc(x, a, m); NTL_OPT_RETURN(ZZ_pX, x); } // These always use "classical" arithmetic void PlainDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); void PlainDiv(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); void PlainRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); void PlainRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b, ZZVec& tmp); void PlainDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b, ZZVec& tmp); // These always use FFT arithmetic void FFTDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); void FFTDiv(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); void FFTRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); void PlainInvTrunc(ZZ_pX& x, const ZZ_pX& a, long m); // always uses "classical" algorithm // ALIAS RESTRICTION: input may not alias output void NewtonInvTrunc(ZZ_pX& x, const ZZ_pX& a, long m); // uses a Newton Iteration with the FFT. // ALIAS RESTRICTION: input may not alias output inline ZZ_pX operator/(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator/(const ZZ_pX& a, const ZZ_p& b) { ZZ_pX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator/(const ZZ_pX& a, long b) { ZZ_pX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator/=(ZZ_pX& x, const ZZ_p& b) { div(x, x, b); return x; } inline ZZ_pX& operator/=(ZZ_pX& x, long b) { div(x, x, b); return x; } inline ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pX& b) { div(x, x, b); return x; } inline ZZ_pX operator%(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; rem(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). inline ZZ_pX GCD(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; GCD(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b); // d = gcd(a,b), a s + b t = d void PlainXGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b); // same as above, but uses classical algorithm void PlainGCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // always uses "cdlassical" arithmetic class ZZ_pXMatrix { private: ZZ_pXMatrix(const ZZ_pXMatrix&); // disable ZZ_pX elts[2][2]; public: ZZ_pXMatrix() { } ~ZZ_pXMatrix() { } void operator=(const ZZ_pXMatrix&); ZZ_pX& operator() (long i, long j) { return elts[i][j]; } const ZZ_pX& operator() (long i, long j) const { return elts[i][j]; } }; void HalfGCD(ZZ_pXMatrix& M_out, const ZZ_pX& U, const ZZ_pX& V, long d_red); // deg(U) > deg(V), 1 <= d_red <= deg(U)+1. // // This computes a 2 x 2 polynomial matrix M_out such that // M_out * (U, V)^T = (U', V')^T, // where U', V' are consecutive polynomials in the Euclidean remainder // sequence of U, V, and V' is the polynomial of highest degree // satisfying deg(V') <= deg(U) - d_red. void XHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red); // same as above, except that U is replaced by U', and V by V' /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the ZZ_pXModulus data structure and associated routines below. void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f); // x = (a * b) % f inline ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f) { ZZ_pX x; MulMod(x, a, b, f); NTL_OPT_RETURN(ZZ_pX, x); } void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // x = a^2 % f inline ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_pX x; SqrMod(x, a, f); NTL_OPT_RETURN(ZZ_pX, x); } void MulByXMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // x = (a * X) mod f inline ZZ_pX MulByXMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_pX x; MulByXMod(x, a, f); NTL_OPT_RETURN(ZZ_pX, x); } void InvMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // x = a^{-1} % f, error is a is not invertible inline ZZ_pX InvMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_pX x; InvMod(x, a, f); NTL_OPT_RETURN(ZZ_pX, x); } long InvModStatus(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build ZZ_pXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class ZZ_pXModulus { public: ZZ_pXModulus() : UseFFT(0), n(-1) { } ~ZZ_pXModulus() { } // the following members may become private in future ZZ_pX f; // the modulus long UseFFT;// flag indicating whether FFT should be used. long n; // n = deg(f) long k; // least k s/t 2^k >= n long l; // least l s/t 2^l >= 2n-3 FFTRep FRep; // 2^k point rep of f // H = rev((rev(f))^{-1} rem X^{n-1}) FFTRep HRep; // 2^l point rep of H vec_ZZ_p tracevec; // mutable // but these will remain public ZZ_pXModulus(const ZZ_pX& ff); const ZZ_pX& val() const { return f; } operator const ZZ_pX& () const { return f; } }; inline long deg(const ZZ_pXModulus& F) { return F.n; } void build(ZZ_pXModulus& F, const ZZ_pX& f); // deg(f) > 0. void rem21(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); // x = a % f // deg(a) <= 2(n-1), where n = F.n = deg(f) void rem(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); // x = a % f, no restrictions on deg(a); makes repeated calls to rem21 inline ZZ_pX operator%(const ZZ_pX& a, const ZZ_pXModulus& F) { ZZ_pX x; rem(x, a, F); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pXModulus& F) { rem(x, x, F); return x; } void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pXModulus& F); void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pXModulus& F); inline ZZ_pX operator/(const ZZ_pX& a, const ZZ_pXModulus& F) { ZZ_pX x; div(x, a, F); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pXModulus& F) { div(x, x, F); return x; } void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F); // x = (a * b) % f // deg(a), deg(b) < n inline ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F) { ZZ_pX x; MulMod(x, a, b, F); NTL_OPT_RETURN(ZZ_pX, x); } void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); // x = a^2 % f // deg(a) < n inline ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pXModulus& F) { ZZ_pX x; SqrMod(x, a, F); NTL_OPT_RETURN(ZZ_pX, x); } void PowerMod(ZZ_pX& x, const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F); // x = a^e % f, e >= 0 inline ZZ_pX PowerMod(const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F) { ZZ_pX x; PowerMod(x, a, e, F); NTL_OPT_RETURN(ZZ_pX, x); } inline void PowerMod(ZZ_pX& x, const ZZ_pX& a, long e, const ZZ_pXModulus& F) { PowerMod(x, a, ZZ_expo(e), F); } inline ZZ_pX PowerMod(const ZZ_pX& a, long e, const ZZ_pXModulus& F) { ZZ_pX x; PowerMod(x, a, e, F); NTL_OPT_RETURN(ZZ_pX, x); } void PowerXMod(ZZ_pX& x, const ZZ& e, const ZZ_pXModulus& F); // x = X^e % f, e >= 0 inline ZZ_pX PowerXMod(const ZZ& e, const ZZ_pXModulus& F) { ZZ_pX x; PowerXMod(x, e, F); NTL_OPT_RETURN(ZZ_pX, x); } inline void PowerXMod(ZZ_pX& x, long e, const ZZ_pXModulus& F) { PowerXMod(x, ZZ_expo(e), F); } inline ZZ_pX PowerXMod(long e, const ZZ_pXModulus& F) { ZZ_pX x; PowerXMod(x, e, F); NTL_OPT_RETURN(ZZ_pX, x); } void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F); // x = (X + a)^e % f, e >= 0 inline ZZ_pX PowerXPlusAMod(const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F) { ZZ_pX x; PowerXPlusAMod(x, a, e, F); NTL_OPT_RETURN(ZZ_pX, x); } inline void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, long e, const ZZ_pXModulus& F) { PowerXPlusAMod(x, a, ZZ_expo(e), F); } inline ZZ_pX PowerXPlusAMod(const ZZ_p& a, long e, const ZZ_pXModulus& F) { ZZ_pX x; PowerXPlusAMod(x, a, e, F); NTL_OPT_RETURN(ZZ_pX, x); } // If you need to compute a * b % f for a fixed b, but for many a's // (for example, computing powers of b modulo f), it is // much more efficient to first build a ZZ_pXMultiplier B for b, // and then use the routine below. class ZZ_pXMultiplier { public: ZZ_pXMultiplier() : UseFFT(0) { } ZZ_pXMultiplier(const ZZ_pX& b, const ZZ_pXModulus& F); ~ZZ_pXMultiplier() { } // the following members may become private in the future ZZ_pX b; long UseFFT; FFTRep B1; FFTRep B2; // but this will remain public const ZZ_pX& val() const { return b; } }; void build(ZZ_pXMultiplier& B, const ZZ_pX& b, const ZZ_pXModulus& F); void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); inline ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F) { ZZ_pX x; MulMod(x, a, B, F); NTL_OPT_RETURN(ZZ_pX, x); } // x = (a * b) % f /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() inline ZZ_pX BuildFromRoots(const vec_ZZ_p& a) { ZZ_pX x; BuildFromRoots(x, a); NTL_OPT_RETURN(ZZ_pX, x); } void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a); // b = f(a) inline ZZ_p eval(const ZZ_pX& f, const ZZ_p& a) { ZZ_p x; eval(x, f, a); NTL_OPT_RETURN(ZZ_p, x); } void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a); // b[i] = f(a[i]) inline vec_ZZ_p eval(const ZZ_pX& f, const vec_ZZ_p& a) { vec_ZZ_p x; eval(x, f, a); NTL_OPT_RETURN(vec_ZZ_p, x); } void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b); // computes f such that f(a[i]) = b[i] inline ZZ_pX interpolate(const vec_ZZ_p& a, const vec_ZZ_p& b) { ZZ_pX x; interpolate(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } /***************************************************************** vectors of ZZ_pX's *****************************************************************/ typedef Vec vec_ZZ_pX; /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ // algorithms for computing g(h) mod f void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F); // x = g(h) mod f inline ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F) { ZZ_pX x; CompMod(x, g, h, F); NTL_OPT_RETURN(ZZ_pX, x); } void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& h, const ZZ_pXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3, const ZZ_pX& h, const ZZ_pXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If ZZ_pXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If ZZ_pXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, ZZ_pXArgBound = 0. // If a single h is going to be used with many g's // then you should build a ZZ_pXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If ZZ_pXArgBound > 0, a table of size less than m may be built. struct ZZ_pXArgument { vec_ZZ_pX H; }; NTL_THREAD_LOCAL extern long ZZ_pXArgBound; void build(ZZ_pXArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& H, const ZZ_pXModulus& F); inline ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pXArgument& H, const ZZ_pXModulus& F) { ZZ_pX x; CompMod(x, g, H, F); NTL_OPT_RETURN(ZZ_pX, x); } #ifndef NTL_TRANSITION void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); inline vec_ZZ_p UpdateMap(const vec_ZZ_p& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F) { vec_ZZ_p x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_ZZ_p, x); } #endif /* computes (a, b), (a, (b*X)%f), ..., (a, (b*X^{n-1})%f), where ( , ) denotes the vector inner product. This is really a "transposed" MulMod by B. */ void PlainUpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_pX& b, const ZZ_pX& f); // same as above, but uses only classical arithmetic void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F); inline vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F) { vec_ZZ_p x; ProjectPowers(x, a, k, h, F); NTL_OPT_RETURN(vec_ZZ_p, x); } // computes (a, 1), (a, h), ..., (a, h^{k-1} % f) // this is really a "transposed" compose. void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F); inline vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F) { vec_ZZ_p x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_ZZ_p, x); } // same as above, but uses a pre-computed ZZ_pXArgument inline void project(ZZ_p& x, const vec_ZZ_p& a, const ZZ_pX& b) { InnerProduct(x, a, b.rep); } inline ZZ_p project(const vec_ZZ_p& a, const ZZ_pX& b) { ZZ_p x; project(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m); // computes the minimum polynomial of a linealy generated sequence; // m is a bound on the degree of the polynomial; // required: a.length() >= 2*m inline ZZ_pX MinPolySeq(const vec_ZZ_p& a, long m) { ZZ_pX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(ZZ_pX, x); } void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); inline ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m) { ZZ_pX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } inline ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F) { ZZ_pX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // computes the monic minimal polynomial if (g mod f). // m = a bound on the degree of the minimal polynomial. // If this argument is not supplied, it defaults to deg(f). // The algorithm is probabilistic, always returns a divisor of // the minimal polynomial, and returns a proper divisor with // probability at most m/p. void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); inline ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m) { ZZ_pX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F) { MinPolyMod(h, g, F, F.n); } inline ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F) { ZZ_pX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // same as above, but guarantees that result is correct void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); inline ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m) { ZZ_pX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F) { IrredPolyMod(h, g, F, F.n); } inline ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F) { ZZ_pX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // same as above, but assumes that f is irreducible, // or at least that the minimal poly of g is itself irreducible. // The algorithm is deterministic (and is always correct). /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_ZZ_p& S, const ZZ_pX& f); inline vec_ZZ_p TraceVec(const ZZ_pX& f) { vec_ZZ_p x; TraceVec(x, f); NTL_OPT_RETURN(vec_ZZ_p, x); } void FastTraceVec(vec_ZZ_p& S, const ZZ_pX& f); void PlainTraceVec(vec_ZZ_p& S, const ZZ_pX& f); void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F); inline ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& F) { ZZ_p x; TraceMod(x, a, F); NTL_OPT_RETURN(ZZ_p, x); } void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f); inline ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_p x; TraceMod(x, a, f); NTL_OPT_RETURN(ZZ_p, x); } void ComputeTraceVec(const ZZ_pXModulus& F); void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f); inline ZZ_p NormMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_p x; NormMod(x, a, f); NTL_OPT_RETURN(ZZ_p, x); } void resultant(ZZ_p& rres, const ZZ_pX& a, const ZZ_pX& b); inline ZZ_p resultant(const ZZ_pX& a, const ZZ_pX& b) { ZZ_p x; resultant(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } void CharPolyMod(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& f); // g = char poly of (a mod f) inline ZZ_pX CharPolyMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_pX x; CharPolyMod(x, a, f); NTL_OPT_RETURN(ZZ_pX, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/ZZ_pXFactoring.h000644 000765 000024 00000015434 12377144457 017743 0ustar00shoupstaff000000 000000 #ifndef NTL_ZZ_pXFactoring__H #define NTL_ZZ_pXFactoring__H #include #include #include #include NTL_OPEN_NNS /************************************************************ factorization routines ************************************************************/ void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& f); inline vec_pair_ZZ_pX_long SquareFreeDecomp(const ZZ_pX& f) { vec_pair_ZZ_pX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_ZZ_p& x, const ZZ_pX& f); inline vec_ZZ_p FindRoots(const ZZ_pX& f) { vec_ZZ_p x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(ZZ_p& root, const ZZ_pX& f); inline ZZ_p FindRoot(const ZZ_pX& f) { ZZ_p x; FindRoot(x, f); return x; } // finds a single root of f. // assumes that f is monic and splits into distinct linear factors void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); inline vec_ZZ_pX SFBerlekamp(const ZZ_pX& f, long verbose=0) { vec_ZZ_pX x; SFBerlekamp(x, f, verbose); return x; } // Assumes f is square-free and monic. // returns list of factors of f. // Uses "Berlekamp" appraoch. void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose=0); inline vec_pair_ZZ_pX_long berlekamp(const ZZ_pX& f, long verbose=0) { vec_pair_ZZ_pX_long x; berlekamp(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Berlekamp" appraoch. NTL_THREAD_LOCAL extern long ZZ_pX_BlockingFactor; // Controls GCD blocking for DDF. void DDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h, long verbose=0); inline vec_pair_ZZ_pX_long DDF(const ZZ_pX& f, const ZZ_pX& h, long verbose=0) { vec_pair_ZZ_pX_long x; DDF(x, f, h, verbose); return x; } // Performs distinct-degree factorization. // Assumes f is monic and square-free, and h = X^p mod f // Obsolete: see NewDDF, below. NTL_THREAD_LOCAL extern long ZZ_pX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF NTL_THREAD_LOCAL extern char ZZ_pX_stem[]; // Determines filename stem for external storage in NewDDF. NTL_THREAD_LOCAL extern double ZZ_pXFileThresh; // external files are used for baby/giant steps if size // of these tables exceeds ZZ_pXFileThresh KB. void NewDDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h, long verbose=0); inline vec_pair_ZZ_pX_long NewDDF(const ZZ_pX& f, const ZZ_pX& h, long verbose=0) { vec_pair_ZZ_pX_long x; NewDDF(x, f, h, verbose); return x; } // same as above, but uses baby-step/giant-step method void EDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& b, long d, long verbose=0); inline vec_ZZ_pX EDF(const ZZ_pX& f, const ZZ_pX& b, long d, long verbose=0) { vec_ZZ_pX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); inline vec_ZZ_pX RootEDF(const ZZ_pX& f, long verbose=0) { vec_ZZ_pX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); inline vec_ZZ_pX SFCanZass(const ZZ_pX& f, long verbose=0) { vec_ZZ_pX x; SFCanZass(x, f, verbose); return x; } // Assumes f is monic and square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose=0); inline vec_pair_ZZ_pX_long CanZass(const ZZ_pX& f, long verbose=0) { vec_pair_ZZ_pX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v); inline ZZ_pX mul(const vec_pair_ZZ_pX_long& v) { ZZ_pX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const ZZ_pX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const ZZ_pX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const ZZ_pX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(ZZ_pX& f, long n); inline ZZ_pX BuildIrred_ZZ_pX(long n) { ZZ_pX x; BuildIrred(x, n); NTL_OPT_RETURN(ZZ_pX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g); inline ZZ_pX BuildRandomIrred(const ZZ_pX& g) { ZZ_pX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(ZZ_pX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F); // same as above, but uses a slightly faster probabilistic algorithm // the return value may be 0 or may be too big, but for large p // (relative to n), this happens with very low probability. void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& b); inline ZZ_pX TraceMap(const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& b) { ZZ_pX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) void PowerCompose(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F); inline ZZ_pX PowerCompose(const ZZ_pX& a, long d, const ZZ_pXModulus& F) { ZZ_pX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/c_lip.h000644 000765 000024 00000044431 12377144460 016153 0ustar00shoupstaff000000 000000 typedef long * _ntl_verylong; #if (defined(NTL_AVOID_FLOAT) && defined(NTL_LONG_LONG)) #error "at most one of NTL_AVOID_FLOAT NTL_LONG_LONG allowed" #endif #define NTL_NBITS NTL_NBITS_MAX #define NTL_RADIX (1L<>1) #define NTL_RADIXM (NTL_RADIX-1) #define NTL_RADIXROOT (1L<= b >= 0 */ void _ntl_zsmul(_ntl_verylong a, long d, _ntl_verylong *b); /* *b = d * a */ void _ntl_zmul(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *c); /* *c = a * b */ void _ntl_zsq(_ntl_verylong a, _ntl_verylong *c); /* *c = a * a */ long _ntl_zsdiv(_ntl_verylong a, long b, _ntl_verylong *q); /* (*q) = floor(a/b) and a - floor(a/b)*(*q) is returned; error is raised if b == 0; if b does not divide a, then sign(*q) == sign(b) */ void _ntl_zdiv(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *q, _ntl_verylong *r); /* (*q) = floor(a/b) and (*r) = a - floor(a/b)*(*q); error is raised if b == 0; if b does not divide a, then sign(*q) == sign(b) */ void _ntl_zmultirem(_ntl_verylong a, long n, long* dd, long* rr); void _ntl_zmultirem2(_ntl_verylong a, long n, long* dd, double **tbl, long* rr); /* rr[i] = a % dd[i], i = 0..n-1; assumes a >= 0, 0 < dd[i] < NTL_RADIX _ntl_zmultirem2 takes an extra argument, tbl, which contains pre-computed residues of powers of RADIX */ void _ntl_zmultirem3(_ntl_verylong a, long n, long* dd, long **tbl, long* rr); /* same as above, but tbl has different type */ long _ntl_zsfastrem(_ntl_verylong a, long d); /* return a % d; assumes a >= 0, 0 < d < NTL_RADIX */ void _ntl_zmod(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *r); /* same as _ntl_zdiv, but only remainder is computed */ long _ntl_zsmod(_ntl_verylong a, long d); /* same as _ntl_zsdiv, but only remainder is computed */ void _ntl_zquickmod(_ntl_verylong *r, _ntl_verylong b); /* *r = *r % b; assumes b > 0 and *r >= 0; The division is performed in place (but may sometimes cause *r to grow by one digit) */ void _ntl_zsaddmul(_ntl_verylong x, long y, _ntl_verylong *ww); /* *ww += x*y */ void _ntl_zaddmul(_ntl_verylong x, _ntl_verylong y, _ntl_verylong *ww); /* *ww += x*y */ void _ntl_zssubmul(_ntl_verylong x, long y, _ntl_verylong *ww); /* *ww -= x*y */ void _ntl_zsubmul(_ntl_verylong x, _ntl_verylong y, _ntl_verylong *ww); /* *ww -= x*y */ /******************************************************************** Shifting and bit manipulation *********************************************************************/ void _ntl_z2mul(_ntl_verylong n, _ntl_verylong *a); /* *a = 2 * n */ long _ntl_z2div(_ntl_verylong n, _ntl_verylong *a); /* *a = sign(n) * (|n|/2) */ void _ntl_zlshift(_ntl_verylong n, long k, _ntl_verylong *a); /* *a = sign(n) * (|n| << k); shift is in reverse direction for negative k */ void _ntl_zrshift(_ntl_verylong n, long k, _ntl_verylong *a); /* *a = sign(n) * (|n| >> k); shift is in reverse direction for negative k */ long _ntl_zmakeodd(_ntl_verylong *n); /* if (n != 0) *n = m; return (k such that n == 2 ^ k * m with m odd); else return (0); */ long _ntl_znumtwos(_ntl_verylong n); /* return largest e such that 2^e divides n, or zero if n is zero */ long _ntl_zodd(_ntl_verylong a); /* returns 1 if n is odd and 0 if it is even */ long _ntl_zbit(_ntl_verylong a, long p); /* returns p-th bit of a, where the low order bit is indexed by 0; p out of range returns 0 */ long _ntl_zsetbit(_ntl_verylong *a, long p); /* returns original value of p-th bit of |a|, and replaces p-th bit of a by 1 if it was zero; error if p < 0 */ long _ntl_zswitchbit(_ntl_verylong *a, long p); /* returns original value of p-th bit of |a|, and switches the value of p-th bit of a; p starts counting at 0; error if p < 0 */ void _ntl_zlowbits(_ntl_verylong a, long k, _ntl_verylong *b); /* places k low order bits of |a| in b */ long _ntl_zslowbits(_ntl_verylong a, long k); /* returns k low order bits of |a| */ long _ntl_zweights(long a); /* returns Hamming weight of |a| */ long _ntl_zweight(_ntl_verylong a); /* returns Hamming weight of |a| */ void _ntl_zand(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *c); /* c gets bit pattern `bits of |a|` and `bits of |b|` */ void _ntl_zor(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *c); /* c gets bit pattern `bits of |a|` inclusive or `bits of |b|` */ void _ntl_zxor(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *c); /* c gets bit pattern `bits of |a|` exclusive or `bits of |b|` */ /************************************************************************ Comparison *************************************************************************/ long _ntl_zcompare(_ntl_verylong a, _ntl_verylong b); /* if (a > b) return (1); if (a == b) return (0); if (a < b) return (-1); */ long _ntl_zscompare(_ntl_verylong a, long b); /* single-precision version of the above */ long _ntl_ziszero (_ntl_verylong a); /* test for 0 */ long _ntl_zsign(_ntl_verylong a); /* if (a > 0) return (1); if (a == 0) return (0); if (a < 0) return (-1); */ void _ntl_zabs(_ntl_verylong *a); /* *a = |a| */ void _ntl_znegate(_ntl_verylong *a); /* *a = -a */ void _ntl_zcopy(_ntl_verylong a, _ntl_verylong *b); /* *b = a; space is allocated */ void _ntl_zcopy1(_ntl_verylong a, _ntl_verylong *b); /* *b = a; space not necessarily allocated */ void _ntl_zswap(_ntl_verylong *a, _ntl_verylong *b); /* swap a and b (by swaping pointers) */ long _ntl_z2log(_ntl_verylong a); /* number of bits in |a|; returns 0 if a = 0 */ long _ntl_z2logs(long a); /* single-precision version of the above */ /******************************************************************** Conversion *********************************************************************/ void _ntl_zzero(_ntl_verylong *a); /* *a = 0; space is allocated */ void _ntl_zzero1(_ntl_verylong *a); /* *a = 0; space not necessarily allocated */ void _ntl_zone(_ntl_verylong *a); /* *a = 1 */ void _ntl_zintoz(long d, _ntl_verylong *a); /* *a = d; space is allocated */ void _ntl_zintoz1(long d, _ntl_verylong *a); /* *a = d; space not necessarily allocated */ void _ntl_zuintoz(unsigned long d, _ntl_verylong *a); /* *a = d; space is allocated */ long _ntl_ztoint(_ntl_verylong a); /* converts a to a long; overflow results in value mod 2^{NTL_BITS_PER_LONG}. */ unsigned long _ntl_ztouint(_ntl_verylong a); /* converts a to a long; overflow results in value mod 2^{NTL_BITS_PER_LONG}. */ double _ntl_zdoub(_ntl_verylong n); /* converts a to a double; no overflow check */ long _ntl_zround_correction(_ntl_verylong a, long k, long residual); /* k >= 1, |a| >= 2^k, and residual is 0, 1, or -1. The result is what we should add to (a >> k) to round x = a/2^k to the nearest integer using IEEE-like rounding rules (i.e., round to nearest, and round to even to break ties). The result is either 0 or sign(a). If residual is not zero, it is as if x were replaced by x' = x + residual*2^{-(k+1)}. This can be used to break ties when x is exactly half way between two integers. */ double _ntl_zlog(_ntl_verylong a); /* computes log(a), protecting against overflow */ void _ntl_zdoubtoz(double a, _ntl_verylong *x); /* x = floor(a); */ /************************************************************************ Square roots *************************************************************************/ long _ntl_zsqrts(long n); /* return floor(sqrt(n)); error raised in n < 0 */ void _ntl_zsqrt(_ntl_verylong n, _ntl_verylong *r); /* *r = floor(sqrt(n)); error raised in n < 0 */ /********************************************************************* Exponentiation **********************************************************************/ void _ntl_zexp(_ntl_verylong a, long e, _ntl_verylong *b); /* *b = a^e; error raised if e < 0 */ void _ntl_zexps(long a, long e, _ntl_verylong *b); /* *b = a^e; error raised if e < 0 */ /********************************************************************* Modular Arithmetic Addition, subtraction, multiplication, squaring division, inversion, and exponentiation modulo a positive modulus n, where all operands (except for the exponent in exponentiation) and results are in the range [0, n-1]. ***********************************************************************/ void _ntl_zaddmod(_ntl_verylong a, _ntl_verylong b, _ntl_verylong n, _ntl_verylong *c); /* *c = (a + b) % n */ void _ntl_zsubmod(_ntl_verylong a, _ntl_verylong b, _ntl_verylong n, _ntl_verylong *c); /* *c = (a - b) % n */ void _ntl_zsmulmod(_ntl_verylong a, long b, _ntl_verylong n, _ntl_verylong *c); /* *c = (a * b) % n */ void _ntl_zmulmod(_ntl_verylong a, _ntl_verylong b, _ntl_verylong n, _ntl_verylong *c); /* *c = (a * b) % n */ void _ntl_zsqmod(_ntl_verylong a, _ntl_verylong n, _ntl_verylong *c); /* *c = (a ^ 2) % n */ void _ntl_zinvmod(_ntl_verylong a, _ntl_verylong n, _ntl_verylong *c); /* *c = (1 / a) % n; error raised if gcd(b, n) != 1 */ void _ntl_zpowermod(_ntl_verylong g, _ntl_verylong e, _ntl_verylong F, _ntl_verylong *h); /* *b = (a ^ e) % n; */ /************************************************************************** Euclidean Algorithms ***************************************************************************/ void _ntl_zgcd(_ntl_verylong m1, _ntl_verylong m2, _ntl_verylong *r); /* *r = greatest common divisor of m1 and m2; uses binary gcd algorithm */ void _ntl_zexteucl(_ntl_verylong a, _ntl_verylong *xa, _ntl_verylong b, _ntl_verylong *xb, _ntl_verylong *d); /* *d = a * *xa + b * *xb = gcd(a, b); sets *d, *xa and *xb given a and b; uses Lehmer`s trick */ long _ntl_zinv(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *c); /* if (a and b coprime) { *c = inv; return(0); } else { *c = gcd(a, b); return(1); } where inv is such that (inv * a) == 1 mod b; error raised if b <= 1 or a < 0 or a >= b */ long _ntl_zxxratrecon(_ntl_verylong x, _ntl_verylong m, _ntl_verylong a_bound, _ntl_verylong b_bound, _ntl_verylong *a, _ntl_verylong *b); /* rational reconstruction: see doc in ZZ.txt */ /********************************************************************** Storage Allocation These routines use malloc and free. ***********************************************************************/ long _ntl_zmaxalloc(_ntl_verylong x); /* max allocation request, possibly rounded up a bit */ void _ntl_zsetlength(_ntl_verylong *v, long len); /* Allocates enough space to hold a len-digit number, where each digit has NTL_NBITS bits. If space must be allocated, space for one extra digit is always allocated. */ void _ntl_zfree(_ntl_verylong *x); /* Free's space held by x, and sets x back to 0. */ /******************************************************************* Special routines ********************************************************************/ long _ntl_zsize(_ntl_verylong n); long _ntl_zisone(_ntl_verylong n); long _ntl_zdigit(_ntl_verylong a, long i); long _ntl_zsptest(_ntl_verylong a); long _ntl_zwsptest(_ntl_verylong a); long _ntl_zcrtinrange(_ntl_verylong g, _ntl_verylong a); void _ntl_zfrombytes(_ntl_verylong *x, const unsigned char *p, long n); void _ntl_zbytesfromz(unsigned char *p, _ntl_verylong a, long nn); long _ntl_zblock_construct_alloc(_ntl_verylong *x, long d, long n); void _ntl_zblock_construct_set(_ntl_verylong x, _ntl_verylong *y, long i); long _ntl_zblock_destroy(_ntl_verylong x); long _ntl_zblock_storage(long d); void _ntl_crt_struct_init(void **crt_struct, long n, _ntl_verylong p, const long *primes); void _ntl_crt_struct_insert(void *crt_struct, long i, _ntl_verylong m); void _ntl_crt_struct_free(void *crt_struct); void _ntl_crt_struct_eval(void *crt_struct, _ntl_verylong *t, const long *a); long _ntl_crt_struct_special(void *crt_struct); void _ntl_rem_struct_init(void **rem_struct, long n, _ntl_verylong p, const long *primes); void _ntl_rem_struct_free(void *rem_struct); void _ntl_rem_struct_eval(void *rem_struct, long *x, _ntl_verylong a); #define NTL_crt_struct_eval _ntl_crt_struct_eval #define NTL_crt_struct_free _ntl_crt_struct_free #define NTL_crt_struct_init _ntl_crt_struct_init #define NTL_crt_struct_insert _ntl_crt_struct_insert #define NTL_crt_struct_special _ntl_crt_struct_special #define NTL_rem_struct_eval _ntl_rem_struct_eval #define NTL_rem_struct_free _ntl_rem_struct_free #define NTL_rem_struct_init _ntl_rem_struct_init #define NTL_verylong _ntl_verylong #define NTL_z2log _ntl_z2log #define NTL_zabs _ntl_zabs #define NTL_zadd _ntl_zadd #define NTL_zaddmod _ntl_zaddmod #define NTL_zand _ntl_zand #define NTL_zbit _ntl_zbit #define NTL_zblock_construct_alloc _ntl_zblock_construct_alloc #define NTL_zblock_construct_set _ntl_zblock_construct_set #define NTL_zblock_destroy _ntl_zblock_destroy #define NTL_zblock_storage _ntl_zblock_storage #define NTL_zbytesfromz _ntl_zbytesfromz #define NTL_zcompare _ntl_zcompare #define NTL_zcopy _ntl_zcopy1 #define NTL_zcrtinrange _ntl_zcrtinrange #define NTL_zdigit _ntl_zdigit #define NTL_zdiv _ntl_zdiv #define NTL_zdoub _ntl_zdoub #define NTL_zdoubtoz _ntl_zdoubtoz #define NTL_zexp _ntl_zexp #define NTL_zexps _ntl_zexps #define NTL_zexteucl _ntl_zexteucl #define NTL_zfree _ntl_zfree #define NTL_zfrombytes _ntl_zfrombytes #define NTL_zgcd _ntl_zgcd #define NTL_zintoz _ntl_zintoz1 #define NTL_zinv _ntl_zinv #define NTL_zinvmod _ntl_zinvmod #define NTL_zisone _ntl_zisone #define NTL_ziszero _ntl_ziszero #define NTL_zlog _ntl_zlog #define NTL_zlowbits _ntl_zlowbits #define NTL_zlshift _ntl_zlshift #define NTL_zmakeodd _ntl_zmakeodd #define NTL_zmod _ntl_zmod #define NTL_zmul _ntl_zmul #define NTL_zmulmod _ntl_zmulmod #define NTL_znegate _ntl_znegate #define NTL_znumtwos _ntl_znumtwos #define NTL_zodd _ntl_zodd #define NTL_zone _ntl_zone #define NTL_zor _ntl_zor #define NTL_zpowermod _ntl_zpowermod #define NTL_zquickmod _ntl_zquickmod #define NTL_zround_correction _ntl_zround_correction #define NTL_zrshift _ntl_zrshift #define NTL_zsadd _ntl_zsadd #define NTL_zscompare _ntl_zscompare #define NTL_zsdiv _ntl_zsdiv #define NTL_zsetbit _ntl_zsetbit #define NTL_zmaxalloc _ntl_zmaxalloc #define NTL_zsetlength _ntl_zsetlength #define NTL_zsign _ntl_zsign #define NTL_zsize _ntl_zsize #define NTL_zslowbits _ntl_zslowbits #define NTL_zsmod _ntl_zsmod #define NTL_zsmul _ntl_zsmul #define NTL_zsmulmod _ntl_zsmulmod #define NTL_zsptest _ntl_zsptest #define NTL_zsq _ntl_zsq #define NTL_zsqmod _ntl_zsqmod #define NTL_zsqrt _ntl_zsqrt #define NTL_zsqrts _ntl_zsqrts #define NTL_zsub _ntl_zsub #define NTL_zsubmod _ntl_zsubmod #define NTL_zsubpos _ntl_zsubpos #define NTL_zswap _ntl_zswap #define NTL_zswitchbit _ntl_zswitchbit #define NTL_ztoint _ntl_ztoint #define NTL_ztouint _ntl_ztouint #define NTL_zuintoz _ntl_zuintoz #define NTL_zweight _ntl_zweight #define NTL_zweights _ntl_zweights #define NTL_zwsptest _ntl_zwsptest #define NTL_zxor _ntl_zxor #define NTL_zxxratrecon _ntl_zxxratrecon #define NTL_zzero _ntl_zzero1 #define NTL_zsaddmul _ntl_zsaddmul #define NTL_zaddmul _ntl_zaddmul #define NTL_zssubmul _ntl_zssubmul #define NTL_zsubmul _ntl_zsubmul ntl-6.2.1/include/NTL/config.h000644 000765 000024 00000034222 12377144460 016327 0ustar00shoupstaff000000 000000 #ifndef NTL_config__H #define NTL_config__H /************************************************************************* NTL Configuration File ---------------------- This file may be modified prior to building NTL so as to specify some basic configuration options, and to customize how code is generated so as to improve performance. The Basic Configuration Options must be set by hand. If you use the configuration wizard, then these flags should be set before the installation process begins; there values will be retained by the wizard. The Performance Options can be set either by hand, by editing this file, or (on most Unix platforms) can be set automatically using the configuration wizard which runs when NTL is installed. All NTL header files include this file. By setting these flags here, instead of on the compiler command line, it is easier to guarantee that NTL library and client code use consistent settings. How to do it ------------ To set a flag, just replace the pre-processor directive 'if 0' by 'if 1' for that flag, which causes the appropriate macro to be defined. Of course, to unset a flag, just replace the 'if 1' by an 'if 0'. You can also do this more conveniently via the command line using the configure script. *************************************************************************/ /************************************************************************* * * Basic Configuration Options * *************************************************************************/ /* None of these flags are set by the configuration wizard; * they must be set by hand, before installation begins. */ #if 1 #define NTL_STD_CXX /* * Use this flag if you want to use the "Standard C++" version of NTL. * In this version, all of NTL is "wrapped" inside the namespace NTL, * and are no longer directly accessible---you must either use * explicit qualification, or using directives, or using declarations. * However, note that all names that begin with "NTL_" are macros, * and as such do not belong to any namespace. * Additionally, instead of including the standard headers * , , and , the standard headers * , , and are included. * These "wrap" some (but not all) names in namespace std. * Also, the 'nothrow' version on the 'new' operator is used. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* The following three flags may be used if you want to use some * of the features of Standard C++, but your compiler is deficient. * Instead of setting the NTL_STD_CXX, you can set any subset * of the these three. Setting all three of these flags is equivalent * to setting NTL_STD_CXX. No harm is done if NTL_STD_CXX is set * and some of the following three flags are set. * * To re-build after changing any of these flags: rm *.o; make ntl.a */ #if 0 #define NTL_PSTD_NNS /* Set if NTL library components are to be wrapped in namespace 'NTL'. */ #endif #if 0 #define NTL_PSTD_NHF /* Set if you want to use the new header files , , and * , instead of the traditional header files , * , and . * If new header files are used, then it is assumed that all standard * library components are wrapped in namespace std; otherwise, * it is assumed that all standard library components are in the * global namespace. * * Also, when set, some internal NTL files use the header * in place of . */ #endif #if 0 #define NTL_PSTD_NTN /* Set if you want to use the 'nothrow' version of new. */ #endif #if 0 #define NTL_GMP_LIP /* * Use this flag if you want to use GMP as the long integer package. * This can result in significantly faster code on some platforms. * It requires that the GMP package (version >= 3.1) has already been * installed. You will also have to set the variables GMP_OPT_INCDIR, * GMP_OPT_LIBDIR, GMP_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GMP_LIP=on * to that script. * * Beware that setting this flag can break some very old NTL codes. * * To re-build after changing this flag: * rm *.o; make setup3; make ntl.a * You may also have to edit the makefile to modify the variables * GMP_OPT_INCDIR, GMP_OPT_LIBDIR, and GMP_OPT_LIB. */ #endif #if 0 #define NTL_GF2X_LIB /* * Use this flag if you want to use the gf2x library for * faster GF2X arithmetic. * This can result in significantly faster code, especially * when working with polynomials of huge degree. * You will also have to set the variables GF2X_OPT_INCDIR, * GF2X_OPT_LIBDIR, GF2X_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GF2X_LIB=on * to that script. * * To re-build after changing this flag: * rm GF2X.o; GF2X1.o; make ntl.a * You may also have to edit the makefile to modify the variables * GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, and GF2X_OPT_LIB. */ #endif #if 0 #define NTL_LONG_LONG_TYPE long long /* * If you set the flag NTL_LONG_LONG, then the value of * NTL_LONG_LONG_TYPE will be used * to declare 'double word' signed integer types. * Irrelevant when NTL_GMP_LIP is set. * If left undefined, some "ifdef magic" will attempt * to find the best choice for your platform, depending * on the compiler and wordsize. On 32-bit machines, * this is usually 'long long'. * * To re-build after changing this flag: rm lip.o; make ntl.a */ #endif #if 0 #define NTL_UNSIGNED_LONG_LONG_TYPE unsigned long long /* * If you set the flag NTL_SPMM_ULL, then the value of * NTL_UNSIGNED_LONG_LONG_TYPE will be used * to declare 'double word' unsigned integer types. * If left undefined, some "ifdef magic" will attempt * to find the best choice for your platform, depending * on the compiler and wordsize. On 32-bit machines, * this is usually 'unsigned long long'. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_CLEAN_INT /* * This will disallow the use of some non-standard integer arithmetic * that may improve performance somewhat. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_CLEAN_PTR /* * This will disallow the use of some non-standard pointer arithmetic * that may improve performance somewhat. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_RANGE_CHECK /* * This will generate vector subscript range-check code. * Useful for debugging, but it slows things down of course. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_NO_INIT_TRANS /* * Without this flag, NTL uses a special code sequence to avoid * copying large objects in return statements. However, if your * compiler optimizes away the return of a *named* local object, * this is not necessary, and setting this flag will result * in *slightly* more compact and efficient code. Although * the emeriging C++ standard allows compilers to perform * this optimization, I know of none that currently do. * Most will avoid copying *temporary* objects in return statements, * and NTL's default code sequence exploits this fact. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_X86_FIX /* * Forces the "x86 floating point fix", overriding the default behavior. * By default, NTL will apply the "fix" if it looks like it is * necessary, and if knows how to fix it. * The problem addressed here is that x86 processors sometimes * run in a mode where FP registers have more precision than doubles. * This will cause code in quad_float.c some trouble. * NTL can normally correctly detect the problem, and fix it, * so you shouldn't need to worry about this or the next flag. * To re-build after changing this flag: rm quad_float.o; make ntl.a * */ #elif 0 #define NTL_NO_X86_FIX /* * Forces no "x86 floating point fix", overriding the default behavior. * To re-build after changing this flag: rm quad_float.o; make ntl.a */ #endif /************************************************************************* * * Performance Options * *************************************************************************/ /* One can choose one of three different stragtegies for long integer * arithmetic: the default, NTL_LONG_LONG, or NTL_AVOID_FLOAT. * The configuration wizard will choose among them. * */ #if 0 #define NTL_LONG_LONG /* * * For platforms that support it, this flag can be set to cause * the low-level multiplication code to use the type "long long", * which may yield a significant performance gain, * but on others, it can yield no improvement and can even * slow things down. * * * See below (NTL_LONG_LONG_TYPE) for how to use a type name * other than "long long". * * If you set NTL_LONG_LONG, you might also want to set * the flag NTL_TBL_REM (see below). * * To re-build after changing this flag: rm lip.o; make ntl.a */ #elif 0 #define NTL_AVOID_FLOAT /* * * On machines with slow floating point or---more comminly---slow int/float * conversions, this flag can lead to faster code. * * If you set NTL_AVOID_FLOAT, you should probably also * set NTL_TBL_REM (see below). * * To re-build after changing this flag: rm lip.o; make ntl.a */ #endif /* There are four strategies to implmement single-precision * modular multiplication with precondinition (see the MulModPrecon * function in the ZZ module): the default, NTL_SPMM_UL, and NTL_SPMM_ULL, * and NTL_SPMM_ASM. * This plays a crucial role in the "small prime FFT" used to * implement polynomial arithmetic, and in other CRT-based methods * (such as linear algebra over ZZ), as well as polynomial and matrix * arithmetic over zz_p. */ #if 0 #define NTL_SPMM_UL /* The default MulModPrecon implementation uses a mix of * int and float arithmetic, which may be slow on certain machines. * This flag causes an "all integer" implementation to be used. * It is entirely portable. * To re-build after changing this flag: rm *.o; make ntl.a */ #elif 0 #define NTL_SPMM_ULL /* Like this previous flag, this also causes an "all integer" * implementation of MulModPrecon to be used. * It us usually a faster implementation, * but it is not enturely portable. * It relies on double-word unsigned multiplication * (see NTL_UNSIGNED_LONG_LONG_TYPE above). * * To re-build after changing this flag: rm *.o; make ntl.a */ #elif 0 #define NTL_SPMM_ASM /* Like this previous two flag, this also causes an "all integer" * implementation of MulModPrecon to be used. * It relies assembler code to do double-word unsigned multiplication. * This is only supported on a select mechines under GCC. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* * The following two flags provide additional control for how the * FFT modulo single-precision primes is implemented. */ #if 0 #define NTL_FFT_BIGTAB /* * Precomputed tables are used to store all the roots of unity * used in an FFT computation for the first NTL_FFT_BIGTAB_LIMIT * FFT primes (the latter is defined in FFT.h). This can * lead to significant time savings but at the const of some space: * in the worst case, the precomputed tables will take of space * log_2(NTL_FFT_BUGTAB_LIMIT) * M, where M is roughly the maxmimum * space occupied by any one polynomial that was involved in an * FFT computation (this could be a polynomial over zz_p, ZZ_p, or ZZ). * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_FFT_LAZYMUL /* * This flag only has an effect when combined with the NTL_FFT_BIGTAB * flag, and either the NTL_SPMM_ULL or NTL_SPMM_ASM flags. * When set, a "lazy multiplication" strategy due to David Harvey: * see his paper "FASTER ARITHMETIC FOR NUMBER-THEORETIC TRANSFORMS". * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* The next five flags NTL_AVOID_BRANCHING, NTL_TBL_REM, * NTL_GF2X_ALTCODE, NTL_GF2X_ALTCODE1, and NTL_GF2X_NOINLINE * are also set by the configuration wizard. */ #if 0 #define NTL_AVOID_BRANCHING /* * With this option, branches are replaced at several * key points with equivalent code using shifts and masks. * It may speed things up on machines with * deep pipelines and high branch penalities. * This flag mainly affects the implementation of the * single-precision modular arithmetic routines. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_TBL_REM /* * * With this flag, some divisions are avoided in the * ZZ_pX multiplication routines. If you use the NTL_AVOID_FLOAT * or NTL_LONG_LONG flags, then you should probably use this one too. * * Irrelevent when NTL_GMP_LIP is set. * * To re-build after changing this flag: * rm lip.o; make ntl.a */ #endif #if 0 #define NTL_GF2X_ALTCODE /* * With this option, the default strategy for implmenting low-level * GF2X multiplication is replaced with an alternative strategy. * This alternative strategy seems to work better on RISC machines * with deep pipelines and high branch penalties (like a powerpc), * but does no better (or even worse) on x86s. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #elif 0 #define NTL_GF2X_ALTCODE1 /* * Yest another alternative strategy for implementing GF2X * multiplication. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #endif #if 0 #define NTL_GF2X_NOINLINE /* * By default, the low-level GF2X multiplication routine in inlined. * This can potentially lead to some trouble on some platforms, * and you can override the default by setting this flag. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #endif /* The following flag is not set by the configuration wizard; its use * is not generally recommended. */ #endif ntl-6.2.1/include/NTL/ctools.h000644 000765 000024 00000015531 12377144457 016375 0ustar00shoupstaff000000 000000 #ifndef NTL_ctools__H #define NTL_ctools__H #include #include /* * Resolve double-word integer types. * * Unfortunately, there is no "standard" way to do this. * On 32-bit machines, 'long long' usually works (but not * on MSVC++ or BORLAND), and on 64-bit machines, there is * no standard. However, most compilers do offer *some* * non-standard double-word type. * * Note that C99 creates a standard header , * but it is not clear how widely this is implemented yet, * and for example, GCC does not provide a type int128_t * in on 64-bit machines. */ #if (defined(NTL_LONG_LONG_TYPE)) #define NTL_LL_TYPE NTL_LONG_LONG_TYPE #elif (NTL_BITS_PER_LONG == 64 && defined(__GNUC__)) #define NTL_LL_TYPE __int128_t #elif (NTL_BITS_PER_LONG == 32 && (defined(_MSC_VER) || defined(__BORLANDC__))) #define NTL_LL_TYPE __int64 #elif (NTL_BITS_PER_LONG == 64 && (defined(_MSC_VER) || defined(__BORLANDC__))) #define NTL_LL_TYPE __int128 #endif #if (!defined(NTL_LL_TYPE)) #define NTL_LL_TYPE long long #endif #if (defined(NTL_UNSIGNED_LONG_LONG_TYPE)) #define NTL_ULL_TYPE NTL_UNSIGNED_LONG_LONG_TYPE #elif (NTL_BITS_PER_LONG == 64 && defined(__GNUC__)) #define NTL_ULL_TYPE __uint128_t #elif (NTL_BITS_PER_LONG == 32 && (defined(_MSC_VER) || defined(__BORLANDC__))) #define NTL_ULL_TYPE unsigned __int64 #elif (NTL_BITS_PER_LONG == 64 && (defined(_MSC_VER) || defined(__BORLANDC__))) #define NTL_ULL_TYPE unsigned __int128 #endif #if (!defined(NTL_ULL_TYPE)) #define NTL_ULL_TYPE unsigned long long #endif /********************************************************/ #define NTL_OVFBND (1L << (NTL_BITS_PER_LONG-4)) /* * NTL_OVFBND is the general bound used throughout NTL to keep various * integer values comfortably bounded away from an integer overflow * condition. Do not change this value! */ #if ((NTL_BITS_PER_SIZE_T-1) < (NTL_BITS_PER_LONG-4)) #define NTL_OVFBND1 (1L << (NTL_BITS_PER_SIZE_T-1)) #else #define NTL_OVFBND1 NTL_OVFBND #endif /* * NTL_OVFBND1 is a smaller bound than NTL_OVF when size_t is * narrower than long. This prevents overflow on calls to malloc * and realloc. */ #define NTL_OVERFLOW(n, a, b) \ (((b) >= NTL_OVFBND) || (((long) (n)) > 0 && (((a) >= NTL_OVFBND) || \ (((long) (n)) >= (NTL_OVFBND-((long)(b))+((long)(a))-1)/((long)(a)))))) /* * NTL_OVERFLOW(n, a, b) returns 1 if n*a + b >= NTL_OVFBND, * and returns 0 otherwise. The value n is effectively treated as type long, * while the values a and b may be *any* integral type. It is assumed that * n >= 0, a > 0, and b >= 0. Care is taken to ensure that overflow does * not occur. If a and b are constants, and n has no side effects, * a good optimizing compiler will * translate this into a single test * of the form n >= c, where c is a constant. */ #define NTL_OVERFLOW1(n, a, b) \ (((b) >= NTL_OVFBND1) || (((long) (n)) > 0 && (((a) >= NTL_OVFBND1) || \ (((long) (n)) >= (NTL_OVFBND1-((long)(b))+((long)(a))-1)/((long)(a)))))) /* * NTL_OVERFLOW1 is the same as NTL_OVERFLOW, except that it uses the * bound NTL_OVFBND1 instead of NTL_OVFBND. */ #define NTL_MALLOC(n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) malloc(((long)(n))*((long)(a)) + ((long)(b))))) /* * NTL_MALLOC(n, a, b) returns 0 if a*n + b >= NTL_OVFBND1, and otherwise * returns malloc(n*a + b). * The programmer must ensure that the name "malloc" is visible * at the point in the source code where this macro is expanded. */ #define NTL_SNS_MALLOC(n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) NTL_SNS malloc(((long)(n))*((long)(a)) + ((long)(b))))) /* * NTL_SNS_MALLOC is the same as NTL_MALLOC, except that the call * to malloc is prefixed by NTL_SNS. */ #define NTL_REALLOC(p, n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) realloc((p), ((long)(n))*((long)(a)) + ((long)(b))))) /* * NTL_REALLOC(n, a, b) returns 0 if a*n + b >= NTL_OVFBND1, and otherwise * returns realloc(p, n*a + b). * The programmer must ensure that the name "realloc" is visible * at the point in the source code where this macro is expanded. */ #define NTL_SNS_REALLOC(p, n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) NTL_SNS realloc((p), ((long)(n))*((long)(a)) + ((long)(b))))) /* * NTL_SNS_REALLOC is the same as NTL_REALLOC, except that the call * to realloc is prefixed by NTL_SNS. */ #define NTL_MAX_ALLOC_BLOCK (40000) /* * NTL_MAX_ALLOC_BLOCK is the number of bytes that are allocated in * a single block in a number of places throughout NTL (for * vec_ZZ_p, ZZVec, vec_GF2X, and GF2XVec). */ #define NTL_ULONG_TO_LONG(a) \ ((((unsigned long) a) >> (NTL_BITS_PER_LONG-1)) ? \ (((long) (((unsigned long) a) - ((unsigned long) NTL_MIN_LONG))) + \ NTL_MIN_LONG) : \ ((long) a)) /* * This macro converts from unsigned long to signed long. It is portable * among platforms for which a long has a 2's complement representation * of the same width as an unsigned long. While it avoids assumptions * about the behavior of non-standard conversions, a good optimizing * compiler should turn it into the identity function. */ #define NTL_UINT_TO_INT(a) \ ((((unsigned int) a) >> (NTL_BITS_PER_INT-1)) ? \ (((int) (((unsigned int) a) - ((unsigned int) NTL_MIN_INT))) + \ NTL_MIN_INT) : \ ((int) a)) /* * This macro converts from unsigned int to signed int. It is portable * among platforms for which an int has a 2's complement representation * of the same width as an unsigned int. While it avoids assumptions * about the behavior of non-standard conversions, a good optimizing * compiler should turn it into the identity function. */ #define NTL_THREAD_LOCAL /* * placeholder for now...it will eventually be defined as thread_local */ #define NTL_RELEASE_THRESH (128) /* * threshold for releasing scratch memory. */ long _ntl_IsFinite(double *p); /* This forces a double into memory, and tests if it is "normal"; that means, not NaN, not +/- infinity, not denormalized, etc. Forcing into memory is sometimes necessary on machines with "extended" double precision registers (e.g., Intel x86s) to force the standard IEEE format. */ void _ntl_ForceToMem(double *p); /* This is do-nothing routine that has the effect of forcing a double into memory (see comment above). */ double _ntl_ldexp(double x, long e); void _ntl_abort(); /* This is the routine called by NTL to abort a program in case of error. */ void _ntl_abort_cxx_callback(); /* This is a C++ function (implemented in tools.c) that is used to implement the callback mechanism. The issue here is that I don't want a C function to call a C++ function via a function pointer. This could potentially be problematic. EDIT: since changing over to all-C++, this is now moot. */ #endif ntl-6.2.1/include/NTL/def_config.h000644 000765 000024 00000034222 12377144457 017153 0ustar00shoupstaff000000 000000 #ifndef NTL_config__H #define NTL_config__H /************************************************************************* NTL Configuration File ---------------------- This file may be modified prior to building NTL so as to specify some basic configuration options, and to customize how code is generated so as to improve performance. The Basic Configuration Options must be set by hand. If you use the configuration wizard, then these flags should be set before the installation process begins; there values will be retained by the wizard. The Performance Options can be set either by hand, by editing this file, or (on most Unix platforms) can be set automatically using the configuration wizard which runs when NTL is installed. All NTL header files include this file. By setting these flags here, instead of on the compiler command line, it is easier to guarantee that NTL library and client code use consistent settings. How to do it ------------ To set a flag, just replace the pre-processor directive 'if 0' by 'if 1' for that flag, which causes the appropriate macro to be defined. Of course, to unset a flag, just replace the 'if 1' by an 'if 0'. You can also do this more conveniently via the command line using the configure script. *************************************************************************/ /************************************************************************* * * Basic Configuration Options * *************************************************************************/ /* None of these flags are set by the configuration wizard; * they must be set by hand, before installation begins. */ #if 1 #define NTL_STD_CXX /* * Use this flag if you want to use the "Standard C++" version of NTL. * In this version, all of NTL is "wrapped" inside the namespace NTL, * and are no longer directly accessible---you must either use * explicit qualification, or using directives, or using declarations. * However, note that all names that begin with "NTL_" are macros, * and as such do not belong to any namespace. * Additionally, instead of including the standard headers * , , and , the standard headers * , , and are included. * These "wrap" some (but not all) names in namespace std. * Also, the 'nothrow' version on the 'new' operator is used. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* The following three flags may be used if you want to use some * of the features of Standard C++, but your compiler is deficient. * Instead of setting the NTL_STD_CXX, you can set any subset * of the these three. Setting all three of these flags is equivalent * to setting NTL_STD_CXX. No harm is done if NTL_STD_CXX is set * and some of the following three flags are set. * * To re-build after changing any of these flags: rm *.o; make ntl.a */ #if 0 #define NTL_PSTD_NNS /* Set if NTL library components are to be wrapped in namespace 'NTL'. */ #endif #if 0 #define NTL_PSTD_NHF /* Set if you want to use the new header files , , and * , instead of the traditional header files , * , and . * If new header files are used, then it is assumed that all standard * library components are wrapped in namespace std; otherwise, * it is assumed that all standard library components are in the * global namespace. * * Also, when set, some internal NTL files use the header * in place of . */ #endif #if 0 #define NTL_PSTD_NTN /* Set if you want to use the 'nothrow' version of new. */ #endif #if 0 #define NTL_GMP_LIP /* * Use this flag if you want to use GMP as the long integer package. * This can result in significantly faster code on some platforms. * It requires that the GMP package (version >= 3.1) has already been * installed. You will also have to set the variables GMP_OPT_INCDIR, * GMP_OPT_LIBDIR, GMP_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GMP_LIP=on * to that script. * * Beware that setting this flag can break some very old NTL codes. * * To re-build after changing this flag: * rm *.o; make setup3; make ntl.a * You may also have to edit the makefile to modify the variables * GMP_OPT_INCDIR, GMP_OPT_LIBDIR, and GMP_OPT_LIB. */ #endif #if 0 #define NTL_GF2X_LIB /* * Use this flag if you want to use the gf2x library for * faster GF2X arithmetic. * This can result in significantly faster code, especially * when working with polynomials of huge degree. * You will also have to set the variables GF2X_OPT_INCDIR, * GF2X_OPT_LIBDIR, GF2X_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GF2X_LIB=on * to that script. * * To re-build after changing this flag: * rm GF2X.o; GF2X1.o; make ntl.a * You may also have to edit the makefile to modify the variables * GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, and GF2X_OPT_LIB. */ #endif #if 0 #define NTL_LONG_LONG_TYPE long long /* * If you set the flag NTL_LONG_LONG, then the value of * NTL_LONG_LONG_TYPE will be used * to declare 'double word' signed integer types. * Irrelevant when NTL_GMP_LIP is set. * If left undefined, some "ifdef magic" will attempt * to find the best choice for your platform, depending * on the compiler and wordsize. On 32-bit machines, * this is usually 'long long'. * * To re-build after changing this flag: rm lip.o; make ntl.a */ #endif #if 0 #define NTL_UNSIGNED_LONG_LONG_TYPE unsigned long long /* * If you set the flag NTL_SPMM_ULL, then the value of * NTL_UNSIGNED_LONG_LONG_TYPE will be used * to declare 'double word' unsigned integer types. * If left undefined, some "ifdef magic" will attempt * to find the best choice for your platform, depending * on the compiler and wordsize. On 32-bit machines, * this is usually 'unsigned long long'. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_CLEAN_INT /* * This will disallow the use of some non-standard integer arithmetic * that may improve performance somewhat. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_CLEAN_PTR /* * This will disallow the use of some non-standard pointer arithmetic * that may improve performance somewhat. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_RANGE_CHECK /* * This will generate vector subscript range-check code. * Useful for debugging, but it slows things down of course. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_NO_INIT_TRANS /* * Without this flag, NTL uses a special code sequence to avoid * copying large objects in return statements. However, if your * compiler optimizes away the return of a *named* local object, * this is not necessary, and setting this flag will result * in *slightly* more compact and efficient code. Although * the emeriging C++ standard allows compilers to perform * this optimization, I know of none that currently do. * Most will avoid copying *temporary* objects in return statements, * and NTL's default code sequence exploits this fact. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_X86_FIX /* * Forces the "x86 floating point fix", overriding the default behavior. * By default, NTL will apply the "fix" if it looks like it is * necessary, and if knows how to fix it. * The problem addressed here is that x86 processors sometimes * run in a mode where FP registers have more precision than doubles. * This will cause code in quad_float.c some trouble. * NTL can normally correctly detect the problem, and fix it, * so you shouldn't need to worry about this or the next flag. * To re-build after changing this flag: rm quad_float.o; make ntl.a * */ #elif 0 #define NTL_NO_X86_FIX /* * Forces no "x86 floating point fix", overriding the default behavior. * To re-build after changing this flag: rm quad_float.o; make ntl.a */ #endif /************************************************************************* * * Performance Options * *************************************************************************/ /* One can choose one of three different stragtegies for long integer * arithmetic: the default, NTL_LONG_LONG, or NTL_AVOID_FLOAT. * The configuration wizard will choose among them. * */ #if 0 #define NTL_LONG_LONG /* * * For platforms that support it, this flag can be set to cause * the low-level multiplication code to use the type "long long", * which may yield a significant performance gain, * but on others, it can yield no improvement and can even * slow things down. * * * See below (NTL_LONG_LONG_TYPE) for how to use a type name * other than "long long". * * If you set NTL_LONG_LONG, you might also want to set * the flag NTL_TBL_REM (see below). * * To re-build after changing this flag: rm lip.o; make ntl.a */ #elif 0 #define NTL_AVOID_FLOAT /* * * On machines with slow floating point or---more comminly---slow int/float * conversions, this flag can lead to faster code. * * If you set NTL_AVOID_FLOAT, you should probably also * set NTL_TBL_REM (see below). * * To re-build after changing this flag: rm lip.o; make ntl.a */ #endif /* There are four strategies to implmement single-precision * modular multiplication with precondinition (see the MulModPrecon * function in the ZZ module): the default, NTL_SPMM_UL, and NTL_SPMM_ULL, * and NTL_SPMM_ASM. * This plays a crucial role in the "small prime FFT" used to * implement polynomial arithmetic, and in other CRT-based methods * (such as linear algebra over ZZ), as well as polynomial and matrix * arithmetic over zz_p. */ #if 0 #define NTL_SPMM_UL /* The default MulModPrecon implementation uses a mix of * int and float arithmetic, which may be slow on certain machines. * This flag causes an "all integer" implementation to be used. * It is entirely portable. * To re-build after changing this flag: rm *.o; make ntl.a */ #elif 0 #define NTL_SPMM_ULL /* Like this previous flag, this also causes an "all integer" * implementation of MulModPrecon to be used. * It us usually a faster implementation, * but it is not enturely portable. * It relies on double-word unsigned multiplication * (see NTL_UNSIGNED_LONG_LONG_TYPE above). * * To re-build after changing this flag: rm *.o; make ntl.a */ #elif 0 #define NTL_SPMM_ASM /* Like this previous two flag, this also causes an "all integer" * implementation of MulModPrecon to be used. * It relies assembler code to do double-word unsigned multiplication. * This is only supported on a select mechines under GCC. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* * The following two flags provide additional control for how the * FFT modulo single-precision primes is implemented. */ #if 0 #define NTL_FFT_BIGTAB /* * Precomputed tables are used to store all the roots of unity * used in an FFT computation for the first NTL_FFT_BIGTAB_LIMIT * FFT primes (the latter is defined in FFT.h). This can * lead to significant time savings but at the const of some space: * in the worst case, the precomputed tables will take of space * log_2(NTL_FFT_BUGTAB_LIMIT) * M, where M is roughly the maxmimum * space occupied by any one polynomial that was involved in an * FFT computation (this could be a polynomial over zz_p, ZZ_p, or ZZ). * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_FFT_LAZYMUL /* * This flag only has an effect when combined with the NTL_FFT_BIGTAB * flag, and either the NTL_SPMM_ULL or NTL_SPMM_ASM flags. * When set, a "lazy multiplication" strategy due to David Harvey: * see his paper "FASTER ARITHMETIC FOR NUMBER-THEORETIC TRANSFORMS". * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif /* The next five flags NTL_AVOID_BRANCHING, NTL_TBL_REM, * NTL_GF2X_ALTCODE, NTL_GF2X_ALTCODE1, and NTL_GF2X_NOINLINE * are also set by the configuration wizard. */ #if 0 #define NTL_AVOID_BRANCHING /* * With this option, branches are replaced at several * key points with equivalent code using shifts and masks. * It may speed things up on machines with * deep pipelines and high branch penalities. * This flag mainly affects the implementation of the * single-precision modular arithmetic routines. * * To re-build after changing this flag: rm *.o; make ntl.a */ #endif #if 0 #define NTL_TBL_REM /* * * With this flag, some divisions are avoided in the * ZZ_pX multiplication routines. If you use the NTL_AVOID_FLOAT * or NTL_LONG_LONG flags, then you should probably use this one too. * * Irrelevent when NTL_GMP_LIP is set. * * To re-build after changing this flag: * rm lip.o; make ntl.a */ #endif #if 0 #define NTL_GF2X_ALTCODE /* * With this option, the default strategy for implmenting low-level * GF2X multiplication is replaced with an alternative strategy. * This alternative strategy seems to work better on RISC machines * with deep pipelines and high branch penalties (like a powerpc), * but does no better (or even worse) on x86s. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #elif 0 #define NTL_GF2X_ALTCODE1 /* * Yest another alternative strategy for implementing GF2X * multiplication. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #endif #if 0 #define NTL_GF2X_NOINLINE /* * By default, the low-level GF2X multiplication routine in inlined. * This can potentially lead to some trouble on some platforms, * and you can override the default by setting this flag. * * To re-build after changing this flag: rm GF2X.o; make ntl.a */ #endif /* The following flag is not set by the configuration wizard; its use * is not generally recommended. */ #endif ntl-6.2.1/include/NTL/fileio.h000644 000765 000024 00000001400 12377144457 016327 0ustar00shoupstaff000000 000000 #ifndef NTL_fileio__H #define NTL_fileio__H #include #if (defined(NTL_STD_CXX) || defined(NTL_PSTD_NHF)) #include #else #include #endif #if 0 namespace foo_bar { class ofstream; class ifstream; } #endif NTL_OPEN_NNS void OpenWrite(NTL_SNS ofstream& s, const char *name); // opens file for writing...aborts if fails void OpenRead(NTL_SNS ifstream& s, const char *name); // opens file for reading char *FileName(const char* stem, const char *ext); // builds the name "stem-ext", returns a pointer to buffer char *FileName(const char* stem, const char *ext, long d); // builds the name stem-ext-DDDDD, returns pointer to buffer NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/g_lip.h000644 000765 000024 00000040363 12377144460 016157 0ustar00shoupstaff000000 000000 #if 1 typedef void *_ntl_gbigint; #else /* * This way of defining the bigint handle type is a bit non-standard, * but better for debugging. */ struct _ntl_gbigint_is_opaque { int _x_; }; typedef struct _ntl_gbigint_is_opaque * _ntl_gbigint; #endif #define NTL_SP_NBITS NTL_NBITS_MAX #define NTL_SP_BOUND (1L << NTL_SP_NBITS) #define NTL_SP_FBOUND ((double) NTL_SP_BOUND) #define NTL_WSP_NBITS (NTL_BITS_PER_LONG-2) #define NTL_WSP_BOUND (1L << NTL_WSP_NBITS) /* define the following so an error is raised */ #define NTL_RADIX ...... #define NTL_NBITSH ...... #define NTL_RADIXM ...... #define NTL_RADIXROOT ...... #define NTL_RADIXROOTM ...... #define NTL_FRADIX_INV ...... /*********************************************************************** Basic Functions ***********************************************************************/ void _ntl_gsadd(_ntl_gbigint a, long d, _ntl_gbigint *b); /* *b = a + d */ void _ntl_gadd(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* *c = a + b */ void _ntl_gsub(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* *c = a - b */ void _ntl_gsubpos(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* *c = a - b; assumes a >= b >= 0 */ void _ntl_gsmul(_ntl_gbigint a, long d, _ntl_gbigint *b); /* *b = d * a */ void _ntl_gmul(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* *c = a * b */ void _ntl_gsq(_ntl_gbigint a, _ntl_gbigint *c); /* *c = a * a */ long _ntl_gsdiv(_ntl_gbigint a, long b, _ntl_gbigint *q); /* (*q) = floor(a/b) and a - floor(a/b)*(*q) is returned; error is raised if b == 0; if b does not divide a, then sign(*q) == sign(b) */ void _ntl_gdiv(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *q, _ntl_gbigint *r); /* (*q) = floor(a/b) and (*r) = a - floor(a/b)*(*q); error is raised if b == 0; if b does not divide a, then sign(*q) == sign(b) */ void _ntl_gmod(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *r); /* same as _ntl_gdiv, but only remainder is computed */ long _ntl_gsmod(_ntl_gbigint a, long d); /* same as _ntl_gsdiv, but only remainder is computed */ void _ntl_gquickmod(_ntl_gbigint *r, _ntl_gbigint b); /* *r = *r % b; The division is performed in place (but may sometimes assumes b > 0 and *r >= 0; cause *r to grow by one digit) */ void _ntl_gsaddmul(_ntl_gbigint x, long y, _ntl_gbigint *ww); /* *ww += x*y */ void _ntl_gaddmul(_ntl_gbigint x, _ntl_gbigint y, _ntl_gbigint *ww); /* *ww += x*y */ void _ntl_gssubmul(_ntl_gbigint x, long y, _ntl_gbigint *ww); /* *ww -= x*y */ void _ntl_gsubmul(_ntl_gbigint x, _ntl_gbigint y, _ntl_gbigint *ww); /* *ww -= x*y */ /******************************************************************** Shifting and bit manipulation *********************************************************************/ void _ntl_glshift(_ntl_gbigint n, long k, _ntl_gbigint *a); /* *a = sign(n) * (|n| << k); shift is in reverse direction for negative k */ void _ntl_grshift(_ntl_gbigint n, long k, _ntl_gbigint *a); /* *a = sign(n) * (|n| >> k); shift is in reverse direction for negative k */ long _ntl_gmakeodd(_ntl_gbigint *n); /* if (n != 0) *n = m; return (k such that n == 2 ^ k * m with m odd); else return (0); */ long _ntl_gnumtwos(_ntl_gbigint n); /* return largest e such that 2^e divides n, or zero if n is zero */ long _ntl_godd(_ntl_gbigint a); /* returns 1 if n is odd and 0 if it is even */ long _ntl_gbit(_ntl_gbigint a, long p); /* returns p-th bit of a, where the low order bit is indexed by 0; p out of range returns 0 */ long _ntl_gsetbit(_ntl_gbigint *a, long p); /* returns original value of p-th bit of |a|, and replaces p-th bit of a by 1 if it was zero; error if p < 0 */ long _ntl_gswitchbit(_ntl_gbigint *a, long p); /* returns original value of p-th bit of |a|, and switches the value of p-th bit of a; p starts counting at 0; error if p < 0 */ void _ntl_glowbits(_ntl_gbigint a, long k, _ntl_gbigint *b); /* places k low order bits of |a| in b */ long _ntl_gslowbits(_ntl_gbigint a, long k); /* returns k low order bits of |a| */ long _ntl_gweights(long a); /* returns Hamming weight of |a| */ long _ntl_gweight(_ntl_gbigint a); /* returns Hamming weight of |a| */ void _ntl_gand(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* c gets bit pattern `bits of |a|` and `bits of |b|` */ void _ntl_gor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* c gets bit pattern `bits of |a|` inclusive or `bits of |b|` */ void _ntl_gxor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* c gets bit pattern `bits of |a|` exclusive or `bits of |b|` */ /************************************************************************ Comparison *************************************************************************/ long _ntl_gcompare(_ntl_gbigint a, _ntl_gbigint b); /* if (a > b) return (1); if (a == b) return (0); if (a < b) return (-1); */ long _ntl_gscompare(_ntl_gbigint a, long b); /* single-precision version of the above */ long _ntl_giszero (_ntl_gbigint a); /* test for 0 */ long _ntl_gsign(_ntl_gbigint a); /* if (a > 0) return (1); if (a == 0) return (0); if (a < 0) return (-1); */ void _ntl_gabs(_ntl_gbigint *a); /* *a = |a| */ void _ntl_gnegate(_ntl_gbigint *a); /* *a = -a */ void _ntl_gcopy(_ntl_gbigint a, _ntl_gbigint *b); /* *b = a; */ void _ntl_gswap(_ntl_gbigint *a, _ntl_gbigint *b); /* swap a and b (by swaping pointers) */ long _ntl_g2log(_ntl_gbigint a); /* number of bits in |a|; returns 0 if a = 0 */ long _ntl_g2logs(long a); /* single-precision version of the above */ /******************************************************************** Conversion *********************************************************************/ void _ntl_gzero(_ntl_gbigint *a); /* *a = 0; */ void _ntl_gone(_ntl_gbigint *a); /* *a = 1 */ void _ntl_gintoz(long d, _ntl_gbigint *a); /* *a = d; */ void _ntl_guintoz(unsigned long d, _ntl_gbigint *a); /* *a = d; space is allocated */ long _ntl_gtoint(_ntl_gbigint a); /* converts a to a long; overflow results in value mod 2^{NTL_BITS_PER_LONG}. */ unsigned long _ntl_gtouint(_ntl_gbigint a); /* converts a to a long; overflow results in value mod 2^{NTL_BITS_PER_LONG}. */ double _ntl_gdoub(_ntl_gbigint n); /* converts a to a double; no overflow check */ long _ntl_ground_correction(_ntl_gbigint a, long k, long residual); /* k >= 1, |a| >= 2^k, and residual is 0, 1, or -1. The result is what we should add to (a >> k) to round x = a/2^k to the nearest integer using IEEE-like rounding rules (i.e., round to nearest, and round to even to break ties). The result is either 0 or sign(a). If residual is not zero, it is as if x were replaced by x' = x + residual*2^{-(k+1)}. This can be used to break ties when x is exactly half way between two integers. */ double _ntl_glog(_ntl_gbigint a); /* computes log(a), protecting against overflow */ void _ntl_gdoubtoz(double a, _ntl_gbigint *x); /* x = floor(a); */ /************************************************************************ Square roots *************************************************************************/ long _ntl_gsqrts(long n); /* return floor(sqrt(n)); error raised in n < 0 */ void _ntl_gsqrt(_ntl_gbigint n, _ntl_gbigint *r); /* *r = floor(sqrt(n)); error raised in n < 0 */ /********************************************************************* Exponentiation **********************************************************************/ void _ntl_gexp(_ntl_gbigint a, long e, _ntl_gbigint *b); /* *b = a^e; error raised if e < 0 */ void _ntl_gexps(long a, long e, _ntl_gbigint *b); /* *b = a^e; error raised if e < 0 */ /********************************************************************* Modular Arithmetic Addition, subtraction, multiplication, squaring division, inversion, and exponentiation modulo a positive modulus n, where all operands (except for the exponent in exponentiation) and results are in the range [0, n-1]. ALIAS RESTRICTION: output parameters should not alias n ***********************************************************************/ void _ntl_gaddmod(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a + b) % n */ void _ntl_gsubmod(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a - b) % n */ void _ntl_gsmulmod(_ntl_gbigint a, long b, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a * b) % n */ void _ntl_gmulmod(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a * b) % n */ void _ntl_gsqmod(_ntl_gbigint a, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a ^ 2) % n */ void _ntl_ginvmod(_ntl_gbigint a, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (1 / a) % n; error raised if gcd(b, n) != 1 */ void _ntl_gpowermod(_ntl_gbigint g, _ntl_gbigint e, _ntl_gbigint F, _ntl_gbigint *h); /* *b = (a ^ e) % n; */ /************************************************************************** Euclidean Algorithms ***************************************************************************/ void _ntl_ggcd(_ntl_gbigint m1, _ntl_gbigint m2, _ntl_gbigint *r); /* *r = greatest common divisor of m1 and m2; uses binary gcd algorithm */ void _ntl_gexteucl(_ntl_gbigint a, _ntl_gbigint *xa, _ntl_gbigint b, _ntl_gbigint *xb, _ntl_gbigint *d); /* *d = a * *xa + b * *xb = gcd(a, b); sets *d, *xa and *xb given a and b; uses Lehmer`s trick */ long _ntl_ginv(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* if (a and b coprime) { *c = inv; return(0); } else { *c = gcd(a, b); return(1); } where inv is such that (inv * a) == 1 mod b; error raised if a < 0 or b <= 0 */ long _ntl_gxxratrecon(_ntl_gbigint x, _ntl_gbigint m, _ntl_gbigint a_bound, _ntl_gbigint b_bound, _ntl_gbigint *a, _ntl_gbigint *b); /* rational reconstruction: see doc in ZZ.txt */ /********************************************************************** Storage Allocation These routines use malloc and free. ***********************************************************************/ inline long _ntl_gmaxalloc(_ntl_gbigint x) { if (!x) return 0; else return ((((long *) (x))[0]) >> 2); } /* DIRT: the above maxalloc routine is inlined, with the definition of ALLOC copied and pasted. */ void _ntl_gsetlength(_ntl_gbigint *v, long len); /* Allocates enough space to hold a len-digit number, where each digit has NTL_NBITS bits. If space must be allocated, space for one extra digit is always allocated. if (exact) then no rounding occurs. */ void _ntl_gfree(_ntl_gbigint *x); /* Free's space held by x, and sets x back to 0. */ /******************************************************************* Special routines ********************************************************************/ long _ntl_gsize(_ntl_gbigint n); long _ntl_gisone(_ntl_gbigint n); long _ntl_gsptest(_ntl_gbigint a); long _ntl_gwsptest(_ntl_gbigint a); long _ntl_gcrtinrange(_ntl_gbigint g, _ntl_gbigint a); void _ntl_gfrombytes(_ntl_gbigint *x, const unsigned char *p, long n); void _ntl_gbytesfromz(unsigned char *p, _ntl_gbigint a, long nn); long _ntl_gblock_construct_alloc(_ntl_gbigint *x, long d, long n); void _ntl_gblock_construct_set(_ntl_gbigint x, _ntl_gbigint *y, long i); long _ntl_gblock_destroy(_ntl_gbigint x); long _ntl_gblock_storage(long d); void _ntl_gcrt_struct_init(void **crt_struct, long n, _ntl_gbigint p, const long *primes); void _ntl_gcrt_struct_insert(void *crt_struct, long i, _ntl_gbigint m); void _ntl_gcrt_struct_free(void *crt_struct); void _ntl_gcrt_struct_eval(void *crt_struct, _ntl_gbigint *t, const long *a); long _ntl_gcrt_struct_special(void *crt_struct); void _ntl_grem_struct_init(void **rem_struct, long n, _ntl_gbigint p, const long *primes); void _ntl_grem_struct_free(void *rem_struct); void _ntl_grem_struct_eval(void *rem_struct, long *x, _ntl_gbigint a); #define NTL_crt_struct_eval _ntl_gcrt_struct_eval #define NTL_crt_struct_free _ntl_gcrt_struct_free #define NTL_crt_struct_init _ntl_gcrt_struct_init #define NTL_crt_struct_insert _ntl_gcrt_struct_insert #define NTL_crt_struct_special _ntl_gcrt_struct_special #define NTL_rem_struct_eval _ntl_grem_struct_eval #define NTL_rem_struct_free _ntl_grem_struct_free #define NTL_rem_struct_init _ntl_grem_struct_init #define NTL_verylong _ntl_gbigint #define NTL_z2log _ntl_g2log #define NTL_zabs _ntl_gabs #define NTL_zadd _ntl_gadd #define NTL_zaddmod _ntl_gaddmod #define NTL_zand _ntl_gand #define NTL_zbit _ntl_gbit #define NTL_zblock_construct_alloc _ntl_gblock_construct_alloc #define NTL_zblock_construct_set _ntl_gblock_construct_set #define NTL_zblock_destroy _ntl_gblock_destroy #define NTL_zblock_storage _ntl_gblock_storage #define NTL_zbytesfromz _ntl_gbytesfromz #define NTL_zcompare _ntl_gcompare #define NTL_zcopy _ntl_gcopy #define NTL_zcrtinrange _ntl_gcrtinrange #define NTL_zdiv _ntl_gdiv #define NTL_zdoub _ntl_gdoub #define NTL_zdoubtoz _ntl_gdoubtoz #define NTL_zexp _ntl_gexp #define NTL_zexps _ntl_gexps #define NTL_zexteucl _ntl_gexteucl #define NTL_zfree _ntl_gfree #define NTL_zfrombytes _ntl_gfrombytes #define NTL_zgcd _ntl_ggcd #define NTL_zintoz _ntl_gintoz #define NTL_zinv _ntl_ginv #define NTL_zinvmod _ntl_ginvmod #define NTL_zisone _ntl_gisone #define NTL_ziszero _ntl_giszero #define NTL_zlog _ntl_glog #define NTL_zlowbits _ntl_glowbits #define NTL_zlshift _ntl_glshift #define NTL_zmakeodd _ntl_gmakeodd #define NTL_zmod _ntl_gmod #define NTL_zmul _ntl_gmul #define NTL_zmulmod _ntl_gmulmod #define NTL_znegate _ntl_gnegate #define NTL_znumtwos _ntl_gnumtwos #define NTL_zodd _ntl_godd #define NTL_zone _ntl_gone #define NTL_zor _ntl_gor #define NTL_zpowermod _ntl_gpowermod #define NTL_zquickmod _ntl_gquickmod #define NTL_zround_correction _ntl_ground_correction #define NTL_zrshift _ntl_grshift #define NTL_zsadd _ntl_gsadd #define NTL_zscompare _ntl_gscompare #define NTL_zsdiv _ntl_gsdiv #define NTL_zsetbit _ntl_gsetbit #define NTL_zmaxalloc _ntl_gmaxalloc #define NTL_zsetlength _ntl_gsetlength #define NTL_zsign _ntl_gsign #define NTL_zsize _ntl_gsize #define NTL_zslowbits _ntl_gslowbits #define NTL_zsmod _ntl_gsmod #define NTL_zsmul _ntl_gsmul #define NTL_zsmulmod _ntl_gsmulmod #define NTL_zsptest _ntl_gsptest #define NTL_zsq _ntl_gsq #define NTL_zsqmod _ntl_gsqmod #define NTL_zsqrt _ntl_gsqrt #define NTL_zsqrts _ntl_gsqrts #define NTL_zsub _ntl_gsub #define NTL_zsubmod _ntl_gsubmod #define NTL_zsubpos _ntl_gsubpos #define NTL_zswap _ntl_gswap #define NTL_zswitchbit _ntl_gswitchbit #define NTL_ztoint _ntl_gtoint #define NTL_ztouint _ntl_gtouint #define NTL_zuintoz _ntl_guintoz #define NTL_zweight _ntl_gweight #define NTL_zweights _ntl_gweights #define NTL_zwsptest _ntl_gwsptest #define NTL_zxor _ntl_gxor #define NTL_zxxratrecon _ntl_gxxratrecon #define NTL_zzero _ntl_gzero #define NTL_zsaddmul _ntl_gsaddmul #define NTL_zaddmul _ntl_gaddmul #define NTL_zssubmul _ntl_gssubmul #define NTL_zsubmul _ntl_gsubmul #define NTL_GMP_LIP ntl-6.2.1/include/NTL/lip.h000644 000765 000024 00000000324 12377144457 015650 0ustar00shoupstaff000000 000000 #ifndef NTL_g_lip__H #define NTL_g_lip__H #include #include #ifdef NTL_GMP_LIP #include #include #else #include #endif #endif ntl-6.2.1/include/NTL/lzz_p.h000644 000765 000024 00000022367 12377144457 016235 0ustar00shoupstaff000000 000000 #ifndef NTL_zz_p__H #define NTL_zz_p__H #include #include #define NTL_zz_p_QUICK_CRT (NTL_DOUBLE_PRECISION - NTL_SP_NBITS > 12) NTL_OPEN_NNS class zz_pInfoT { private: zz_pInfoT(); // disabled zz_pInfoT(const zz_pInfoT&); // disabled void operator=(const zz_pInfoT&); // disabled public: zz_pInfoT(long NewP, long maxroot); zz_pInfoT(INIT_FFT_TYPE, FFTPrimeInfo *info); zz_pInfoT(INIT_USER_FFT_TYPE, long q); ~zz_pInfoT(); long ref_count; long p; double pinv; FFTPrimeInfo* p_info; // non-null means we are directly using // an FFT prime long p_own; // flag to indicate if info object is owened // by this long PrimeCnt; // 0 for FFT prime; otherwise same as NumPrimes // used for establishing crossover points long NumPrimes; long MaxRoot; long MinusMModP; // -M mod p, M = product of primes // the following arrays are indexed 0..NumPrimes-1 // q = FFTPrime[i] long *CoeffModP; // coeff mod p double *x; // u/q, where u = (M/q)^{-1} mod q long *u; // u, as above }; NTL_THREAD_LOCAL extern zz_pInfoT *zz_pInfo; // current modulus, initially null // FIXME: in a thread-safe impl, we have to use a thread-safe // reference counted pointer, like shared_ptr class zz_pContext { private: zz_pInfoT *ptr; public: void save(); void restore() const; zz_pContext() { ptr = 0; } explicit zz_pContext(long p, long maxroot=NTL_FFTMaxRoot); zz_pContext(INIT_FFT_TYPE, long index); zz_pContext(INIT_USER_FFT_TYPE, long q); zz_pContext(const zz_pContext&); zz_pContext& operator=(const zz_pContext&); ~zz_pContext(); }; class zz_pBak { private: long MustRestore; zz_pInfoT *ptr; zz_pBak(const zz_pBak&); // disabled void operator=(const zz_pBak&); // disabled public: void save(); void restore(); zz_pBak() { MustRestore = 0; ptr = 0; } ~zz_pBak(); }; class zz_pPush { private: zz_pBak bak; zz_pPush(const zz_pPush&); // disabled void operator=(const zz_pPush&); // disabled public: zz_pPush() { bak.save(); } explicit zz_pPush(const zz_pContext& context) { bak.save(); context.restore(); } explicit zz_pPush(long p, long maxroot=NTL_FFTMaxRoot) { bak.save(); zz_pContext c(p); c.restore(); } zz_pPush(INIT_FFT_TYPE, long index) { bak.save(); zz_pContext c(INIT_FFT, index); c.restore(); } zz_pPush(INIT_USER_FFT_TYPE, long q) { bak.save(); zz_pContext c(INIT_USER_FFT, q); c.restore(); } }; #define NTL_zz_pRegister(x) zz_p x class zz_pX; // forward declaration class zz_p { public: typedef long rep_type; typedef zz_pContext context_type; typedef zz_pBak bak_type; typedef zz_pPush push_type; typedef zz_pX poly_type; long _zz_p__rep; static void init(long NewP, long maxroot=NTL_FFTMaxRoot); static void FFTInit(long index); static void UserFFTInit(long q); // ****** constructors and assignment zz_p() : _zz_p__rep(0) { } explicit zz_p(long a) : _zz_p__rep(0) { *this = a; } zz_p(const zz_p& a) : _zz_p__rep(a._zz_p__rep) { } ~zz_p() { } zz_p& operator=(const zz_p& a) { _zz_p__rep = a._zz_p__rep; return *this; } inline zz_p& operator=(long a); // a loop-hole for direct access to _zz_p__rep long& LoopHole() { return _zz_p__rep; } static long modulus() { return zz_pInfo->p; } static zz_p zero() { return zz_p(); } static double ModulusInverse() { return zz_pInfo->pinv; } static long PrimeCnt() { return zz_pInfo->PrimeCnt; } static long storage() { return sizeof(long); } zz_p(long a, INIT_LOOP_HOLE_TYPE) { _zz_p__rep = a; } // for consistency zz_p(INIT_NO_ALLOC_TYPE) : _zz_p__rep(0) { } zz_p(INIT_ALLOC_TYPE) : _zz_p__rep(0) { } void allocate() { } }; zz_p to_zz_p(long a); void conv(zz_p& x, long a); inline zz_p& zz_p::operator=(long a) { conv(*this, a); return *this; } zz_p to_zz_p(const ZZ& a); void conv(zz_p& x, const ZZ& a); // read-only access to _zz_p__representation inline long rep(zz_p a) { return a._zz_p__rep; } inline void clear(zz_p& x) // x = 0 { x._zz_p__rep = 0; } inline void set(zz_p& x) // x = 1 { x._zz_p__rep = 1; } inline void swap(zz_p& x, zz_p& y) // swap x and y { long t; t = x._zz_p__rep; x._zz_p__rep = y._zz_p__rep; y._zz_p__rep = t; } // ****** addition inline void add(zz_p& x, zz_p a, zz_p b) // x = a + b { x._zz_p__rep = AddMod(a._zz_p__rep, b._zz_p__rep, zz_p::modulus()); } inline void sub(zz_p& x, zz_p a, zz_p b) // x = a - b { x._zz_p__rep = SubMod(a._zz_p__rep, b._zz_p__rep, zz_p::modulus()); } inline void negate(zz_p& x, zz_p a) // x = -a { x._zz_p__rep = SubMod(0, a._zz_p__rep, zz_p::modulus()); } // scalar versions inline void add(zz_p& x, zz_p a, long b) { add(x, a, to_zz_p(b)); } inline void add(zz_p& x, long a, zz_p b) { add(x, to_zz_p(a), b); } inline void sub(zz_p& x, zz_p a, long b) { sub(x, a, to_zz_p(b)); } inline void sub(zz_p& x, long a, zz_p b) { sub(x, to_zz_p(a), b); } inline zz_p operator+(zz_p a, zz_p b) { zz_p x; add(x, a, b); return x; } inline zz_p operator+(zz_p a, long b) { zz_p x; add(x, a, b); return x; } inline zz_p operator+(long a, zz_p b) { zz_p x; add(x, a, b); return x; } inline zz_p operator-(zz_p a, zz_p b) { zz_p x; sub(x, a, b); return x; } inline zz_p operator-(zz_p a, long b) { zz_p x; sub(x, a, b); return x; } inline zz_p operator-(long a, zz_p b) { zz_p x; sub(x, a, b); return x; } inline zz_p operator-(zz_p a) { zz_p x; negate(x, a); return x; } inline zz_p& operator+=(zz_p& x, zz_p b) { add(x, x, b); return x; } inline zz_p& operator+=(zz_p& x, long b) { add(x, x, b); return x; } inline zz_p& operator-=(zz_p& x, zz_p b) { sub(x, x, b); return x; } inline zz_p& operator-=(zz_p& x, long b) { sub(x, x, b); return x; } inline zz_p& operator++(zz_p& x) { add(x, x, 1); return x; } inline void operator++(zz_p& x, int) { add(x, x, 1); } inline zz_p& operator--(zz_p& x) { sub(x, x, 1); return x; } inline void operator--(zz_p& x, int) { sub(x, x, 1); } // ****** multiplication inline void mul(zz_p& x, zz_p a, zz_p b) // x = a*b { x._zz_p__rep = MulMod(a._zz_p__rep, b._zz_p__rep, zz_p::modulus(), zz_p::ModulusInverse()); } inline void mul(zz_p& x, zz_p a, long b) { mul(x, a, to_zz_p(b)); } inline void mul(zz_p& x, long a, zz_p b) { mul(x, to_zz_p(a), b); } inline zz_p operator*(zz_p a, zz_p b) { zz_p x; mul(x, a, b); return x; } inline zz_p operator*(zz_p a, long b) { zz_p x; mul(x, a, b); return x; } inline zz_p operator*(long a, zz_p b) { zz_p x; mul(x, a, b); return x; } inline zz_p& operator*=(zz_p& x, zz_p b) { mul(x, x, b); return x; } inline zz_p& operator*=(zz_p& x, long b) { mul(x, x, b); return x; } inline void sqr(zz_p& x, zz_p a) // x = a^2 { x._zz_p__rep = MulMod(a._zz_p__rep, a._zz_p__rep, zz_p::modulus(), zz_p::ModulusInverse()); } inline zz_p sqr(zz_p a) { zz_p x; sqr(x, a); return x; } // ****** division inline void div(zz_p& x, zz_p a, zz_p b) // x = a/b { x._zz_p__rep = MulMod(a._zz_p__rep, InvMod(b._zz_p__rep, zz_p::modulus()), zz_p::modulus(), zz_p::ModulusInverse()); } inline void inv(zz_p& x, zz_p a) // x = 1/a { x._zz_p__rep = InvMod(a._zz_p__rep, zz_p::modulus()); } inline zz_p inv(zz_p a) { zz_p x; inv(x, a); return x; } inline void div(zz_p& x, zz_p a, long b) { div(x, a, to_zz_p(b)); } inline void div(zz_p& x, long a, zz_p b) { div(x, to_zz_p(a), b); } inline zz_p operator/(zz_p a, zz_p b) { zz_p x; div(x, a, b); return x; } inline zz_p operator/(zz_p a, long b) { zz_p x; div(x, a, b); return x; } inline zz_p operator/(long a, zz_p b) { zz_p x; div(x, a, b); return x; } inline zz_p& operator/=(zz_p& x, zz_p b) { div(x, x, b); return x; } inline zz_p& operator/=(zz_p& x, long b) { div(x, x, b); return x; } // ****** exponentiation inline void power(zz_p& x, zz_p a, long e) // x = a^e { x._zz_p__rep = PowerMod(a._zz_p__rep, e, zz_p::modulus()); } inline zz_p power(zz_p a, long e) { zz_p x; power(x, a, e); return x; } // ****** comparison inline long IsZero(zz_p a) { return a._zz_p__rep == 0; } inline long IsOne(zz_p a) { return a._zz_p__rep == 1; } inline long operator==(zz_p a, zz_p b) { return a._zz_p__rep == b._zz_p__rep; } inline long operator!=(zz_p a, zz_p b) { return !(a == b); } inline long operator==(zz_p a, long b) { return a == to_zz_p(b); } inline long operator==(long a, zz_p b) { return to_zz_p(a) == b; } inline long operator!=(zz_p a, long b) { return !(a == b); } inline long operator!=(long a, zz_p b) { return !(a == b); } // ****** random numbers inline void random(zz_p& x) // x = random element in zz_p { x._zz_p__rep = RandomBnd(zz_p::modulus()); } inline zz_p random_zz_p() { zz_p x; random(x); return x; } // ****** input/output NTL_SNS ostream& operator<<(NTL_SNS ostream& s, zz_p a); NTL_SNS istream& operator>>(NTL_SNS istream& s, zz_p& x); /* additional legacy conversions for v6 conversion regime */ inline void conv(int& x, zz_p a) { conv(x, rep(a)); } inline void conv(unsigned int& x, zz_p a) { conv(x, rep(a)); } inline void conv(long& x, zz_p a) { conv(x, rep(a)); } inline void conv(unsigned long& x, zz_p a) { conv(x, rep(a)); } inline void conv(ZZ& x, zz_p a) { conv(x, rep(a)); } inline void conv(zz_p& x, zz_p a) { x = a; } /* ------------------------------------- */ NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/lzz_pE.h000644 000765 000024 00000030250 12377144457 016330 0ustar00shoupstaff000000 000000 #ifndef NTL_zz_pE__H #define NTL_zz_pE__H #include #include #include #include NTL_OPEN_NNS class zz_pEInfoT { private: zz_pEInfoT(); // disabled zz_pEInfoT(const zz_pEInfoT&); // disabled void operator=(const zz_pEInfoT&); // disabled public: long ref_count; zz_pEInfoT(const zz_pX&); ~zz_pEInfoT() { } zz_pXModulus p; ZZ _card; long _card_init; long _card_base; long _card_exp; }; NTL_THREAD_LOCAL extern zz_pEInfoT *zz_pEInfo; // info for current modulus, initially null class zz_pEContext { private: zz_pEInfoT *ptr; public: void save(); void restore() const; zz_pEContext() { ptr = 0; } explicit zz_pEContext(const zz_pX& p); zz_pEContext(const zz_pEContext&); zz_pEContext& operator=(const zz_pEContext&); ~zz_pEContext(); }; class zz_pEBak { private: long MustRestore; zz_pEInfoT *ptr; zz_pEBak(const zz_pEBak&); // disabled void operator=(const zz_pEBak&); // disabled public: void save(); void restore(); zz_pEBak() { MustRestore = 0; ptr = 0; } ~zz_pEBak(); }; class zz_pEPush { private: zz_pEBak bak; zz_pEPush(const zz_pEPush&); // disabled void operator=(const zz_pEPush&); // disabled public: zz_pEPush() { bak.save(); } explicit zz_pEPush(const zz_pEContext& context) { bak.save(); context.restore(); } explicit zz_pEPush(const zz_pX& p) { bak.save(); zz_pEContext c(p); c.restore(); } }; class zz_pEX; // forward declaration class zz_pE { public: typedef zz_pX rep_type; typedef zz_pEContext context_type; typedef zz_pEBak bak_type; typedef zz_pEPush push_type; typedef zz_pEX poly_type; zz_pX _zz_pE__rep; static long DivCross() { return 16; } static long ModCross() { return 8; } // ****** constructors and assignment zz_pE() { } // NO_ALLOC explicit zz_pE(long a) { *this = a; } // NO_ALLOC explicit zz_pE(const zz_p& a) { *this = a; } // NO_ALLOC zz_pE(const zz_pE& a) { _zz_pE__rep = a._zz_pE__rep; } // NO_ALLOC zz_pE(INIT_NO_ALLOC_TYPE) { } // allocates no space zz_pE(INIT_ALLOC_TYPE) { _zz_pE__rep.rep.SetMaxLength(zz_pE::degree()); } // allocates space void allocate() { _zz_pE__rep.rep.SetMaxLength(zz_pE::degree()); } ~zz_pE() { } zz_pE& operator=(const zz_pE& a) { _zz_pE__rep = a._zz_pE__rep; return *this; } zz_pE(zz_pE& x, INIT_TRANS_TYPE) : _zz_pE__rep(x._zz_pE__rep, INIT_TRANS) { } // You can always access the _zz_pE__representation directly...if you dare. zz_pX& LoopHole() { return _zz_pE__rep; } static const zz_pXModulus& modulus() { return zz_pEInfo->p; } static long degree() { return deg(zz_pEInfo->p); } static const ZZ& cardinality(); static const zz_pE& zero(); static long initialized() { return (zz_pEInfo != 0); } static void init(const zz_pX&); inline zz_pE& operator=(long a); inline zz_pE& operator=(const zz_p& a); }; inline const zz_pX& _zz_pE__rep(const zz_pE& a) { return a._zz_pE__rep; } inline void clear(zz_pE& x) // x = 0 { clear(x._zz_pE__rep); } inline void set(zz_pE& x) // x = 1 { set(x._zz_pE__rep); } inline void swap(zz_pE& x, zz_pE& y) // swap x and y { swap(x._zz_pE__rep, y._zz_pE__rep); } // ****** addition inline void add(zz_pE& x, const zz_pE& a, const zz_pE& b) // x = a + b { add(x._zz_pE__rep, a._zz_pE__rep, b._zz_pE__rep); } inline void sub(zz_pE& x, const zz_pE& a, const zz_pE& b) // x = a - b { sub(x._zz_pE__rep, a._zz_pE__rep, b._zz_pE__rep); } inline void negate(zz_pE& x, const zz_pE& a) { negate(x._zz_pE__rep, a._zz_pE__rep); } inline void add(zz_pE& x, const zz_pE& a, long b) { add(x._zz_pE__rep, a._zz_pE__rep, b); } inline void add(zz_pE& x, const zz_pE& a, const zz_p& b) { add(x._zz_pE__rep, a._zz_pE__rep, b); } inline void add(zz_pE& x, long a, const zz_pE& b) { add(x._zz_pE__rep, a, b._zz_pE__rep); } inline void add(zz_pE& x, const zz_p& a, const zz_pE& b) { add(x._zz_pE__rep, a, b._zz_pE__rep); } inline void sub(zz_pE& x, const zz_pE& a, long b) { sub(x._zz_pE__rep, a._zz_pE__rep, b); } inline void sub(zz_pE& x, const zz_pE& a, const zz_p& b) { sub(x._zz_pE__rep, a._zz_pE__rep, b); } inline void sub(zz_pE& x, long a, const zz_pE& b) { sub(x._zz_pE__rep, a, b._zz_pE__rep); } inline void sub(zz_pE& x, const zz_p& a, const zz_pE& b) { sub(x._zz_pE__rep, a, b._zz_pE__rep); } // ****** multiplication inline void mul(zz_pE& x, const zz_pE& a, const zz_pE& b) // x = a*b { MulMod(x._zz_pE__rep, a._zz_pE__rep, b._zz_pE__rep, zz_pE::modulus()); } inline void sqr(zz_pE& x, const zz_pE& a) // x = a^2 { SqrMod(x._zz_pE__rep, a._zz_pE__rep, zz_pE::modulus()); } inline zz_pE sqr(const zz_pE& a) { zz_pE x; sqr(x, a); NTL_OPT_RETURN(zz_pE, x); } inline void mul(zz_pE& x, const zz_pE& a, long b) { mul(x._zz_pE__rep, a._zz_pE__rep, b); } inline void mul(zz_pE& x, const zz_pE& a, const zz_p& b) { mul(x._zz_pE__rep, a._zz_pE__rep, b); } inline void mul(zz_pE& x, long a, const zz_pE& b) { mul(x._zz_pE__rep, a, b._zz_pE__rep); } inline void mul(zz_pE& x, const zz_p& a, const zz_pE& b) { mul(x._zz_pE__rep, a, b._zz_pE__rep); } // ****** division void div(zz_pE& x, const zz_pE& a, const zz_pE& b); void div(zz_pE& x, const zz_pE& a, long b); void div(zz_pE& x, const zz_pE& a, const zz_p& b); void div(zz_pE& x, long a, const zz_pE& b); void div(zz_pE& x, const zz_p& a, const zz_pE& b); void inv(zz_pE& x, const zz_pE& a); inline zz_pE inv(const zz_pE& a) { zz_pE x; inv(x, a); NTL_OPT_RETURN(zz_pE, x); } // ****** exponentiation inline void power(zz_pE& x, const zz_pE& a, const ZZ& e) // x = a^e { PowerMod(x._zz_pE__rep, a._zz_pE__rep, e, zz_pE::modulus()); } inline zz_pE power(const zz_pE& a, const ZZ& e) { zz_pE x; power(x, a, e); NTL_OPT_RETURN(zz_pE, x); } inline void power(zz_pE& x, const zz_pE& a, long e) { power(x, a, ZZ_expo(e)); } inline zz_pE power(const zz_pE& a, long e) { zz_pE x; power(x, a, e); NTL_OPT_RETURN(zz_pE, x); } // ****** conversion inline void conv(zz_pE& x, const zz_pX& a) { rem(x._zz_pE__rep, a, zz_pE::modulus()); } inline void conv(zz_pE& x, long a) { conv(x._zz_pE__rep, a); } inline void conv(zz_pE& x, const zz_p& a) { conv(x._zz_pE__rep, a); } inline void conv(zz_pE& x, const ZZ& a) { conv(x._zz_pE__rep, a); } inline zz_pE to_zz_pE(const zz_pX& a) { zz_pE x; conv(x, a); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE to_zz_pE(long a) { zz_pE x; conv(x, a); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE to_zz_pE(const zz_p& a) { zz_pE x; conv(x, a); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE to_zz_pE(const ZZ& a) { zz_pE x; conv(x, a); NTL_OPT_RETURN(zz_pE, x); } // ****** comparison inline long IsZero(const zz_pE& a) { return IsZero(a._zz_pE__rep); } inline long IsOne(const zz_pE& a) { return IsOne(a._zz_pE__rep); } inline long operator==(const zz_pE& a, const zz_pE& b) { return a._zz_pE__rep == b._zz_pE__rep; } inline long operator==(const zz_pE& a, long b) { return a._zz_pE__rep == b; } inline long operator==(const zz_pE& a, const zz_p& b) { return a._zz_pE__rep == b; } inline long operator==(long a, const zz_pE& b) { return a == b._zz_pE__rep; } inline long operator==(const zz_p& a, const zz_pE& b) { return a == b._zz_pE__rep; } inline long operator!=(const zz_pE& a, const zz_pE& b) { return !(a == b); } inline long operator!=(const zz_pE& a, long b) { return !(a == b); } inline long operator!=(const zz_pE& a, const zz_p& b) { return !(a == b); } inline long operator!=(long a, const zz_pE& b) { return !(a == b); } inline long operator!=(const zz_p& a, const zz_pE& b) { return !(a == b); } // ****** norm and trace inline void trace(zz_p& x, const zz_pE& a) { TraceMod(x, a._zz_pE__rep, zz_pE::modulus()); } inline zz_p trace(const zz_pE& a) { return TraceMod(a._zz_pE__rep, zz_pE::modulus()); } inline void norm(zz_p& x, const zz_pE& a) { NormMod(x, a._zz_pE__rep, zz_pE::modulus()); } inline zz_p norm(const zz_pE& a) { return NormMod(a._zz_pE__rep, zz_pE::modulus()); } // ****** random numbers inline void random(zz_pE& x) // x = random element in zz_pE { random(x._zz_pE__rep, zz_pE::degree()); } inline zz_pE random_zz_pE() { zz_pE x; random(x); NTL_OPT_RETURN(zz_pE, x); } // ****** input/output inline NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const zz_pE& a) { return s << a._zz_pE__rep; } NTL_SNS istream& operator>>(NTL_SNS istream& s, zz_pE& x); inline const zz_pX& rep(const zz_pE& a) { return a._zz_pE__rep; } inline zz_pE& zz_pE::operator=(long a) { conv(*this, a); return *this; } inline zz_pE& zz_pE::operator=(const zz_p& a) { conv(*this, a); return *this; } inline zz_pE operator+(const zz_pE& a, const zz_pE& b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator+(const zz_pE& a, const zz_p& b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator+(const zz_pE& a, long b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator+(const zz_p& a, const zz_pE& b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator+(long a, const zz_pE& b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_pE& a, const zz_pE& b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_pE& a, const zz_p& b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_pE& a, long b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_p& a, const zz_pE& b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(long a, const zz_pE& b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_pE& a) { zz_pE x; negate(x, a); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE& operator+=(zz_pE& x, const zz_pE& b) { add(x, x, b); return x; } inline zz_pE& operator+=(zz_pE& x, const zz_p& b) { add(x, x, b); return x; } inline zz_pE& operator+=(zz_pE& x, long b) { add(x, x, b); return x; } inline zz_pE& operator-=(zz_pE& x, const zz_pE& b) { sub(x, x, b); return x; } inline zz_pE& operator-=(zz_pE& x, const zz_p& b) { sub(x, x, b); return x; } inline zz_pE& operator-=(zz_pE& x, long b) { sub(x, x, b); return x; } inline zz_pE& operator++(zz_pE& x) { add(x, x, 1); return x; } inline void operator++(zz_pE& x, int) { add(x, x, 1); } inline zz_pE& operator--(zz_pE& x) { sub(x, x, 1); return x; } inline void operator--(zz_pE& x, int) { sub(x, x, 1); } inline zz_pE operator*(const zz_pE& a, const zz_pE& b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator*(const zz_pE& a, const zz_p& b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator*(const zz_pE& a, long b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator*(const zz_p& a, const zz_pE& b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator*(long a, const zz_pE& b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE& operator*=(zz_pE& x, const zz_pE& b) { mul(x, x, b); return x; } inline zz_pE& operator*=(zz_pE& x, const zz_p& b) { mul(x, x, b); return x; } inline zz_pE& operator*=(zz_pE& x, long b) { mul(x, x, b); return x; } inline zz_pE operator/(const zz_pE& a, const zz_pE& b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator/(const zz_pE& a, const zz_p& b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator/(const zz_pE& a, long b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator/(const zz_p& a, const zz_pE& b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator/(long a, const zz_pE& b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE& operator/=(zz_pE& x, const zz_pE& b) { div(x, x, b); return x; } inline zz_pE& operator/=(zz_pE& x, const zz_p& b) { div(x, x, b); return x; } inline zz_pE& operator/=(zz_pE& x, long b) { div(x, x, b); return x; } /* additional legacy conversions for v6 conversion regime */ inline void conv(zz_pX& x, const zz_pE& a) { x = rep(a); } inline void conv(zz_pE& x, const zz_pE& a) { x = a; } /* ------------------------------------- */ NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/lzz_pEX.h000644 000765 000024 00000075050 12377144457 016467 0ustar00shoupstaff000000 000000 #ifndef NTL_zz_pEX__H #define NTL_zz_pEX__H #include NTL_OPEN_NNS class zz_pEXModulus; // forward declaration class zz_pEX { public: typedef zz_pE coeff_type; typedef zz_pEXModulus modulus_type; vec_zz_pE rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ zz_pEX() { } // initial value 0 explicit zz_pEX(long a) { *this = a; } explicit zz_pEX(const zz_p& a) { *this = a; } explicit zz_pEX(const zz_pE& a) { *this = a; } zz_pEX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } ~zz_pEX() { } void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } zz_pE& operator[](long i) { return rep[i]; } const zz_pE& operator[](long i) const { return rep[i]; } static const zz_pEX& zero(); inline zz_pEX(long i, const zz_pE& c); inline zz_pEX(long i, const zz_p& c); inline zz_pEX(long i, long c); inline zz_pEX(INIT_MONO_TYPE, long i, const zz_pE& c); inline zz_pEX(INIT_MONO_TYPE, long i, const zz_p& c); inline zz_pEX(INIT_MONO_TYPE, long i, long c); inline zz_pEX(INIT_MONO_TYPE, long i); inline zz_pEX& operator=(long a); inline zz_pEX& operator=(const zz_p& a); inline zz_pEX& operator=(const zz_pE& a); zz_pEX(zz_pEX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } }; NTL_SNS istream& operator>>(NTL_SNS istream& s, zz_pEX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const zz_pEX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const zz_pEX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const zz_pE& coeff(const zz_pEX& a, long i); // zero if i not in range const zz_pE& LeadCoeff(const zz_pEX& a); // zero if a == 0 const zz_pE& ConstTerm(const zz_pEX& a); // zero if a == 0 void SetCoeff(zz_pEX& x, long i, const zz_pE& a); void SetCoeff(zz_pEX& x, long i, const zz_p& a); void SetCoeff(zz_pEX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(zz_pEX& x, long i); // x[i] = 1, error is raised if i < 0 inline zz_pEX::zz_pEX(long i, const zz_pE& a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(long i, const zz_p& a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(long i, long a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(INIT_MONO_TYPE, long i, const zz_pE& a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(INIT_MONO_TYPE, long i, const zz_p& a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(zz_pEX& x); // x is set to the monomial X long IsX(const zz_pEX& a); // test if x = X inline void clear(zz_pEX& x) // x = 0 { x.rep.SetLength(0); } inline void set(zz_pEX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(zz_pEX& x, zz_pEX& y) // swap x & y (only pointers are swapped) { swap(x.rep, y.rep); } void random(zz_pEX& x, long n); inline zz_pEX random_zz_pEX(long n) { zz_pEX x; random(x, n); NTL_OPT_RETURN(zz_pEX, x); } // generate a random polynomial of degree < n void trunc(zz_pEX& x, const zz_pEX& a, long m); inline zz_pEX trunc(const zz_pEX& a, long m) { zz_pEX x; trunc(x, a, m); NTL_OPT_RETURN(zz_pEX, x); } // x = a % X^m void RightShift(zz_pEX& x, const zz_pEX& a, long n); inline zz_pEX RightShift(const zz_pEX& a, long n) { zz_pEX x; RightShift(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } // x = a/X^n void LeftShift(zz_pEX& x, const zz_pEX& a, long n); inline zz_pEX LeftShift(const zz_pEX& a, long n) { zz_pEX x; LeftShift(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } // x = a*X^n #ifndef NTL_TRANSITION inline zz_pEX operator>>(const zz_pEX& a, long n) { zz_pEX x; RightShift(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator<<(const zz_pEX& a, long n) { zz_pEX x; LeftShift(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator<<=(zz_pEX& x, long n) { LeftShift(x, x, n); return x; } inline zz_pEX& operator>>=(zz_pEX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(zz_pEX& x, const zz_pEX& a); inline zz_pEX diff(const zz_pEX& a) { zz_pEX x; diff(x, a); NTL_OPT_RETURN(zz_pEX, x); } // x = derivative of a void MakeMonic(zz_pEX& x); void reverse(zz_pEX& c, const zz_pEX& a, long hi); inline zz_pEX reverse(const zz_pEX& a, long hi) { zz_pEX x; reverse(x, a, hi); NTL_OPT_RETURN(zz_pEX, x); } inline void reverse(zz_pEX& c, const zz_pEX& a) { reverse(c, a, deg(a)); } inline zz_pEX reverse(const zz_pEX& a) { zz_pEX x; reverse(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline void VectorCopy(vec_zz_pE& x, const zz_pEX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_zz_pE VectorCopy(const zz_pEX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(zz_pEX& x, long a); void conv(zz_pEX& x, const ZZ& a); void conv(zz_pEX& x, const zz_p& a); void conv(zz_pEX& x, const zz_pX& a); void conv(zz_pEX& x, const zz_pE& a); void conv(zz_pEX& x, const vec_zz_pE& a); inline zz_pEX to_zz_pEX(long a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const ZZ& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const zz_p& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const zz_pX& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const zz_pE& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const vec_zz_pE& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& zz_pEX::operator=(long a) { conv(*this, a); return *this; } inline zz_pEX& zz_pEX::operator=(const zz_p& a) { conv(*this, a); return *this; } inline zz_pEX& zz_pEX::operator=(const zz_pE& a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(zz_pEX& x, const zz_pEX& a) { x = a; } inline void conv(vec_zz_pE& x, const zz_pEX& a) { x = a.rep; } class ZZX; void conv(zz_pEX& x, const ZZX& a); /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const zz_pEX& a); long IsOne(const zz_pEX& a); inline long operator==(const zz_pEX& a, const zz_pEX& b) { return a.rep == b.rep; } long operator==(const zz_pEX& a, long b); long operator==(const zz_pEX& a, const zz_p& b); long operator==(const zz_pEX& a, const zz_pE& b); inline long operator==(long a, const zz_pEX& b) { return (b == a); } inline long operator==(const zz_p& a, const zz_pEX& b) { return (b == a); } inline long operator==(const zz_pE& a, const zz_pEX& b) { return (b == a); } inline long operator!=(const zz_pEX& a, const zz_pEX& b) { return !(a == b); } inline long operator!=(const zz_pEX& a, long b) { return !(a == b); } inline long operator!=(const zz_pEX& a, const zz_p& b) { return !(a == b); } inline long operator!=(const zz_pEX& a, const zz_pE& b) { return !(a == b); } inline long operator!=(const long a, const zz_pEX& b) { return !(a == b); } inline long operator!=(const zz_p& a, const zz_pEX& b) { return !(a == b); } inline long operator!=(const zz_pE& a, const zz_pEX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); void sub(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); void negate(zz_pEX& x, const zz_pEX& a); // scalar versions void add(zz_pEX & x, const zz_pEX& a, long b); void add(zz_pEX & x, const zz_pEX& a, const zz_p& b); void add(zz_pEX & x, const zz_pEX& a, const zz_pE& b); inline void add(zz_pEX& x, const zz_pE& a, const zz_pEX& b) { add(x, b, a); } inline void add(zz_pEX& x, const zz_p& a, const zz_pEX& b) { add(x, b, a); } inline void add(zz_pEX& x, long a, const zz_pEX& b) { add(x, b, a); } void sub(zz_pEX & x, const zz_pEX& a, long b); void sub(zz_pEX & x, const zz_pEX& a, const zz_p& b); void sub(zz_pEX & x, const zz_pEX& a, const zz_pE& b); void sub(zz_pEX& x, const zz_pE& a, const zz_pEX& b); void sub(zz_pEX& x, const zz_p& a, const zz_pEX& b); void sub(zz_pEX& x, long a, const zz_pEX& b); inline zz_pEX operator+(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_pEX& a, const zz_pE& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_pEX& a, const zz_p& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_pEX& a, long b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_pE& a, const zz_pEX& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_p& a, const zz_pEX& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(long a, const zz_pEX& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pEX& a, const zz_pE& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pEX& a, const zz_p& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pEX& a, long b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pE& a, const zz_pEX& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_p& a, const zz_pEX& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(long a, const zz_pEX& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator+=(zz_pEX& x, const zz_pEX& b) { add(x, x, b); return x; } inline zz_pEX& operator+=(zz_pEX& x, const zz_pE& b) { add(x, x, b); return x; } inline zz_pEX& operator+=(zz_pEX& x, const zz_p& b) { add(x, x, b); return x; } inline zz_pEX& operator+=(zz_pEX& x, long b) { add(x, x, b); return x; } inline zz_pEX& operator-=(zz_pEX& x, const zz_pEX& b) { sub(x, x, b); return x; } inline zz_pEX& operator-=(zz_pEX& x, const zz_pE& b) { sub(x, x, b); return x; } inline zz_pEX& operator-=(zz_pEX& x, const zz_p& b) { sub(x, x, b); return x; } inline zz_pEX& operator-=(zz_pEX& x, long b) { sub(x, x, b); return x; } inline zz_pEX operator-(const zz_pEX& a) { zz_pEX x; negate(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator++(zz_pEX& x) { add(x, x, 1); return x; } inline void operator++(zz_pEX& x, int) { add(x, x, 1); } inline zz_pEX& operator--(zz_pEX& x) { sub(x, x, 1); return x; } inline void operator--(zz_pEX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a * b void sqr(zz_pEX& x, const zz_pEX& a); inline zz_pEX sqr(const zz_pEX& a) { zz_pEX x; sqr(x, a); NTL_OPT_RETURN(zz_pEX, x); } // x = a^2 void mul(zz_pEX & x, const zz_pEX& a, long b); void mul(zz_pEX & x, const zz_pEX& a, const zz_p& b); void mul(zz_pEX & x, const zz_pEX& a, const zz_pE& b); inline void mul(zz_pEX& x, long a, const zz_pEX& b) { mul(x, b, a); } inline void mul(zz_pEX& x, const zz_p& a, const zz_pEX& b) { mul(x, b, a); } inline void mul(zz_pEX& x, const zz_pE& a, const zz_pEX& b) { mul(x, b, a); } void MulTrunc(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, long n); inline zz_pEX MulTrunc(const zz_pEX& a, const zz_pEX& b, long n) { zz_pEX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(zz_pEX, x); } // x = a * b % X^n void SqrTrunc(zz_pEX& x, const zz_pEX& a, long n); inline zz_pEX SqrTrunc(const zz_pEX& a, long n) { zz_pEX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } // x = a*a % X^n inline zz_pEX operator*(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_pEX& a, const zz_pE& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_pEX& a, const zz_p& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_pEX& a, long b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_pE& a, const zz_pEX& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_p& a, const zz_pEX& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(long a, const zz_pEX& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator*=(zz_pEX& x, const zz_pEX& b) { mul(x, x, b); return x; } inline zz_pEX& operator*=(zz_pEX& x, const zz_pE& b) { mul(x, x, b); return x; } inline zz_pEX& operator*=(zz_pEX& x, const zz_p& b) { mul(x, x, b); return x; } inline zz_pEX& operator*=(zz_pEX& x, long b) { mul(x, x, b); return x; } void power(zz_pEX& x, const zz_pEX& a, long e); inline zz_pEX power(const zz_pEX& a, long e) { zz_pEX x; power(x, a, e); NTL_OPT_RETURN(zz_pEX, x); } /************************************************************* Division **************************************************************/ void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b); // q = a/b, r = a%b void div(zz_pEX& q, const zz_pEX& a, const zz_pEX& b); void div(zz_pEX& q, const zz_pEX& a, const zz_pE& b); void div(zz_pEX& q, const zz_pEX& a, const zz_p& b); void div(zz_pEX& q, const zz_pEX& a, long b); // q = a/b void rem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b); // r = a%b long divide(zz_pEX& q, const zz_pEX& a, const zz_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const zz_pEX& a, const zz_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(zz_pEX& x, const zz_pEX& a, long m); inline zz_pEX InvTrunc(const zz_pEX& a, long m) { zz_pEX x; InvTrunc(x, a, m); NTL_OPT_RETURN(zz_pEX, x); } // computes x = a^{-1} % X^m // constant term must be invertible inline zz_pEX operator/(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; div(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator/(const zz_pEX& a, const zz_pE& b) { zz_pEX x; div(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator/(const zz_pEX& a, const zz_p& b) { zz_pEX x; div(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator/(const zz_pEX& a, long b) { zz_pEX x; div(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator/=(zz_pEX& x, const zz_pEX& b) { div(x, x, b); return x; } inline zz_pEX& operator/=(zz_pEX& x, const zz_pE& b) { div(x, x, b); return x; } inline zz_pEX& operator/=(zz_pEX& x, const zz_p& b) { div(x, x, b); return x; } inline zz_pEX& operator/=(zz_pEX& x, long b) { div(x, x, b); return x; } inline zz_pEX operator%(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; rem(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator%=(zz_pEX& x, const zz_pEX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); inline zz_pEX GCD(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; GCD(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(zz_pEX& d, zz_pEX& s, zz_pEX& t, const zz_pEX& a, const zz_pEX& b); // d = gcd(a,b), a s + b t = d /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the zz_pEXModulus data structure and associated routines below. void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEX& f); inline zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEX& f) { zz_pEX x; MulMod(x, a, b, f); NTL_OPT_RETURN(zz_pEX, x); } // x = (a * b) % f void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); inline zz_pEX SqrMod(const zz_pEX& a, const zz_pEX& f) { zz_pEX x; SqrMod(x, a, f); NTL_OPT_RETURN(zz_pEX, x); } // x = a^2 % f void MulByXMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); inline zz_pEX MulByXMod(const zz_pEX& a, const zz_pEX& f) { zz_pEX x; MulByXMod(x, a, f); NTL_OPT_RETURN(zz_pEX, x); } // x = (a * X) mod f void InvMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); inline zz_pEX InvMod(const zz_pEX& a, const zz_pEX& f) { zz_pEX x; InvMod(x, a, f); NTL_OPT_RETURN(zz_pEX, x); } // x = a^{-1} % f, error is a is not invertible long InvModStatus(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build zz_pEXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class zz_pEXModulus { public: zz_pEXModulus(); ~zz_pEXModulus(); zz_pEXModulus(const zz_pEX& ff); zz_pEX f; // the modulus operator const zz_pEX& () const { return f; } const zz_pEX& val() const { return f; } long n; // deg(f) long method; zz_pEX h0; zz_pE hlc; zz_pEX f0; vec_zz_pE tracevec; // mutable }; inline long deg(const zz_pEXModulus& F) { return F.n; } void build(zz_pEXModulus& F, const zz_pEX& f); void rem(zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F); void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F); void div(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F); void MulMod(zz_pEX& c, const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F); inline zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F) { zz_pEX x; MulMod(x, a, b, F); NTL_OPT_RETURN(zz_pEX, x); } void SqrMod(zz_pEX& c, const zz_pEX& a, const zz_pEXModulus& F); inline zz_pEX SqrMod(const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX x; SqrMod(x, a, F); NTL_OPT_RETURN(zz_pEX, x); } void PowerMod(zz_pEX& h, const zz_pEX& g, const ZZ& e, const zz_pEXModulus& F); inline void PowerMod(zz_pEX& h, const zz_pEX& g, long e, const zz_pEXModulus& F) { PowerMod(h, g, ZZ_expo(e), F); } inline zz_pEX PowerMod(const zz_pEX& g, const ZZ& e, const zz_pEXModulus& F) { zz_pEX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX PowerMod(const zz_pEX& g, long e, const zz_pEXModulus& F) { zz_pEX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(zz_pEX, x); } void PowerXMod(zz_pEX& hh, const ZZ& e, const zz_pEXModulus& F); inline void PowerXMod(zz_pEX& h, long e, const zz_pEXModulus& F) { PowerXMod(h, ZZ_expo(e), F); } inline zz_pEX PowerXMod(const ZZ& e, const zz_pEXModulus& F) { zz_pEX x; PowerXMod(x, e, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX PowerXMod(long e, const zz_pEXModulus& F) { zz_pEX x; PowerXMod(x, e, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator%(const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX x; rem(x, a, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator%=(zz_pEX& x, const zz_pEXModulus& F) { rem(x, x, F); return x; } inline zz_pEX operator/(const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX x; div(x, a, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator/=(zz_pEX& x, const zz_pEXModulus& F) { div(x, x, F); return x; } /***************************************************************** vectors of zz_pEX's *****************************************************************/ typedef Vec vec_zz_pEX; /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(zz_pEX& x, const vec_zz_pE& a); inline zz_pEX BuildFromRoots(const vec_zz_pE& a) { zz_pEX x; BuildFromRoots(x, a); NTL_OPT_RETURN(zz_pEX, x); } // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(zz_pE& b, const zz_pEX& f, const zz_pE& a); inline zz_pE eval(const zz_pEX& f, const zz_pE& a) { zz_pE x; eval(x, f, a); NTL_OPT_RETURN(zz_pE, x); } // b = f(a) void eval(vec_zz_pE& b, const zz_pEX& f, const vec_zz_pE& a); inline vec_zz_pE eval(const zz_pEX& f, const vec_zz_pE& a) { vec_zz_pE x; eval(x, f, a); NTL_OPT_RETURN(vec_zz_pE, x); } // b[i] = f(a[i]) inline void eval(zz_pE& b, const zz_pX& f, const zz_pE& a) { conv(b, CompMod(f, rep(a), zz_pE::modulus())); } inline zz_pE eval(const zz_pX& f, const zz_pE& a) { zz_pE x; eval(x, f, a); NTL_OPT_RETURN(zz_pE, x); } // b = f(a) void interpolate(zz_pEX& f, const vec_zz_pE& a, const vec_zz_pE& b); inline zz_pEX interpolate(const vec_zz_pE& a, const vec_zz_pE& b) { zz_pEX x; interpolate(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } // computes f such that f(a[i]) = b[i] /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F); inline zz_pEX CompMod(const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F) { zz_pEX x; CompMod(x, g, h, F); NTL_OPT_RETURN(zz_pEX, x); } // x = g(h) mod f void Comp2Mod(zz_pEX& x1, zz_pEX& x2, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& h, const zz_pEXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(zz_pEX& x1, zz_pEX& x2, zz_pEX& x3, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& g3, const zz_pEX& h, const zz_pEXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If zz_pEXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If zz_pEXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, zz_pEXArgBound = 0. // If a single h is going to be used with many g's // then you should build a zz_pEXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If zz_pEXArgBound > 0, a table of size less than m may be built. struct zz_pEXArgument { vec_zz_pEX H; }; NTL_THREAD_LOCAL extern long zz_pEXArgBound; void build(zz_pEXArgument& H, const zz_pEX& h, const zz_pEXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEXArgument& H, const zz_pEXModulus& F); inline zz_pEX CompMod(const zz_pEX& g, const zz_pEXArgument& H, const zz_pEXModulus& F) { zz_pEX x; CompMod(x, g, H, F); NTL_OPT_RETURN(zz_pEX, x); } void MinPolySeq(zz_pEX& h, const vec_zz_pE& a, long m); inline zz_pEX MinPolySeq(const vec_zz_pE& a, long m) { zz_pEX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(zz_pEX, x); } void MinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F); inline zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F) { zz_pEX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(zz_pEX, x); } void MinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pEX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pEX, x); } void ProbMinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F); inline zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F) { zz_pEX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(zz_pEX, x); } void ProbMinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pEX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pEX, x); } void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F); inline zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F) { zz_pEX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(zz_pEX, x); } void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pEX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pEX, x); } struct zz_pEXTransMultiplier { zz_pEX f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(zz_pEXTransMultiplier& B, const zz_pEX& b, const zz_pEXModulus& F); void TransMulMod(zz_pEX& x, const zz_pEX& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F); void UpdateMap(vec_zz_pE& x, const vec_zz_pE& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F); inline vec_zz_pE UpdateMap(const vec_zz_pE& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F) { vec_zz_pE x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_zz_pE, x); } void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F); inline vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F) { vec_zz_pE x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_zz_pE, x); } void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F); inline vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k, const zz_pEX& H, const zz_pEXModulus& F) { vec_zz_pE x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_zz_pE, x); } inline void project(zz_pE& x, const vec_zz_pE& a, const zz_pEX& b) { InnerProduct(x, a, b.rep); } inline zz_pE project(const vec_zz_pE& a, const zz_pEX& b) { zz_pE x; InnerProduct(x, a, b.rep); NTL_OPT_RETURN(zz_pE, x); } /***************************************************************** modular composition and minimal polynonomials in towers ******************************************************************/ // composition void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEXArgument& A, const zz_pEXModulus& F); inline zz_pEX CompTower(const zz_pX& g, const zz_pEXArgument& A, const zz_pEXModulus& F) { zz_pEX x; CompTower(x, g, A, F); NTL_OPT_RETURN(zz_pEX, x); } void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F); inline zz_pEX CompTower(const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F) { zz_pEX x; CompTower(x, g, h, F); NTL_OPT_RETURN(zz_pEX, x); } // prob min poly void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pX x; ProbMinPolyTower(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F) { ProbMinPolyTower(h, g, F, deg(F)*zz_pE::degree()); } inline zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F) { zz_pX x; ProbMinPolyTower(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // min poly void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pX x; MinPolyTower(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F) { MinPolyTower(h, g, F, deg(F)*zz_pE::degree()); } inline zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F) { zz_pX x; MinPolyTower(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // irred poly void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pX x; IrredPolyTower(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F) { IrredPolyTower(h, g, F, deg(F)*zz_pE::degree()); } inline zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F) { zz_pX x; IrredPolyTower(x, g, F); NTL_OPT_RETURN(zz_pX, x); } /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_zz_pE& S, const zz_pEX& f); inline vec_zz_pE TraceVec(const zz_pEX& f) { vec_zz_pE x; TraceVec(x, f); NTL_OPT_RETURN(vec_zz_pE, x); } void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEXModulus& F); inline zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& F) { zz_pE x; TraceMod(x, a, F); NTL_OPT_RETURN(zz_pE, x); } void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f); inline zz_pE TraceMod(const zz_pEX& a, const zz_pEX& f) { zz_pE x; TraceMod(x, a, f); NTL_OPT_RETURN(zz_pE, x); } void NormMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f); inline zz_pE NormMod(const zz_pEX& a, const zz_pEX& f) { zz_pE x; NormMod(x, a, f); NTL_OPT_RETURN(zz_pE, x); } void resultant(zz_pE& rres, const zz_pEX& a, const zz_pEX& b); inline zz_pE resultant(const zz_pEX& a, const zz_pEX& b) { zz_pE x; resultant(x, a, b); NTL_OPT_RETURN(zz_pE, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/lzz_pEXFactoring.h000644 000765 000024 00000012550 12377144457 020320 0ustar00shoupstaff000000 000000 #ifndef NTL_zz_pEXFactoring__H #define NTL_zz_pEXFactoring__H #include NTL_OPEN_NNS void SquareFreeDecomp(vec_pair_zz_pEX_long& u, const zz_pEX& f); inline vec_pair_zz_pEX_long SquareFreeDecomp(const zz_pEX& f) { vec_pair_zz_pEX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_zz_pE& x, const zz_pEX& f); inline vec_zz_pE FindRoots(const zz_pEX& f) { vec_zz_pE x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(zz_pE& root, const zz_pEX& f); inline zz_pE FindRoot(const zz_pEX& f) { zz_pE x; FindRoot(x, f); return x; } // finds a single root of f. // assumes that f is monic and splits into distinct linear factors NTL_THREAD_LOCAL extern long zz_pEX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF NTL_THREAD_LOCAL extern char zz_pEX_stem[]; // Determines filename stem for external storage in NewDDF. NTL_THREAD_LOCAL extern double zz_pEXFileThresh; // external files are used for baby/giant steps if size // of these tables exceeds zz_pEXFileThresh KB. void NewDDF(vec_pair_zz_pEX_long& factors, const zz_pEX& f, const zz_pEX& h, long verbose=0); inline vec_pair_zz_pEX_long NewDDF(const zz_pEX& f, const zz_pEX& h, long verbose=0) { vec_pair_zz_pEX_long x; NewDDF(x, f, h, verbose); return x; } void EDF(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& b, long d, long verbose=0); inline vec_zz_pEX EDF(const zz_pEX& f, const zz_pEX& b, long d, long verbose=0) { vec_zz_pEX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0); inline vec_zz_pEX RootEDF(const zz_pEX& f, long verbose=0) { vec_zz_pEX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0); inline vec_zz_pEX SFCanZass(const zz_pEX& f, long verbose=0) { vec_zz_pEX x; SFCanZass(x, f, verbose); return x; } // Assumes f is monic and square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void CanZass(vec_pair_zz_pEX_long& factors, const zz_pEX& f, long verbose=0); inline vec_pair_zz_pEX_long CanZass(const zz_pEX& f, long verbose=0) { vec_pair_zz_pEX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(zz_pEX& f, const vec_pair_zz_pEX_long& v); inline zz_pEX mul(const vec_pair_zz_pEX_long& v) { zz_pEX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const zz_pEX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const zz_pEX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const zz_pEX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(zz_pEX& f, long n); inline zz_pEX BuildIrred_zz_pEX(long n) { zz_pEX x; BuildIrred(x, n); NTL_OPT_RETURN(zz_pEX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(zz_pEX& f, const zz_pEX& g); inline zz_pEX BuildRandomIrred(const zz_pEX& g) { zz_pEX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(zz_pEX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long RecComputeDegree(const zz_pEX& h, const zz_pEXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long IterComputeDegree(const zz_pEX& h, const zz_pEXModulus& F); void TraceMap(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& b); inline zz_pEX TraceMap(const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& b) { zz_pEX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see "zz_pEX.h") void PowerCompose(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F); inline zz_pEX PowerCompose(const zz_pEX& a, long d, const zz_pEXModulus& F) { zz_pEX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see "zz_pEX.h") NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/lzz_pX.h000644 000765 000024 00000105467 12377144457 016370 0ustar00shoupstaff000000 000000 #ifndef NTL_zz_pX__H #define NTL_zz_pX__H #include #include #include NTL_OPEN_NNS // some cross-over points #define NTL_zz_pX_MOD_CROSSOVER (zz_pX_mod_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_MUL_CROSSOVER (zz_pX_mul_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_NEWTON_CROSSOVER (zz_pX_newton_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_DIV_CROSSOVER (zz_pX_div_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_HalfGCD_CROSSOVER (zz_pX_halfgcd_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_GCD_CROSSOVER (zz_pX_gcd_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_BERMASS_CROSSOVER (zz_pX_bermass_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_TRACE_CROSSOVER (zz_pX_trace_crossover[zz_pInfo->PrimeCnt]) extern const long zz_pX_mod_crossover[]; extern const long zz_pX_mul_crossover[]; extern const long zz_pX_newton_crossover[]; extern const long zz_pX_div_crossover[]; extern const long zz_pX_halfgcd_crossover[]; extern const long zz_pX_gcd_crossover[]; extern const long zz_pX_bermass_crossover[]; extern const long zz_pX_trace_crossover[]; /************************************************************ zz_pX The class zz_pX implements polynomial arithmetic modulo p. Polynomials are represented as vec_zz_p's. If f is a zz_pX, then f.rep is a vec_zz_p. The zero polynomial is represented as a zero length vector. Otherwise. f.rep[0] is the constant-term, and f.rep[f.rep.length()-1] is the leading coefficient, which is always non-zero. The member f.rep is public, so the vector representation is fully accessible. Use the member function normalize() to strip leading zeros. **************************************************************/ class zz_pE; // forward declaration class zz_pXModulus; class fftRep; class zz_pXMultiplier; class zz_pX { public: typedef zz_p coeff_type; typedef zz_pE residue_type; typedef zz_pXModulus modulus_type; typedef zz_pXMultiplier multiplier_type; typedef fftRep fft_type; vec_zz_p rep; typedef vec_zz_p VectorBaseType; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ zz_pX() {} // initial value 0 explicit zz_pX(long a) { *this = a; } explicit zz_pX(zz_p a) { *this = a; } zz_pX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } zz_pX(const zz_pX& a) : rep(a.rep) { } // initial value is a inline zz_pX(long i, zz_p c); inline zz_pX(long i, long c); inline zz_pX(INIT_MONO_TYPE, long i, zz_p c); inline zz_pX(INIT_MONO_TYPE, long i, long c); inline zz_pX(INIT_MONO_TYPE, long i); zz_pX& operator=(const zz_pX& a) { rep = a.rep; return *this; } inline zz_pX& operator=(long a); inline zz_pX& operator=(zz_p a); ~zz_pX() { } void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } zz_p& operator[](long i) { return rep[i]; } const zz_p& operator[](long i) const { return rep[i]; } static const zz_pX& zero(); zz_pX(zz_pX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } }; /******************************************************************** input and output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, amd a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary integers which are then reduced modulo p, and leading zeros stripped. *********************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, zz_pX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const zz_pX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const zz_pX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const zz_p coeff(const zz_pX& a, long i); // zero if i not in range void GetCoeff(zz_p& x, const zz_pX& a, long i); // x = a[i], or zero if i not in range const zz_p LeadCoeff(const zz_pX& a); // zero if a == 0 const zz_p ConstTerm(const zz_pX& a); // zero if a == 0 void SetCoeff(zz_pX& x, long i, zz_p a); // x[i] = a, error is raised if i < 0 void SetCoeff(zz_pX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(zz_pX& x, long i); // x[i] = 1, error is raised if i < 0 inline zz_pX::zz_pX(long i, zz_p a) { SetCoeff(*this, i, a); } inline zz_pX::zz_pX(long i, long a) { SetCoeff(*this, i, a); } inline zz_pX::zz_pX(INIT_MONO_TYPE, long i, zz_p a) { SetCoeff(*this, i, a); } inline zz_pX::zz_pX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline zz_pX::zz_pX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(zz_pX& x); // x is set to the monomial X long IsX(const zz_pX& a); // test if x = X inline void clear(zz_pX& x) // x = 0 { x.rep.SetLength(0); } inline void set(zz_pX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(zz_pX& x, zz_pX& y) // swap x & y (only pointers are swapped) { swap(x.rep, y.rep); } void random(zz_pX& x, long n); inline zz_pX random_zz_pX(long n) { zz_pX x; random(x, n); NTL_OPT_RETURN(zz_pX, x); } // generate a random polynomial of degree < n void trunc(zz_pX& x, const zz_pX& a, long m); // x = a % X^m inline zz_pX trunc(const zz_pX& a, long m) { zz_pX x; trunc(x, a, m); NTL_OPT_RETURN(zz_pX, x); } void RightShift(zz_pX& x, const zz_pX& a, long n); // x = a/X^n inline zz_pX RightShift(const zz_pX& a, long n) { zz_pX x; RightShift(x, a, n); NTL_OPT_RETURN(zz_pX, x); } void LeftShift(zz_pX& x, const zz_pX& a, long n); // x = a*X^n inline zz_pX LeftShift(const zz_pX& a, long n) { zz_pX x; LeftShift(x, a, n); NTL_OPT_RETURN(zz_pX, x); } #ifndef NTL_TRANSITION inline zz_pX operator>>(const zz_pX& a, long n) { zz_pX x; RightShift(x, a, n); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator<<(const zz_pX& a, long n) { zz_pX x; LeftShift(x, a, n); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator<<=(zz_pX& x, long n) { LeftShift(x, x, n); return x; } inline zz_pX& operator>>=(zz_pX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(zz_pX& x, const zz_pX& a); // x = derivative of a inline zz_pX diff(const zz_pX& a) { zz_pX x; diff(x, a); NTL_OPT_RETURN(zz_pX, x); } void MakeMonic(zz_pX& x); // makes x monic void reverse(zz_pX& c, const zz_pX& a, long hi); inline zz_pX reverse(const zz_pX& a, long hi) { zz_pX x; reverse(x, a, hi); NTL_OPT_RETURN(zz_pX, x); } inline void reverse(zz_pX& c, const zz_pX& a) { reverse(c, a, deg(a)); } inline zz_pX reverse(const zz_pX& a) { zz_pX x; reverse(x, a); NTL_OPT_RETURN(zz_pX, x); } inline void VectorCopy(vec_zz_p& x, const zz_pX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_zz_p VectorCopy(const zz_pX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(zz_pX& x, long a); inline zz_pX to_zz_pX(long a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } void conv(zz_pX& x, const ZZ& a); inline zz_pX to_zz_pX(const ZZ& a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } void conv(zz_pX& x, zz_p a); inline zz_pX to_zz_pX(zz_p a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } void conv(zz_pX& x, const vec_zz_p& a); inline zz_pX to_zz_pX(const vec_zz_p& a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& zz_pX::operator=(zz_p a) { conv(*this, a); return *this; } inline zz_pX& zz_pX::operator=(long a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(zz_pX& x, const zz_pX& a) { x = a; } inline void conv(vec_zz_p& x, const zz_pX& a) { x = a.rep; } /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const zz_pX& a); long IsOne(const zz_pX& a); inline long operator==(const zz_pX& a, const zz_pX& b) { return a.rep == b.rep; } inline long operator!=(const zz_pX& a, const zz_pX& b) { return !(a == b); } long operator==(const zz_pX& a, long b); long operator==(const zz_pX& a, zz_p b); inline long operator==(long a, const zz_pX& b) { return b == a; } inline long operator==(zz_p a, const zz_pX& b) { return b == a; } inline long operator!=(const zz_pX& a, long b) { return !(a == b); } inline long operator!=(const zz_pX& a, zz_p b) { return !(a == b); } inline long operator!=(long a, const zz_pX& b) { return !(a == b); } inline long operator!=(zz_p a, const zz_pX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a + b void sub(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a - b void negate(zz_pX& x, const zz_pX& a); // x = -a // scalar versions void add(zz_pX & x, const zz_pX& a, zz_p b); // x = a + b inline void add(zz_pX& x, const zz_pX& a, long b) { add(x, a, to_zz_p(b)); } inline void add(zz_pX& x, zz_p a, const zz_pX& b) { add(x, b, a); } inline void add(zz_pX& x, long a, const zz_pX& b) { add(x, b, a); } void sub(zz_pX & x, const zz_pX& a, zz_p b); // x = a - b inline void sub(zz_pX& x, const zz_pX& a, long b) { sub(x, a, to_zz_p(b)); } void sub(zz_pX& x, zz_p a, const zz_pX& b); inline void sub(zz_pX& x, long a, const zz_pX& b) { sub(x, to_zz_p(a), b); } inline zz_pX operator+(const zz_pX& a, const zz_pX& b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator+(const zz_pX& a, zz_p b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator+(const zz_pX& a, long b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator+(zz_p a, const zz_pX& b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator+(long a, const zz_pX& b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(const zz_pX& a, const zz_pX& b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(const zz_pX& a, zz_p b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(const zz_pX& a, long b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(zz_p a, const zz_pX& b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(long a, const zz_pX& b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator+=(zz_pX& x, const zz_pX& b) { add(x, x, b); return x; } inline zz_pX& operator+=(zz_pX& x, zz_p b) { add(x, x, b); return x; } inline zz_pX& operator+=(zz_pX& x, long b) { add(x, x, b); return x; } inline zz_pX& operator-=(zz_pX& x, const zz_pX& b) { sub(x, x, b); return x; } inline zz_pX& operator-=(zz_pX& x, zz_p b) { sub(x, x, b); return x; } inline zz_pX& operator-=(zz_pX& x, long b) { sub(x, x, b); return x; } inline zz_pX operator-(const zz_pX& a) { zz_pX x; negate(x, a); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator++(zz_pX& x) { add(x, x, 1); return x; } inline void operator++(zz_pX& x, int) { add(x, x, 1); } inline zz_pX& operator--(zz_pX& x) { sub(x, x, 1); return x; } inline void operator--(zz_pX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a * b void sqr(zz_pX& x, const zz_pX& a); inline zz_pX sqr(const zz_pX& a) { zz_pX x; sqr(x, a); NTL_OPT_RETURN(zz_pX, x); } // x = a^2 void mul(zz_pX& x, const zz_pX& a, zz_p b); inline void mul(zz_pX& x, const zz_pX& a, long b) { mul(x, a, to_zz_p(b)); } inline void mul(zz_pX& x, zz_p a, const zz_pX& b) { mul(x, b, a); } inline void mul(zz_pX& x, long a, const zz_pX& b) { mul(x, b, a); } inline zz_pX operator*(const zz_pX& a, const zz_pX& b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator*(const zz_pX& a, zz_p b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator*(const zz_pX& a, long b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator*(zz_p a, const zz_pX& b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator*(long a, const zz_pX& b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator*=(zz_pX& x, const zz_pX& b) { mul(x, x, b); return x; } inline zz_pX& operator*=(zz_pX& x, zz_p b) { mul(x, x, b); return x; } inline zz_pX& operator*=(zz_pX& x, long b) { mul(x, x, b); return x; } void PlainMul(zz_pX& x, const zz_pX& a, const zz_pX& b); // always uses the "classical" algorithm void PlainSqr(zz_pX& x, const zz_pX& a); // always uses the "classical" algorithm void FFTMul(zz_pX& x, const zz_pX& a, const zz_pX& b); // always uses the FFT void FFTSqr(zz_pX& x, const zz_pX& a); // always uses the FFT void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n); // x = a * b % X^n inline zz_pX MulTrunc(const zz_pX& a, const zz_pX& b, long n) { zz_pX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(zz_pX, x); } void PlainMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n); void FFTMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n); void SqrTrunc(zz_pX& x, const zz_pX& a, long n); // x = a^2 % X^n inline zz_pX SqrTrunc(const zz_pX& a, long n) { zz_pX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(zz_pX, x); } void PlainSqrTrunc(zz_pX& x, const zz_pX& a, long n); void FFTSqrTrunc(zz_pX& x, const zz_pX& a, long n); void power(zz_pX& x, const zz_pX& a, long e); inline zz_pX power(const zz_pX& a, long e) { zz_pX x; power(x, a, e); NTL_OPT_RETURN(zz_pX, x); } // The following data structures and routines allow one // to hand-craft various algorithms, using the FFT convolution // algorithms directly. // Look in the file zz_pX.c for examples. // FFT representation of polynomials class fftRep { public: long k; // a 2^k point representation long MaxK; // maximum space allocated long *tbl[4]; long NumPrimes; fftRep(const fftRep&); fftRep& operator=(const fftRep&); void SetSize(long NewK); fftRep() { k = MaxK = -1; NumPrimes = 0; } fftRep(INIT_SIZE_TYPE, long InitK) { k = MaxK = -1; NumPrimes = 0; SetSize(InitK); } ~fftRep(); }; void TofftRep(fftRep& y, const zz_pX& x, long k, long lo, long hi); // computes an n = 2^k point convolution of x[lo..hi]. inline void TofftRep(fftRep& y, const zz_pX& x, long k) { TofftRep(y, x, k, 0, deg(x)); } void RevTofftRep(fftRep& y, const vec_zz_p& x, long k, long lo, long hi, long offset); // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. void FromfftRep(zz_pX& x, fftRep& y, long lo, long hi); // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed // NOTE: this version destroys the data in y // non-destructive versions of the above void NDFromfftRep(zz_pX& x, const fftRep& y, long lo, long hi, fftRep& temp); void NDFromfftRep(zz_pX& x, const fftRep& y, long lo, long hi); void RevFromfftRep(vec_zz_p& x, fftRep& y, long lo, long hi); // converts from FFT-representation to coefficient representation // using "inverted" evaluation points. // only the coefficients lo..hi are computed void FromfftRep(zz_p* x, fftRep& y, long lo, long hi); // convert out coefficients lo..hi of y, store result in x. // no normalization is done. // direct manipulation of FFT reps void mul(fftRep& z, const fftRep& x, const fftRep& y); void sub(fftRep& z, const fftRep& x, const fftRep& y); void add(fftRep& z, const fftRep& x, const fftRep& y); void reduce(fftRep& x, const fftRep& a, long k); // reduces a 2^l point FFT-rep to a 2^k point FFT-rep void AddExpand(fftRep& x, const fftRep& a); // x = x + (an "expanded" version of a) /************************************************************* Division **************************************************************/ void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b); // q = a/b, r = a%b void div(zz_pX& q, const zz_pX& a, const zz_pX& b); // q = a/b void div(zz_pX& q, const zz_pX& a, zz_p b); inline void div(zz_pX& q, const zz_pX& a, long b) { div(q, a, to_zz_p(b)); } void rem(zz_pX& r, const zz_pX& a, const zz_pX& b); // r = a%b long divide(zz_pX& q, const zz_pX& a, const zz_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const zz_pX& a, const zz_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(zz_pX& x, const zz_pX& a, long m); // computes x = a^{-1} % X^m // constant term must be non-zero inline zz_pX InvTrunc(const zz_pX& a, long m) { zz_pX x; InvTrunc(x, a, m); NTL_OPT_RETURN(zz_pX, x); } // These always use "classical" arithmetic void PlainDivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b); void PlainDiv(zz_pX& q, const zz_pX& a, const zz_pX& b); void PlainRem(zz_pX& r, const zz_pX& a, const zz_pX& b); // These always use FFT arithmetic void FFTDivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b); void FFTDiv(zz_pX& q, const zz_pX& a, const zz_pX& b); void FFTRem(zz_pX& r, const zz_pX& a, const zz_pX& b); void PlainInvTrunc(zz_pX& x, const zz_pX& a, long m); // always uses "classical" algorithm // ALIAS RESTRICTION: input may not alias output void NewtonInvTrunc(zz_pX& x, const zz_pX& a, long m); // uses a Newton Iteration with the FFT. // ALIAS RESTRICTION: input may not alias output inline zz_pX operator/(const zz_pX& a, const zz_pX& b) { zz_pX x; div(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator/(const zz_pX& a, zz_p b) { zz_pX x; div(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator/(const zz_pX& a, long b) { zz_pX x; div(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator/=(zz_pX& x, zz_p b) { div(x, x, b); return x; } inline zz_pX& operator/=(zz_pX& x, long b) { div(x, x, b); return x; } inline zz_pX& operator/=(zz_pX& x, const zz_pX& b) { div(x, x, b); return x; } inline zz_pX operator%(const zz_pX& a, const zz_pX& b) { zz_pX x; rem(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator%=(zz_pX& x, const zz_pX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). inline zz_pX GCD(const zz_pX& a, const zz_pX& b) { zz_pX x; GCD(x, a, b); NTL_OPT_RETURN(zz_pX, x); } void XGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b); // d = gcd(a,b), a s + b t = d void PlainXGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b); // same as above, but uses classical algorithm void PlainGCD(zz_pX& x, const zz_pX& a, const zz_pX& b); // always uses "cdlassical" arithmetic class zz_pXMatrix { private: zz_pXMatrix(const zz_pXMatrix&); // disable zz_pX elts[2][2]; public: zz_pXMatrix() { } ~zz_pXMatrix() { } void operator=(const zz_pXMatrix&); zz_pX& operator() (long i, long j) { return elts[i][j]; } const zz_pX& operator() (long i, long j) const { return elts[i][j]; } }; void HalfGCD(zz_pXMatrix& M_out, const zz_pX& U, const zz_pX& V, long d_red); // deg(U) > deg(V), 1 <= d_red <= deg(U)+1. // // This computes a 2 x 2 polynomial matrix M_out such that // M_out * (U, V)^T = (U', V')^T, // where U', V' are consecutive polynomials in the Euclidean remainder // sequence of U, V, and V' is the polynomial of highest degree // satisfying deg(V') <= deg(U) - d_red. void XHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red); // same as above, except that U is replaced by U', and V by V' /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the zz_pXModulus data structure and associated routines below. void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pX& f); // x = (a * b) % f inline zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pX& f) { zz_pX x; MulMod(x, a, b, f); NTL_OPT_RETURN(zz_pX, x); } void SqrMod(zz_pX& x, const zz_pX& a, const zz_pX& f); // x = a^2 % f inline zz_pX SqrMod(const zz_pX& a, const zz_pX& f) { zz_pX x; SqrMod(x, a, f); NTL_OPT_RETURN(zz_pX, x); } void MulByXMod(zz_pX& x, const zz_pX& a, const zz_pX& f); // x = (a * X) mod f inline zz_pX MulByXMod(const zz_pX& a, const zz_pX& f) { zz_pX x; MulByXMod(x, a, f); NTL_OPT_RETURN(zz_pX, x); } void InvMod(zz_pX& x, const zz_pX& a, const zz_pX& f); // x = a^{-1} % f, error is a is not invertible inline zz_pX InvMod(const zz_pX& a, const zz_pX& f) { zz_pX x; InvMod(x, a, f); NTL_OPT_RETURN(zz_pX, x); } long InvModStatus(zz_pX& x, const zz_pX& a, const zz_pX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build zz_pXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class zz_pXModulus { public: zz_pXModulus() : UseFFT(0), n(-1) { } ~zz_pXModulus() { } zz_pX f; // the modulus long UseFFT;// flag indicating whether FFT should be used. long n; // n = deg(f) long k; // least k s/t 2^k >= n long l; // least l s/t 2^l >= 2n-3 fftRep FRep; // 2^k point rep of f // H = rev((rev(f))^{-1} rem X^{n-1}) fftRep HRep; // 2^l point rep of H vec_zz_p tracevec; // mutable zz_pXModulus(const zz_pX& ff); operator const zz_pX& () const { return f; } const zz_pX& val() const { return f; } }; inline long deg(const zz_pXModulus& F) { return F.n; } void build(zz_pXModulus& F, const zz_pX& f); // deg(f) > 0 void rem21(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); // x = a % f // deg(a) <= 2(n-1), where n = F.n = deg(f) void rem(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); // x = a % f, no restrictions on deg(a); makes repeated calls to rem21 inline zz_pX operator%(const zz_pX& a, const zz_pXModulus& F) { zz_pX x; rem(x, a, F); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator%=(zz_pX& x, const zz_pXModulus& F) { rem(x, x, F); return x; } void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pXModulus& F); void div(zz_pX& q, const zz_pX& a, const zz_pXModulus& F); inline zz_pX operator/(const zz_pX& a, const zz_pXModulus& F) { zz_pX x; div(x, a, F); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator/=(zz_pX& x, const zz_pXModulus& F) { div(x, x, F); return x; } void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pXModulus& F); // x = (a * b) % f // deg(a), deg(b) < n inline zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pXModulus& F) { zz_pX x; MulMod(x, a, b, F); NTL_OPT_RETURN(zz_pX, x); } void SqrMod(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); // x = a^2 % f // deg(a) < n inline zz_pX SqrMod(const zz_pX& a, const zz_pXModulus& F) { zz_pX x; SqrMod(x, a, F); NTL_OPT_RETURN(zz_pX, x); } void PowerMod(zz_pX& x, const zz_pX& a, const ZZ& e, const zz_pXModulus& F); // x = a^e % f, e >= 0 inline zz_pX PowerMod(const zz_pX& a, const ZZ& e, const zz_pXModulus& F) { zz_pX x; PowerMod(x, a, e, F); NTL_OPT_RETURN(zz_pX, x); } inline void PowerMod(zz_pX& x, const zz_pX& a, long e, const zz_pXModulus& F) { PowerMod(x, a, ZZ_expo(e), F); } inline zz_pX PowerMod(const zz_pX& a, long e, const zz_pXModulus& F) { zz_pX x; PowerMod(x, a, e, F); NTL_OPT_RETURN(zz_pX, x); } void PowerXMod(zz_pX& x, const ZZ& e, const zz_pXModulus& F); // x = X^e % f, e >= 0 inline zz_pX PowerXMod(const ZZ& e, const zz_pXModulus& F) { zz_pX x; PowerXMod(x, e, F); NTL_OPT_RETURN(zz_pX, x); } inline void PowerXMod(zz_pX& x, long e, const zz_pXModulus& F) { PowerXMod(x, ZZ_expo(e), F); } inline zz_pX PowerXMod(long e, const zz_pXModulus& F) { zz_pX x; PowerXMod(x, e, F); NTL_OPT_RETURN(zz_pX, x); } void PowerXPlusAMod(zz_pX& x, zz_p a, const ZZ& e, const zz_pXModulus& F); // x = (X + a)^e % f, e >= 0 inline zz_pX PowerXPlusAMod(zz_p a, const ZZ& e, const zz_pXModulus& F) { zz_pX x; PowerXPlusAMod(x, a, e, F); NTL_OPT_RETURN(zz_pX, x); } inline void PowerXPlusAMod(zz_pX& x, zz_p a, long e, const zz_pXModulus& F) { PowerXPlusAMod(x, a, ZZ_expo(e), F); } inline zz_pX PowerXPlusAMod(zz_p a, long e, const zz_pXModulus& F) { zz_pX x; PowerXPlusAMod(x, a, e, F); NTL_OPT_RETURN(zz_pX, x); } // If you need to compute a * b % f for a fixed b, but for many a's // (for example, computing powers of b modulo f), it is // much more efficient to first build a zz_pXMultiplier B for b, // and then use the routine below. class zz_pXMultiplier { public: zz_pXMultiplier() : UseFFT(0) { } zz_pXMultiplier(const zz_pX& b, const zz_pXModulus& F); ~zz_pXMultiplier() { } zz_pX b; long UseFFT; fftRep B1; fftRep B2; const zz_pX& val() const { return b; } }; void build(zz_pXMultiplier& B, const zz_pX& b, const zz_pXModulus& F); void MulMod(zz_pX& x, const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F); // x = (a * b) % f inline zz_pX MulMod(const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F) { zz_pX x; MulMod(x, a, B, F); NTL_OPT_RETURN(zz_pX, x); } /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(zz_pX& x, const vec_zz_p& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() inline zz_pX BuildFromRoots(const vec_zz_p& a) { zz_pX x; BuildFromRoots(x, a); NTL_OPT_RETURN(zz_pX, x); } void eval(zz_p& b, const zz_pX& f, zz_p a); // b = f(a) inline zz_p eval(const zz_pX& f, zz_p a) { zz_p x; eval(x, f, a); return x; } void eval(vec_zz_p& b, const zz_pX& f, const vec_zz_p& a); // b[i] = f(a[i]) inline vec_zz_p eval(const zz_pX& f, const vec_zz_p& a) { vec_zz_p x; eval(x, f, a); NTL_OPT_RETURN(vec_zz_p, x); } void interpolate(zz_pX& f, const vec_zz_p& a, const vec_zz_p& b); // computes f such that f(a[i]) = b[i] inline zz_pX interpolate(const vec_zz_p& a, const vec_zz_p& b) { zz_pX x; interpolate(x, a, b); NTL_OPT_RETURN(zz_pX, x); } /***************************************************************** vectors of zz_pX's *****************************************************************/ typedef Vec vec_zz_pX; /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ // algorithms for computing g(h) mod f void CompMod(zz_pX& x, const zz_pX& g, const zz_pX& h, const zz_pXModulus& F); // x = g(h) mod f inline zz_pX CompMod(const zz_pX& g, const zz_pX& h, const zz_pXModulus& F) { zz_pX x; CompMod(x, g, h, F); NTL_OPT_RETURN(zz_pX, x); } void Comp2Mod(zz_pX& x1, zz_pX& x2, const zz_pX& g1, const zz_pX& g2, const zz_pX& h, const zz_pXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(zz_pX& x1, zz_pX& x2, zz_pX& x3, const zz_pX& g1, const zz_pX& g2, const zz_pX& g3, const zz_pX& h, const zz_pXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If zz_pXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If zz_pXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, zz_pXArgBound = 0. // If a single h is going to be used with many g's // then you should build a zz_pXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If zz_pXArgBound > 0, a table of size less than m may be built. struct zz_pXArgument { vec_zz_pX H; }; NTL_THREAD_LOCAL extern long zz_pXArgBound; void build(zz_pXArgument& H, const zz_pX& h, const zz_pXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& H, const zz_pXModulus& F); inline zz_pX CompMod(const zz_pX& g, const zz_pXArgument& H, const zz_pXModulus& F) { zz_pX x; CompMod(x, g, H, F); NTL_OPT_RETURN(zz_pX, x); } #ifndef NTL_TRANSITION void UpdateMap(vec_zz_p& x, const vec_zz_p& a, const zz_pXMultiplier& B, const zz_pXModulus& F); inline vec_zz_p UpdateMap(const vec_zz_p& a, const zz_pXMultiplier& B, const zz_pXModulus& F) { vec_zz_p x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_zz_p, x); } #endif /* computes (a, b), (a, (b*X)%f), ..., (a, (b*X^{n-1})%f), where ( , ) denotes the vector inner product. This is really a "transposed" MulMod by B. */ void PlainUpdateMap(vec_zz_p& x, const vec_zz_p& a, const zz_pX& b, const zz_pX& f); // same as above, but uses only classical arithmetic void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F); // computes (a, 1), (a, h), ..., (a, h^{k-1} % f) // this is really a "transposed" compose. inline vec_zz_p ProjectPowers(const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F) { vec_zz_p x; ProjectPowers(x, a, k, h, F); NTL_OPT_RETURN(vec_zz_p, x); } void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F); inline vec_zz_p ProjectPowers(const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F) { vec_zz_p x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_zz_p, x); } // same as above, but uses a pre-computed zz_pXArgument inline void project(zz_p& x, const vec_zz_p& a, const zz_pX& b) { InnerProduct(x, a, b.rep); } inline zz_p project(const vec_zz_p& a, const zz_pX& b) { zz_p x; project(x, a, b); return x; } void MinPolySeq(zz_pX& h, const vec_zz_p& a, long m); // computes the minimum polynomial of a linealy generated sequence; // m is a bound on the degree of the polynomial; // required: a.length() >= 2*m inline zz_pX MinPolySeq(const vec_zz_p& a, long m) { zz_pX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(zz_pX, x); } void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); inline zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } inline zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F) { zz_pX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // computes the monic minimal polynomial if (g mod f). // m = a bound on the degree of the minimal polynomial. // If this argument is not supplied, it defaults to deg(f). // The algorithm is probabilistic, always returns a divisor of // the minimal polynomial, and returns a proper divisor with // probability at most m/p. void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); inline zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F) { MinPolyMod(h, g, F, F.n); } inline zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F) { zz_pX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // same as above, but guarantees that result is correct void IrredPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); inline zz_pX IrredPolyMod(const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void IrredPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F) { IrredPolyMod(h, g, F, F.n); } inline zz_pX IrredPolyMod(const zz_pX& g, const zz_pXModulus& F) { zz_pX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // same as above, but assumes that f is irreducible, // or at least that the minimal poly of g is itself irreducible. // The algorithm is deterministic (and is always correct). /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_zz_p& S, const zz_pX& f); inline vec_zz_p TraceVec(const zz_pX& f) { vec_zz_p x; TraceVec(x, f); NTL_OPT_RETURN(vec_zz_p, x); } void FastTraceVec(vec_zz_p& S, const zz_pX& f); void PlainTraceVec(vec_zz_p& S, const zz_pX& f); void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F); inline zz_p TraceMod(const zz_pX& a, const zz_pXModulus& F) { zz_p x; TraceMod(x, a, F); return x; } void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f); inline zz_p TraceMod(const zz_pX& a, const zz_pX& f) { zz_p x; TraceMod(x, a, f); return x; } void ComputeTraceVec(const zz_pXModulus& F); void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f); inline zz_p NormMod(const zz_pX& a, const zz_pX& f) { zz_p x; NormMod(x, a, f); return x; } void resultant(zz_p& rres, const zz_pX& a, const zz_pX& b); inline zz_p resultant(const zz_pX& a, const zz_pX& b) { zz_p x; resultant(x, a, b); return x; } void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& f); // g = char poly of (a mod f) // only implemented for p >= deg(f)+1 inline zz_pX CharPolyMod(const zz_pX& a, const zz_pX& f) { zz_pX x; CharPolyMod(x, a, f); NTL_OPT_RETURN(zz_pX, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/lzz_pXFactoring.h000644 000765 000024 00000015442 12377144457 020216 0ustar00shoupstaff000000 000000 #ifndef NTL_zz_pXFactoring__H #define NTL_zz_pXFactoring__H #include #include #include NTL_OPEN_NNS /************************************************************ factorization routines ************************************************************/ void SquareFreeDecomp(vec_pair_zz_pX_long& u, const zz_pX& f); inline vec_pair_zz_pX_long SquareFreeDecomp(const zz_pX& f) { vec_pair_zz_pX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_zz_p& x, const zz_pX& f); inline vec_zz_p FindRoots(const zz_pX& f) { vec_zz_p x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(zz_p& root, const zz_pX& f); inline zz_p FindRoot(const zz_pX& f) { zz_p x; FindRoot(x, f); return x; } // finds a single root of ff. // assumes that f is monic and splits into distinct linear factors void SFBerlekamp(vec_zz_pX& factors, const zz_pX& f, long verbose=0); inline vec_zz_pX SFBerlekamp(const zz_pX& f, long verbose=0) { vec_zz_pX x; SFBerlekamp(x, f, verbose); return x; } // Assumes f is square-free and monic. // returns list of factors of f. // Uses "Berlekamp" appraoch. void berlekamp(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose=0); inline vec_pair_zz_pX_long berlekamp(const zz_pX& f, long verbose=0) { vec_pair_zz_pX_long x; berlekamp(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Berlekamp" appraoch. NTL_THREAD_LOCAL extern long zz_pX_BlockingFactor; // Controls GCD blocking for DDF. void DDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h, long verbose=0); inline vec_pair_zz_pX_long DDF(const zz_pX& f, const zz_pX& h, long verbose=0) { vec_pair_zz_pX_long x; DDF(x, f, h, verbose); return x; } // Performs distinct-degree factorization. // Assumes f is monic and square-free, and h = X^p mod f // Obsolete: see NewDDF, below. NTL_THREAD_LOCAL extern long zz_pX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF void NewDDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h, long verbose=0); inline vec_pair_zz_pX_long NewDDF(const zz_pX& f, const zz_pX& h, long verbose=0) { vec_pair_zz_pX_long x; NewDDF(x, f, h, verbose); return x; } // same as above, but uses baby-step/giant-step method void EDF(vec_zz_pX& factors, const zz_pX& f, const zz_pX& b, long d, long verbose=0); inline vec_zz_pX EDF(const zz_pX& f, const zz_pX& b, long d, long verbose=0) { vec_zz_pX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_zz_pX& factors, const zz_pX& f, long verbose=0); inline vec_zz_pX RootEDF(const zz_pX& f, long verbose=0) { vec_zz_pX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_zz_pX& factors, const zz_pX& f, long verbose=0); inline vec_zz_pX SFCanZass(const zz_pX& f, long verbose=0) { vec_zz_pX x; SFCanZass(x, f, verbose); return x; } // Assumes f is square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void SFCanZass1(vec_pair_zz_pX_long& u, zz_pX& h, const zz_pX& f, long verbose=0); // Not intended for general use. void SFCanZass2(vec_zz_pX& factors, const vec_pair_zz_pX_long& u, const zz_pX& h, long verbose=0); // Not intended for general use. void CanZass(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose=0); inline vec_pair_zz_pX_long CanZass(const zz_pX& f, long verbose=0) { vec_pair_zz_pX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(zz_pX& f, const vec_pair_zz_pX_long& v); inline zz_pX mul(const vec_pair_zz_pX_long& v) { zz_pX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const zz_pX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const zz_pX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const zz_pX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(zz_pX& f, long n); inline zz_pX BuildIrred_zz_pX(long n) { zz_pX x; BuildIrred(x, n); NTL_OPT_RETURN(zz_pX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(zz_pX& f, const zz_pX& g); inline zz_pX BuildRandomIrred(const zz_pX& g) { zz_pX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(zz_pX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long ComputeDegree(const zz_pX& h, const zz_pXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long ProbComputeDegree(const zz_pX& h, const zz_pXModulus& F); // same as above, but uses a slightly faster probabilistic algorithm // the return value may be 0 or may be too big, but for large p // (relative to n), this happens with very low probability. void TraceMap(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& b); inline zz_pX TraceMap(const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& b) { zz_pX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see "zz_pX.h") void PowerCompose(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F); inline zz_pX PowerCompose(const zz_pX& a, long d, const zz_pXModulus& F) { zz_pX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see "zz_pX.h") NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_GF2.h000644 000765 000024 00000010225 12377144457 016304 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_GF2__H #define NTL_mat_GF2__H #include #include NTL_OPEN_NNS typedef Mat mat_GF2; // some backward compaitibilty stuff inline void conv(mat_GF2& x, const vec_vec_GF2& a) { MakeMatrix(x, a); } inline mat_GF2 to_mat_GF2(const vec_vec_GF2& a) { mat_GF2 x; conv(x, a); NTL_OPT_RETURN(mat_GF2, x); } void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); inline void sub(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { add(X, A, B); } inline void negate(mat_GF2& X, const mat_GF2& A) { X = A; } void mul(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b); void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B); void mul(mat_GF2& X, const mat_GF2& A, GF2 b); inline void mul(mat_GF2& X, GF2 a, const mat_GF2& B) { mul(X, B, a); } inline void mul(mat_GF2& X, const mat_GF2& A, long b) { mul(X, A, to_GF2(b)); } inline void mul(mat_GF2& X, long a, const mat_GF2& B) { mul(X, B, a); } void ident(mat_GF2& X, long n); inline mat_GF2 ident_mat_GF2(long n) { mat_GF2 X; ident(X, n); NTL_OPT_RETURN(mat_GF2, X); } long IsIdent(const mat_GF2& A, long n); void transpose(mat_GF2& X, const mat_GF2& A); void solve(ref_GF2 d, vec_GF2& X, const mat_GF2& A, const vec_GF2& b); void inv(ref_GF2 d, mat_GF2& X, const mat_GF2& A); inline void sqr(mat_GF2& X, const mat_GF2& A) { mul(X, A, A); } inline mat_GF2 sqr(const mat_GF2& A) { mat_GF2 X; sqr(X, A); NTL_OPT_RETURN(mat_GF2, X); } void inv(mat_GF2& X, const mat_GF2& A); inline mat_GF2 inv(const mat_GF2& A) { mat_GF2 X; inv(X, A); NTL_OPT_RETURN(mat_GF2, X); } void power(mat_GF2& X, const mat_GF2& A, const ZZ& e); inline mat_GF2 power(const mat_GF2& A, const ZZ& e) { mat_GF2 X; power(X, A, e); NTL_OPT_RETURN(mat_GF2, X); } inline void power(mat_GF2& X, const mat_GF2& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_GF2 power(const mat_GF2& A, long e) { mat_GF2 X; power(X, A, e); NTL_OPT_RETURN(mat_GF2, X); } void diag(mat_GF2& X, long n, GF2 d); inline mat_GF2 diag(long n, GF2 d) { mat_GF2 X; diag(X, n, d); NTL_OPT_RETURN(mat_GF2, X); } long IsDiag(const mat_GF2& A, long n, GF2 d); long gauss(mat_GF2& M); long gauss(mat_GF2& M, long w); void image(mat_GF2& X, const mat_GF2& A); void kernel(mat_GF2& X, const mat_GF2& A); void determinant(ref_GF2 x, const mat_GF2& a); inline GF2 determinant(const mat_GF2& a) { GF2 x; determinant(x, a); return x; } inline mat_GF2 transpose(const mat_GF2 & a) { mat_GF2 x; transpose(x, a); NTL_OPT_RETURN(mat_GF2, x); } void clear(mat_GF2& a); // x = 0 (dimension unchanged) long IsZero(const mat_GF2& a); // test if a is the zero matrix (any dimension) // operator notation: mat_GF2 operator+(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator-(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator*(const mat_GF2& a, const mat_GF2& b); inline mat_GF2 operator-(const mat_GF2& a) { return a; } // matrix/scalar multiplication: inline mat_GF2 operator*(const mat_GF2& a, GF2 b) { mat_GF2 x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2, x); } inline mat_GF2 operator*(const mat_GF2& a, long b) { mat_GF2 x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2, x); } inline mat_GF2 operator*(GF2 a, const mat_GF2& b) { mat_GF2 x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2, x); } inline mat_GF2 operator*(long a, const mat_GF2& b) { mat_GF2 x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2, x); } // matrix/vector multiplication: vec_GF2 operator*(const mat_GF2& a, const vec_GF2& b); vec_GF2 operator*(const vec_GF2& a, const mat_GF2& b); // assignment operator notation: inline mat_GF2& operator+=(mat_GF2& x, const mat_GF2& a) { add(x, x, a); return x; } inline mat_GF2& operator-=(mat_GF2& x, const mat_GF2& a) { sub(x, x, a); return x; } inline mat_GF2& operator*=(mat_GF2& x, const mat_GF2& a) { mul(x, x, a); return x; } inline mat_GF2& operator*=(mat_GF2& x, GF2 a) { mul(x, x, a); return x; } inline mat_GF2& operator*=(mat_GF2& x, long a) { mul(x, x, a); return x; } inline vec_GF2& operator*=(vec_GF2& x, const mat_GF2& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_GF2E.h000644 000765 000024 00000011127 12377144457 016413 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_GF2E__H #define NTL_mat_GF2E__H #include #include NTL_OPEN_NNS typedef Mat mat_GF2E; void add(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); inline void sub(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B) { add(X, A, B); } inline void negate(mat_GF2E& X, const mat_GF2E& A) { X = A; } void mul(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); void mul(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b); void mul(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B); void mul(mat_GF2E& X, const mat_GF2E& A, const GF2E& b); inline void mul(mat_GF2E& X, const GF2E& a, const mat_GF2E& B) { mul(X, B, a); } void mul(mat_GF2E& X, const mat_GF2E& A, GF2 b); inline void mul(mat_GF2E& X, GF2 a, const mat_GF2E& B) { mul(X, B, a); } inline void mul(mat_GF2E& X, const mat_GF2E& A, long b) { mul(X, A, to_GF2(b)); } inline void mul(mat_GF2E& X, long a, const mat_GF2E& B) { mul(X, B, a); } void ident(mat_GF2E& X, long n); inline mat_GF2E ident_mat_GF2E(long n) { mat_GF2E X; ident(X, n); NTL_OPT_RETURN(mat_GF2E, X); } void determinant(GF2E& d, const mat_GF2E& A); long IsIdent(const mat_GF2E& A, long n); void transpose(mat_GF2E& X, const mat_GF2E& A); void solve(GF2E& d, vec_GF2E& X, const mat_GF2E& A, const vec_GF2E& b); void inv(GF2E& d, mat_GF2E& X, const mat_GF2E& A); inline void sqr(mat_GF2E& X, const mat_GF2E& A) { mul(X, A, A); } inline mat_GF2E sqr(const mat_GF2E& A) { mat_GF2E X; sqr(X, A); NTL_OPT_RETURN(mat_GF2E, X); } void inv(mat_GF2E& X, const mat_GF2E& A); inline mat_GF2E inv(const mat_GF2E& A) { mat_GF2E X; inv(X, A); NTL_OPT_RETURN(mat_GF2E, X); } void power(mat_GF2E& X, const mat_GF2E& A, const ZZ& e); inline mat_GF2E power(const mat_GF2E& A, const ZZ& e) { mat_GF2E X; power(X, A, e); NTL_OPT_RETURN(mat_GF2E, X); } inline void power(mat_GF2E& X, const mat_GF2E& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_GF2E power(const mat_GF2E& A, long e) { mat_GF2E X; power(X, A, e); NTL_OPT_RETURN(mat_GF2E, X); } void diag(mat_GF2E& X, long n, const GF2E& d); inline mat_GF2E diag(long n, const GF2E& d) { mat_GF2E X; diag(X, n, d); NTL_OPT_RETURN(mat_GF2E, X); } long IsDiag(const mat_GF2E& A, long n, const GF2E& d); long gauss(mat_GF2E& M); long gauss(mat_GF2E& M, long w); void image(mat_GF2E& X, const mat_GF2E& A); void kernel(mat_GF2E& X, const mat_GF2E& A); // miscellaneous: inline GF2E determinant(const mat_GF2E& a) { GF2E x; determinant(x, a); return x; } // functional variant of determinant inline mat_GF2E transpose(const mat_GF2E& a) { mat_GF2E x; transpose(x, a); NTL_OPT_RETURN(mat_GF2E, x); } void clear(mat_GF2E& a); // x = 0 (dimension unchanged) long IsZero(const mat_GF2E& a); // test if a is the zero matrix (any dimension) // operator notation: mat_GF2E operator+(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator-(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator*(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator-(const mat_GF2E& a); // matrix/scalar multiplication: inline mat_GF2E operator*(const mat_GF2E& a, const GF2E& b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(const mat_GF2E& a, GF2 b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(const mat_GF2E& a, long b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(const GF2E& a, const mat_GF2E& b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(GF2 a, const mat_GF2E& b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(long a, const mat_GF2E& b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } // matrix/vector multiplication: vec_GF2E operator*(const mat_GF2E& a, const vec_GF2E& b); vec_GF2E operator*(const vec_GF2E& a, const mat_GF2E& b); // assignment operator notation: inline mat_GF2E& operator+=(mat_GF2E& x, const mat_GF2E& a) { add(x, x, a); return x; } inline mat_GF2E& operator-=(mat_GF2E& x, const mat_GF2E& a) { sub(x, x, a); return x; } inline mat_GF2E& operator*=(mat_GF2E& x, const mat_GF2E& a) { mul(x, x, a); return x; } inline mat_GF2E& operator*=(mat_GF2E& x, const GF2E& a) { mul(x, x, a); return x; } inline mat_GF2E& operator*=(mat_GF2E& x, GF2 a) { mul(x, x, a); return x; } inline mat_GF2E& operator*=(mat_GF2E& x, long a) { mul(x, x, a); return x; } inline vec_GF2E& operator*=(vec_GF2E& x, const mat_GF2E& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_RR.h000644 000765 000024 00000007167 12377144457 016264 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_RR__H #define NTL_mat_RR__H #include #include NTL_OPEN_NNS typedef Mat mat_RR; void add(mat_RR& X, const mat_RR& A, const mat_RR& B); void sub(mat_RR& X, const mat_RR& A, const mat_RR& B); void negate(mat_RR& X, const mat_RR& A); void mul(mat_RR& X, const mat_RR& A, const mat_RR& B); void mul(vec_RR& x, const mat_RR& A, const vec_RR& b); void mul(vec_RR& x, const vec_RR& a, const mat_RR& B); void mul(mat_RR& X, const mat_RR& A, const RR& b); void mul(mat_RR& X, const mat_RR& A, double b); inline void mul(mat_RR& X, const RR& a, const mat_RR& B) { mul(X, B, a); } inline void mul(mat_RR& X, double a, const mat_RR& B) { mul(X, B, a); } void ident(mat_RR& X, long n); inline mat_RR ident_mat_RR(long n) { mat_RR X; ident(X, n); NTL_OPT_RETURN(mat_RR, X); } void determinant(RR& d, const mat_RR& A); long IsIdent(const mat_RR& A, long n); void transpose(mat_RR& X, const mat_RR& A); void solve(RR& d, vec_RR& X, const mat_RR& A, const vec_RR& b); void inv(RR& d, mat_RR& X, const mat_RR& A); inline void sqr(mat_RR& X, const mat_RR& A) { mul(X, A, A); } inline mat_RR sqr(const mat_RR& A) { mat_RR X; sqr(X, A); NTL_OPT_RETURN(mat_RR, X); } void inv(mat_RR& X, const mat_RR& A); inline mat_RR inv(const mat_RR& A) { mat_RR X; inv(X, A); NTL_OPT_RETURN(mat_RR, X); } void power(mat_RR& X, const mat_RR& A, const ZZ& e); inline mat_RR power(const mat_RR& A, const ZZ& e) { mat_RR X; power(X, A, e); NTL_OPT_RETURN(mat_RR, X); } inline void power(mat_RR& X, const mat_RR& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_RR power(const mat_RR& A, long e) { mat_RR X; power(X, A, e); NTL_OPT_RETURN(mat_RR, X); } void diag(mat_RR& X, long n, const RR& d); inline mat_RR diag(long n, const RR& d) { mat_RR X; diag(X, n, d); NTL_OPT_RETURN(mat_RR, X); } long IsDiag(const mat_RR& A, long n, const RR& d); // miscellaneous: RR determinant(const mat_RR& a); // functional variant of determinant inline mat_RR transpose(const mat_RR & a) { mat_RR x; transpose(x, a); NTL_OPT_RETURN(mat_RR, x); } void clear(mat_RR& a); // x = 0 (dimension unchanged) long IsZero(const mat_RR& a); // test if a is the zero matrix (any dimension) // operator notation: mat_RR operator+(const mat_RR& a, const mat_RR& b); mat_RR operator-(const mat_RR& a, const mat_RR& b); mat_RR operator*(const mat_RR& a, const mat_RR& b); mat_RR operator-(const mat_RR& a); // matrix/vector multiplication: vec_RR operator*(const mat_RR& a, const vec_RR& b); vec_RR operator*(const vec_RR& a, const mat_RR& b); // matrix/scalar multiplication: inline mat_RR operator*(const mat_RR& a, const RR& b) { mat_RR x; mul(x, a, b); NTL_OPT_RETURN(mat_RR, x); } inline mat_RR operator*(const mat_RR& a, double b) { mat_RR x; mul(x, a, b); NTL_OPT_RETURN(mat_RR, x); } inline mat_RR operator*(const RR& a, const mat_RR& b) { mat_RR x; mul(x, a, b); NTL_OPT_RETURN(mat_RR, x); } inline mat_RR operator*(double a, const mat_RR& b) { mat_RR x; mul(x, a, b); NTL_OPT_RETURN(mat_RR, x); } // assignment operator notation: inline mat_RR& operator+=(mat_RR& x, const mat_RR& a) { add(x, x, a); return x; } inline mat_RR& operator-=(mat_RR& x, const mat_RR& a) { sub(x, x, a); return x; } inline mat_RR& operator*=(mat_RR& x, const mat_RR& a) { mul(x, x, a); return x; } inline mat_RR& operator*=(mat_RR& x, const RR& a) { mul(x, x, a); return x; } inline mat_RR& operator*=(mat_RR& x, double a) { mul(x, x, a); return x; } inline vec_RR& operator*=(vec_RR& x, const mat_RR& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_ZZ.h000644 000765 000024 00000010600 12377144457 016266 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_ZZ__H #define NTL_mat_ZZ__H #include #include #include #include NTL_OPEN_NNS typedef Mat mat_ZZ; void add(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); void sub(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); void negate(mat_ZZ& X, const mat_ZZ& A); void mul(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); void mul(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b); void mul(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B); void mul(mat_ZZ& X, const mat_ZZ& A, const ZZ& b); inline void mul(mat_ZZ& X, const ZZ& a, const mat_ZZ& B) { mul(X, B, a); } void mul(mat_ZZ& X, const mat_ZZ& A, long b); inline void mul(mat_ZZ& X, long a, const mat_ZZ& B) { mul(X, B, a); } void ident(mat_ZZ& X, long n); inline mat_ZZ ident_mat_ZZ(long n) { mat_ZZ X; ident(X, n); NTL_OPT_RETURN(mat_ZZ, X); } long IsIdent(const mat_ZZ& A, long n); void diag(mat_ZZ& X, long n, const ZZ& d); inline mat_ZZ diag(long n, const ZZ& d) { mat_ZZ X; diag(X, n, d); NTL_OPT_RETURN(mat_ZZ, X); } long IsDiag(const mat_ZZ& A, long n, const ZZ& d); void determinant(ZZ& d, const mat_ZZ& A, long deterministic=0); void solve(ZZ& d, vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b, long deterministic=0); void solve1(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b); inline void HenselSolve1(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b) { solve1(d_out, x_out, A, b); } // for backward compatability only void inv(ZZ& d, mat_ZZ& X, const mat_ZZ& A, long deterministic=0); inline void sqr(mat_ZZ& X, const mat_ZZ& A) { mul(X, A, A); } inline mat_ZZ sqr(const mat_ZZ& A) { mat_ZZ X; sqr(X, A); NTL_OPT_RETURN(mat_ZZ, X); } void inv(mat_ZZ& X, const mat_ZZ& A); inline mat_ZZ inv(const mat_ZZ& A) { mat_ZZ X; inv(X, A); NTL_OPT_RETURN(mat_ZZ, X); } void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e); inline mat_ZZ power(const mat_ZZ& A, const ZZ& e) { mat_ZZ X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ, X); } inline void power(mat_ZZ& X, const mat_ZZ& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_ZZ power(const mat_ZZ& A, long e) { mat_ZZ X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ, X); } void transpose(mat_ZZ& X, const mat_ZZ& A); inline mat_ZZ transpose(const mat_ZZ& A) { mat_ZZ x; transpose(x, A); NTL_OPT_RETURN(mat_ZZ, x); } void conv(mat_zz_p& x, const mat_ZZ& a); inline mat_zz_p to_mat_zz_p(const mat_ZZ& a) { mat_zz_p x; conv(x, a); NTL_OPT_RETURN(mat_zz_p, x); } void conv(mat_ZZ_p& x, const mat_ZZ& a); inline mat_ZZ_p to_mat_ZZ_p(const mat_ZZ& a) { mat_ZZ_p x; conv(x, a); NTL_OPT_RETURN(mat_ZZ_p, x); } long CRT(mat_ZZ& g, ZZ& a, const mat_zz_p& G); // miscellaneous: inline ZZ determinant(const mat_ZZ& a, long deterministic=0) { ZZ x; determinant(x, a, deterministic); return x; } // functional variant of determinant void clear(mat_ZZ& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ operator+(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator-(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator*(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator-(const mat_ZZ& a); // matrix/scalar multiplication: inline mat_ZZ operator*(const mat_ZZ& a, const ZZ& b) { mat_ZZ x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ, x); } inline mat_ZZ operator*(const mat_ZZ& a, long b) { mat_ZZ x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ, x); } inline mat_ZZ operator*(const ZZ& a, const mat_ZZ& b) { mat_ZZ x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ, x); } inline mat_ZZ operator*(long a, const mat_ZZ& b) { mat_ZZ x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ, x); } // matrix/vector multiplication: vec_ZZ operator*(const mat_ZZ& a, const vec_ZZ& b); vec_ZZ operator*(const vec_ZZ& a, const mat_ZZ& b); // assignment operator notation: inline mat_ZZ& operator+=(mat_ZZ& x, const mat_ZZ& a) { add(x, x, a); return x; } inline mat_ZZ& operator-=(mat_ZZ& x, const mat_ZZ& a) { sub(x, x, a); return x; } inline mat_ZZ& operator*=(mat_ZZ& x, const mat_ZZ& a) { mul(x, x, a); return x; } inline mat_ZZ& operator*=(mat_ZZ& x, const ZZ& a) { mul(x, x, a); return x; } inline mat_ZZ& operator*=(mat_ZZ& x, long a) { mul(x, x, a); return x; } inline vec_ZZ& operator*=(vec_ZZ& x, const mat_ZZ& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_ZZ_p.h000644 000765 000024 00000010123 12377144457 016605 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_ZZ_p__H #define NTL_mat_ZZ_p__H #include #include #include NTL_OPEN_NNS typedef Mat mat_ZZ_p; void add(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); void sub(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); void negate(mat_ZZ_p& X, const mat_ZZ_p& A); void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); void mul(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b); void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B); void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ_p& b); void mul(mat_ZZ_p& X, const mat_ZZ_p& A, long b); inline void mul(mat_ZZ_p& X, const ZZ_p& a, const mat_ZZ_p& B) { mul(X, B, a); } inline void mul(mat_ZZ_p& X, long a, const mat_ZZ_p& B) { mul(X, B, a); } void ident(mat_ZZ_p& X, long n); inline mat_ZZ_p ident_mat_ZZ_p(long n) { mat_ZZ_p X; ident(X, n); NTL_OPT_RETURN(mat_ZZ_p, X); } void determinant(ZZ_p& d, const mat_ZZ_p& A); long IsIdent(const mat_ZZ_p& A, long n); void transpose(mat_ZZ_p& X, const mat_ZZ_p& A); void solve(ZZ_p& d, vec_ZZ_p& X, const mat_ZZ_p& A, const vec_ZZ_p& b); void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A); inline void sqr(mat_ZZ_p& X, const mat_ZZ_p& A) { mul(X, A, A); } inline mat_ZZ_p sqr(const mat_ZZ_p& A) { mat_ZZ_p X; sqr(X, A); NTL_OPT_RETURN(mat_ZZ_p, X); } void inv(mat_ZZ_p& X, const mat_ZZ_p& A); inline mat_ZZ_p inv(const mat_ZZ_p& A) { mat_ZZ_p X; inv(X, A); NTL_OPT_RETURN(mat_ZZ_p, X); } void power(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ& e); inline mat_ZZ_p power(const mat_ZZ_p& A, const ZZ& e) { mat_ZZ_p X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ_p, X); } inline void power(mat_ZZ_p& X, const mat_ZZ_p& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_ZZ_p power(const mat_ZZ_p& A, long e) { mat_ZZ_p X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ_p, X); } void diag(mat_ZZ_p& X, long n, const ZZ_p& d); inline mat_ZZ_p diag(long n, const ZZ_p& d) { mat_ZZ_p X; diag(X, n, d); NTL_OPT_RETURN(mat_ZZ_p, X); } long IsDiag(const mat_ZZ_p& A, long n, const ZZ_p& d); long gauss(mat_ZZ_p& M); long gauss(mat_ZZ_p& M, long w); void image(mat_ZZ_p& X, const mat_ZZ_p& A); void kernel(mat_ZZ_p& X, const mat_ZZ_p& A); inline ZZ_p determinant(const mat_ZZ_p& a) { ZZ_p x; determinant(x, a); return x; } // functional variant of determinant inline mat_ZZ_p transpose(const mat_ZZ_p & a) { mat_ZZ_p x; transpose(x, a); NTL_OPT_RETURN(mat_ZZ_p, x); } void clear(mat_ZZ_p& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ_p& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ_p operator+(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator-(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator*(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator-(const mat_ZZ_p& a); // matrix/scalar multiplication: inline mat_ZZ_p operator*(const mat_ZZ_p& a, const ZZ_p& b) { mat_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_p, x); } inline mat_ZZ_p operator*(const mat_ZZ_p& a, long b) { mat_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_p, x); } inline mat_ZZ_p operator*(const ZZ_p& a, const mat_ZZ_p& b) { mat_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_p, x); } inline mat_ZZ_p operator*(long a, const mat_ZZ_p& b) { mat_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_p, x); } // matrix/vector multiplication: vec_ZZ_p operator*(const mat_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator*(const vec_ZZ_p& a, const mat_ZZ_p& b); // assignment operator notation: inline mat_ZZ_p& operator+=(mat_ZZ_p& x, const mat_ZZ_p& a) { add(x, x, a); return x; } inline mat_ZZ_p& operator-=(mat_ZZ_p& x, const mat_ZZ_p& a) { sub(x, x, a); return x; } inline mat_ZZ_p& operator*=(mat_ZZ_p& x, const mat_ZZ_p& a) { mul(x, x, a); return x; } inline mat_ZZ_p& operator*=(mat_ZZ_p& x, const ZZ_p& a) { mul(x, x, a); return x; } inline mat_ZZ_p& operator*=(mat_ZZ_p& x, long a) { mul(x, x, a); return x; } inline vec_ZZ_p& operator*=(vec_ZZ_p& x, const mat_ZZ_p& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_ZZ_pE.h000644 000765 000024 00000011220 12377144457 016711 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_ZZ_pE__H #define NTL_mat_ZZ_pE__H #include NTL_OPEN_NNS typedef Mat mat_ZZ_pE; void add(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); void sub(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); void negate(mat_ZZ_pE& X, const mat_ZZ_pE& A); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); void mul(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b); void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_pE& b); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_p& b); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, long b); inline void mul(mat_ZZ_pE& X, const ZZ_pE& a, const mat_ZZ_pE& B) { mul(X, B, a); } inline void mul(mat_ZZ_pE& X, const ZZ_p& a, const mat_ZZ_pE& B) { mul(X, B, a); } inline void mul(mat_ZZ_pE& X, long a, const mat_ZZ_pE& B) { mul(X, B, a); } void ident(mat_ZZ_pE& X, long n); inline mat_ZZ_pE ident_mat_ZZ_pE(long n) { mat_ZZ_pE X; ident(X, n); NTL_OPT_RETURN(mat_ZZ_pE, X); } void determinant(ZZ_pE& d, const mat_ZZ_pE& A); inline ZZ_pE determinant(const mat_ZZ_pE& A) { ZZ_pE d; determinant(d, A); NTL_OPT_RETURN(ZZ_pE, d); } long IsIdent(const mat_ZZ_pE& A, long n); void transpose(mat_ZZ_pE& X, const mat_ZZ_pE& A); inline mat_ZZ_pE transpose(const mat_ZZ_pE& A) { mat_ZZ_pE X; transpose(X, A); NTL_OPT_RETURN(mat_ZZ_pE, X); } void solve(ZZ_pE& d, vec_ZZ_pE& X, const mat_ZZ_pE& A, const vec_ZZ_pE& b); void inv(ZZ_pE& d, mat_ZZ_pE& X, const mat_ZZ_pE& A); inline void sqr(mat_ZZ_pE& X, const mat_ZZ_pE& A) { mul(X, A, A); } inline mat_ZZ_pE sqr(const mat_ZZ_pE& A) { mat_ZZ_pE X; sqr(X, A); NTL_OPT_RETURN(mat_ZZ_pE, X); } void inv(mat_ZZ_pE& X, const mat_ZZ_pE& A); inline mat_ZZ_pE inv(const mat_ZZ_pE& A) { mat_ZZ_pE X; inv(X, A); NTL_OPT_RETURN(mat_ZZ_pE, X); } void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ& e); inline mat_ZZ_pE power(const mat_ZZ_pE& A, const ZZ& e) { mat_ZZ_pE X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ_pE, X); } inline void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_ZZ_pE power(const mat_ZZ_pE& A, long e) { mat_ZZ_pE X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ_pE, X); } void diag(mat_ZZ_pE& X, long n, const ZZ_pE& d); inline mat_ZZ_pE diag(long n, const ZZ_pE& d) { mat_ZZ_pE X; diag(X, n, d); NTL_OPT_RETURN(mat_ZZ_pE, X); } long IsDiag(const mat_ZZ_pE& A, long n, const ZZ_pE& d); long gauss(mat_ZZ_pE& M); long gauss(mat_ZZ_pE& M, long w); void image(mat_ZZ_pE& X, const mat_ZZ_pE& A); void kernel(mat_ZZ_pE& X, const mat_ZZ_pE& A); void clear(mat_ZZ_pE& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ_pE& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ_pE operator+(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator-(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator*(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator-(const mat_ZZ_pE& a); // matrix/scalar multiplication: inline mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_pE& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_p& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(const mat_ZZ_pE& a, long b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(const ZZ_pE& a, const mat_ZZ_pE& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(const ZZ_p& a, const mat_ZZ_pE& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(long a, const mat_ZZ_pE& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } // matrix/vector multiplication: vec_ZZ_pE operator*(const mat_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator*(const vec_ZZ_pE& a, const mat_ZZ_pE& b); // assignment operator notation: inline mat_ZZ_pE& operator+=(mat_ZZ_pE& x, const mat_ZZ_pE& a) { add(x, x, a); return x; } inline mat_ZZ_pE& operator-=(mat_ZZ_pE& x, const mat_ZZ_pE& a) { sub(x, x, a); return x; } inline mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const mat_ZZ_pE& a) { mul(x, x, a); return x; } inline mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_pE& a) { mul(x, x, a); return x; } inline mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_p& a) { mul(x, x, a); return x; } inline mat_ZZ_pE& operator*=(mat_ZZ_pE& x, long a) { mul(x, x, a); return x; } inline vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const mat_ZZ_pE& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_lzz_p.h000644 000765 000024 00000010030 12377144457 017056 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_zz_p__H #define NTL_mat_zz_p__H #include #include NTL_OPEN_NNS typedef Mat mat_zz_p; void add(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); void sub(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); void negate(mat_zz_p& X, const mat_zz_p& A); void mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); void mul(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b); void mul(vec_zz_p& x, const vec_zz_p& a, const mat_zz_p& B); void mul(mat_zz_p& X, const mat_zz_p& A, zz_p b); void mul(mat_zz_p& X, const mat_zz_p& A, long b); inline void mul(mat_zz_p& X, zz_p a, const mat_zz_p& B) { mul(X, B, a); } inline void mul(mat_zz_p& X, long a, const mat_zz_p& B) { mul(X, B, a); } void ident(mat_zz_p& X, long n); inline mat_zz_p ident_mat_zz_p(long n) { mat_zz_p X; ident(X, n); NTL_OPT_RETURN(mat_zz_p, X); } void determinant(zz_p& d, const mat_zz_p& A); long IsIdent(const mat_zz_p& A, long n); void transpose(mat_zz_p& X, const mat_zz_p& A); void solve(zz_p& d, vec_zz_p& X, const mat_zz_p& A, const vec_zz_p& b); void inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A); inline void sqr(mat_zz_p& X, const mat_zz_p& A) { mul(X, A, A); } inline mat_zz_p sqr(const mat_zz_p& A) { mat_zz_p X; sqr(X, A); NTL_OPT_RETURN(mat_zz_p, X); } void inv(mat_zz_p& X, const mat_zz_p& A); inline mat_zz_p inv(const mat_zz_p& A) { mat_zz_p X; inv(X, A); NTL_OPT_RETURN(mat_zz_p, X); } void power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e); inline mat_zz_p power(const mat_zz_p& A, const ZZ& e) { mat_zz_p X; power(X, A, e); NTL_OPT_RETURN(mat_zz_p, X); } inline void power(mat_zz_p& X, const mat_zz_p& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_zz_p power(const mat_zz_p& A, long e) { mat_zz_p X; power(X, A, e); NTL_OPT_RETURN(mat_zz_p, X); } void diag(mat_zz_p& X, long n, zz_p d); inline mat_zz_p diag(long n, zz_p d) { mat_zz_p X; diag(X, n, d); NTL_OPT_RETURN(mat_zz_p, X); } long IsDiag(const mat_zz_p& A, long n, zz_p d); long gauss(mat_zz_p& M); long gauss(mat_zz_p& M, long w); void image(mat_zz_p& X, const mat_zz_p& A); void kernel(mat_zz_p& X, const mat_zz_p& A); // miscellaneous: inline zz_p determinant(const mat_zz_p& a) { zz_p x; determinant(x, a); return x; } // functional variant of determinant inline mat_zz_p transpose(const mat_zz_p& a) { mat_zz_p x; transpose(x, a); NTL_OPT_RETURN(mat_zz_p, x); } void clear(mat_zz_p& a); // x = 0 (dimension unchanged) long IsZero(const mat_zz_p& a); // test if a is the zero matrix (any dimension) // operator notation: mat_zz_p operator+(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator-(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator*(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator-(const mat_zz_p& a); // matrix/scalar multiplication: inline mat_zz_p operator*(const mat_zz_p& a, zz_p b) { mat_zz_p x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_p, x); } inline mat_zz_p operator*(const mat_zz_p& a, long b) { mat_zz_p x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_p, x); } inline mat_zz_p operator*(zz_p a, const mat_zz_p& b) { mat_zz_p x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_p, x); } inline mat_zz_p operator*(long a, const mat_zz_p& b) { mat_zz_p x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_p, x); } // matrix/vector multiplication: vec_zz_p operator*(const mat_zz_p& a, const vec_zz_p& b); vec_zz_p operator*(const vec_zz_p& a, const mat_zz_p& b); // assignment operator notation: inline mat_zz_p& operator+=(mat_zz_p& x, const mat_zz_p& a) { add(x, x, a); return x; } inline mat_zz_p& operator-=(mat_zz_p& x, const mat_zz_p& a) { sub(x, x, a); return x; } inline mat_zz_p& operator*=(mat_zz_p& x, const mat_zz_p& a) { mul(x, x, a); return x; } inline mat_zz_p& operator*=(mat_zz_p& x, zz_p a) { mul(x, x, a); return x; } inline mat_zz_p& operator*=(mat_zz_p& x, long a) { mul(x, x, a); return x; } inline vec_zz_p& operator*=(vec_zz_p& x, const mat_zz_p& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_lzz_pE.h000644 000765 000024 00000011221 12377144457 017166 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_zz_pE__H #define NTL_mat_zz_pE__H #include NTL_OPEN_NNS typedef Mat mat_zz_pE; void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); void negate(mat_zz_pE& X, const mat_zz_pE& A); void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b); void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B); void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b); void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b); void mul(mat_zz_pE& X, const mat_zz_pE& A, long b); inline void mul(mat_zz_pE& X, const zz_pE& a, const mat_zz_pE& B) { mul(X, B, a); } inline void mul(mat_zz_pE& X, const zz_p& a, const mat_zz_pE& B) { mul(X, B, a); } inline void mul(mat_zz_pE& X, long a, const mat_zz_pE& B) { mul(X, B, a); } void ident(mat_zz_pE& X, long n); inline mat_zz_pE ident_mat_zz_pE(long n) { mat_zz_pE X; ident(X, n); NTL_OPT_RETURN(mat_zz_pE, X); } void determinant(zz_pE& d, const mat_zz_pE& A); inline zz_pE determinant(const mat_zz_pE& A) { zz_pE d; determinant(d, A); NTL_OPT_RETURN(zz_pE, d); } long IsIdent(const mat_zz_pE& A, long n); void transpose(mat_zz_pE& X, const mat_zz_pE& A); inline mat_zz_pE transpose(const mat_zz_pE& A) { mat_zz_pE X; transpose(X, A); NTL_OPT_RETURN(mat_zz_pE, X); } void solve(zz_pE& d, vec_zz_pE& X, const mat_zz_pE& A, const vec_zz_pE& b); void inv(zz_pE& d, mat_zz_pE& X, const mat_zz_pE& A); inline void sqr(mat_zz_pE& X, const mat_zz_pE& A) { mul(X, A, A); } inline mat_zz_pE sqr(const mat_zz_pE& A) { mat_zz_pE X; sqr(X, A); NTL_OPT_RETURN(mat_zz_pE, X); } void inv(mat_zz_pE& X, const mat_zz_pE& A); inline mat_zz_pE inv(const mat_zz_pE& A) { mat_zz_pE X; inv(X, A); NTL_OPT_RETURN(mat_zz_pE, X); } void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e); inline mat_zz_pE power(const mat_zz_pE& A, const ZZ& e) { mat_zz_pE X; power(X, A, e); NTL_OPT_RETURN(mat_zz_pE, X); } inline void power(mat_zz_pE& X, const mat_zz_pE& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_zz_pE power(const mat_zz_pE& A, long e) { mat_zz_pE X; power(X, A, e); NTL_OPT_RETURN(mat_zz_pE, X); } void diag(mat_zz_pE& X, long n, const zz_pE& d); inline mat_zz_pE diag(long n, const zz_pE& d) { mat_zz_pE X; diag(X, n, d); NTL_OPT_RETURN(mat_zz_pE, X); } long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d); long gauss(mat_zz_pE& M); long gauss(mat_zz_pE& M, long w); void image(mat_zz_pE& X, const mat_zz_pE& A); void kernel(mat_zz_pE& X, const mat_zz_pE& A); void clear(mat_zz_pE& a); // x = 0 (dimension unchanged) long IsZero(const mat_zz_pE& a); // test if a is the zero matrix (any dimension) // operator notation: mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator-(const mat_zz_pE& a); // matrix/scalar multiplication: inline mat_zz_pE operator*(const mat_zz_pE& a, const zz_pE& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(const mat_zz_pE& a, const zz_p& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(const mat_zz_pE& a, long b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(const zz_pE& a, const mat_zz_pE& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(const zz_p& a, const mat_zz_pE& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(long a, const mat_zz_pE& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } // matrix/vector multiplication: vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b); // assignment operator notation: inline mat_zz_pE& operator+=(mat_zz_pE& x, const mat_zz_pE& a) { add(x, x, a); return x; } inline mat_zz_pE& operator-=(mat_zz_pE& x, const mat_zz_pE& a) { sub(x, x, a); return x; } inline mat_zz_pE& operator*=(mat_zz_pE& x, const mat_zz_pE& a) { mul(x, x, a); return x; } inline mat_zz_pE& operator*=(mat_zz_pE& x, const zz_pE& a) { mul(x, x, a); return x; } inline mat_zz_pE& operator*=(mat_zz_pE& x, const zz_p& a) { mul(x, x, a); return x; } inline mat_zz_pE& operator*=(mat_zz_pE& x, long a) { mul(x, x, a); return x; } inline vec_zz_pE& operator*=(vec_zz_pE& x, const mat_zz_pE& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_poly_ZZ.h000644 000765 000024 00000000311 12377144457 017327 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_poly_ZZ__H #define NTL_mat_poly_ZZ__H #include #include NTL_OPEN_NNS void CharPoly(ZZX& f, const mat_ZZ& M, long deterministic=0); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_poly_ZZ_p.h000644 000765 000024 00000000300 12377144457 017644 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_poly_ZZ_p__H #define NTL_mat_poly_ZZ_p__H #include #include NTL_OPEN_NNS void CharPoly(ZZ_pX& f, const mat_ZZ_p& M); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/mat_poly_lzz_p.h000644 000765 000024 00000000302 12377144457 020122 0ustar00shoupstaff000000 000000 #ifndef NTL_mat_poly_zz_p__H #define NTL_mat_poly_zz_p__H #include #include NTL_OPEN_NNS void CharPoly(zz_pX& f, const mat_zz_p& M); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/matrix.h000644 000765 000024 00000010421 12377144457 016367 0ustar00shoupstaff000000 000000 #ifndef NTL_matrix__H #define NTL_matrix__H #include #include // matrix templates NTL_OPEN_NNS template class Mat { public: // pseudo-private fields Vec< Vec > _mat__rep; long _mat__numcols; // really public fields typedef typename Vec::value_type value_type; typedef typename Vec::reference reference; typedef typename Vec::const_reference const_reference; Mat() : _mat__numcols(0) { } Mat(const Mat& a); Mat& operator=(const Mat& a); ~Mat() { } Mat(INIT_SIZE_TYPE, long n, long m); void kill(); void SetDims(long n, long m); long NumRows() const { return _mat__rep.length(); } long NumCols() const { return _mat__numcols; } Vec& operator[](long i) { return _mat__rep[i]; } const Vec& operator[](long i) const { return _mat__rep[i]; } Vec& operator()(long i) { return _mat__rep[i-1]; } const Vec& operator()(long i) const { return _mat__rep[i-1]; } reference operator()(long i, long j) { return _mat__rep[i-1][j-1]; } const_reference operator()(long i, long j) const { return _mat__rep[i-1][j-1]; } const_reference get(long i, long j) const { return _mat__rep[i].get(j); } void put(long i, long j, const T& a) { _mat__rep[i].put(j, a); } template void put(long i, long j, const U& a) { _mat__rep[i].put(j, a); } long position(const Vec& a) const { return _mat__rep.position(a); } long position1(const Vec& a) const { return _mat__rep.position1(a); } Mat(Mat& x, INIT_TRANS_TYPE) : _mat__rep(x._mat__rep, INIT_TRANS), _mat__numcols(x._mat__numcols) { } }; template inline const Vec< Vec >& rep(const Mat& a) { return a._mat__rep; } template Mat::Mat(const Mat& a) : _mat__numcols(0) { SetDims(a.NumRows(), a.NumCols()); _mat__rep = a._mat__rep; } template Mat& Mat::operator=(const Mat& a) { SetDims(a.NumRows(), a.NumCols()); _mat__rep = a._mat__rep; return *this; } template Mat::Mat(INIT_SIZE_TYPE, long n, long m) : _mat__numcols(0) { SetDims(n, m); } template void Mat::kill() { _mat__numcols = 0; _mat__rep.kill(); } template void Mat::SetDims(long n, long m) { if (n < 0 || m < 0) Error("SetDims: bad args"); if (m != _mat__numcols) { _mat__rep.kill(); _mat__numcols = m; } long oldmax = _mat__rep.MaxLength(); long i; _mat__rep.SetLength(n); for (i = oldmax; i < n; i++) _mat__rep[i].FixLength(m); } template void MakeMatrix(Mat& x, const Vec< Vec >& a) { long n = a.length(); if (n == 0) { x.SetDims(0, 0); return; } long m = a[0].length(); long i; for (i = 1; i < n; i++) if (a[i].length() != m) Error("nonrectangular matrix"); x.SetDims(n, m); for (i = 0; i < n; i++) x[i] = a[i]; } template void swap(Mat& X, Mat& Y) { swap(X._mat__numcols, Y._mat__numcols); swap(X._mat__rep, Y._mat__rep); } template long operator==(const Mat& a, const Mat& b) { if (a.NumCols() != b.NumCols()) return 0; if (a.NumRows() != b.NumRows()) return 0; long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (a[i] != b[i]) return 0; return 1; } template long operator!=(const Mat& a, const Mat& b) { return !(a == b); } template NTL_SNS istream& operator>>(NTL_SNS istream& s, Mat& x) { Vec< Vec > buf; s >> buf; MakeMatrix(x, buf); return s; } template NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const Mat& a) { long n = a.NumRows(); long i; s << "["; for (i = 0; i < n; i++) { s << a[i]; s << "\n"; } s << "]"; return s; } // conversion template void conv(Mat& x, const Mat& a) { x.SetDims(a.NumRows(), a.NumCols()); conv(x._mat__rep, a._mat__rep); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/new.h000644 000765 000024 00000000602 12377144460 015646 0ustar00shoupstaff000000 000000 #ifndef NTL_new__H #define NTL_new__H #include #if (defined(NTL_STD_CXX) || defined(NTL_PSTD_NTN)) // We use and std::nothrow, even if neither NTL_STD_CXX nor // NTL_PSTD_NHF are set. This appears to be somewhat more compatible // with current compilers. #include #define NTL_NEW_OP new (std::nothrow) #else #define NTL_NEW_OP new #endif #endif ntl-6.2.1/include/NTL/pair.h000644 000765 000024 00000003040 12377144457 016015 0ustar00shoupstaff000000 000000 #ifndef NTL_pair__H #define NTL_pair__H #include // pair templates NTL_OPEN_NNS template class Pair { public: S a; T b; Pair() { } Pair(const Pair& x) : a(x.a), b(x.b) { } Pair(const S& x, const T& y) : a(x), b(y) { } Pair& operator=(const Pair& x) { a = x.a; b = x.b; return *this; } ~Pair() { } }; template inline Pair cons(const S& x, const T& y) { return Pair(x, y); } template inline long operator==(const Pair& x, const Pair& y) { return x.a == y.a && x.b == y.b; } template inline long operator!=(const Pair& x, const Pair& y) { return !(x == y); } template NTL_SNS istream& operator>>(NTL_SNS istream& s, Pair& x) { long c; if (!s) Error("bad pair input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != '[') Error("bad pair input"); s.get(); if (!(s >> x.a)) Error("bad pair input"); if (!(s >> x.b)) Error("bad pair input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != ']') Error("bad pair input"); s.get(); return s; } template NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const Pair& x) { return s << "[" << x.a << " " << x.b << "]"; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/pair_GF2EX_long.h000644 000765 000024 00000000411 12377144457 017726 0ustar00shoupstaff000000 000000 #ifndef NTL_pair_GF2EX_long__H #define NTL_pair_GF2EX_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_GF2EX_long; typedef Vec vec_pair_GF2EX_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/pair_GF2X_long.h000644 000765 000024 00000000400 12377144457 017617 0ustar00shoupstaff000000 000000 #ifndef NTL_pair_GF2X_long__H #define NTL_pair_GF2X_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_GF2X_long; typedef Vec vec_pair_GF2X_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/pair_ZZX_long.h000644 000765 000024 00000000371 12377144457 017613 0ustar00shoupstaff000000 000000 #ifndef NTL_pair_ZZX_long__H #define NTL_pair_ZZX_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_ZZX_long; typedef Vec vec_pair_ZZX_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/pair_ZZ_pEX_long.h000644 000765 000024 00000000367 12377144457 020244 0ustar00shoupstaff000000 000000 #ifndef NTL_pair_ZZ_pEX_long__H #define NTL_pair_ZZ_pEX_long__H #include #include NTL_OPEN_NNS typedef Pair pair_ZZ_pEX_long; typedef Vec vec_pair_ZZ_pEX_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/pair_ZZ_pX_long.h000644 000765 000024 00000000407 12377144457 020132 0ustar00shoupstaff000000 000000 #ifndef NTL_pair_ZZ_pX_long__H #define NTL_pair_ZZ_pX_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_ZZ_pX_long; typedef Vec vec_pair_ZZ_pX_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/pair_lzz_pEX_long.h000644 000765 000024 00000000370 12377144457 020512 0ustar00shoupstaff000000 000000 #ifndef NTL_pair_zz_pEX_long__H #define NTL_pair_zz_pEX_long__H #include #include NTL_OPEN_NNS typedef Pair pair_zz_pEX_long; typedef Vec vec_pair_zz_pEX_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/pair_lzz_pX_long.h000644 000765 000024 00000000410 12377144457 020400 0ustar00shoupstaff000000 000000 #ifndef NTL_pair_zz_pX_long__H #define NTL_pair_zz_pX_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_zz_pX_long; typedef Vec vec_pair_zz_pX_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/quad_float.h000644 000765 000024 00000023672 12377144457 017216 0ustar00shoupstaff000000 000000 #ifndef NTL_quad_float__H #define NTL_quad_float__H /* Copyright (C) 1997, 1998, 1999, 2000 Victor Shoup This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ***************************************************** The quad_float package is derived from the doubledouble package of Keith Briggs. However, the version employed in NTL has been extensively modified. Below, I attach the copyright notice from the original doubledouble package, which is currently available at http://www.labs.bt.com/people/briggsk2 ***************************************************** Copyright (C) 1997 Keith Martin Briggs Except where otherwise indicated, this program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include NTL_OPEN_NNS class quad_float { public: double hi, lo; // Constructors quad_float() : hi(0), lo(0) {} explicit quad_float(double a) : hi(0), lo(0) { *this = a; } inline quad_float& operator=(double x); NTL_THREAD_LOCAL static long oprec; static void SetOutputPrecision(long p); static long OutputPrecision() { return oprec; } quad_float(double x, double y) : hi(x), lo(y) { } // internal use only // FIXME: add a special argument to this to make it more "internal" ~quad_float() {} }; // end class quad_float #if (NTL_BITS_PER_LONG < NTL_DOUBLE_PRECISION) // FIXME: we could make this <=, and even BPL <= DP+1 for // conversions from signed long...but this is mainly academic inline quad_float to_quad_float(long n) { return quad_float(n, 0); } inline quad_float to_quad_float(unsigned long n) { return quad_float(n, 0); } #else quad_float to_quad_float(long n); quad_float to_quad_float(unsigned long n); #endif #if (NTL_BITS_PER_INT < NTL_DOUBLE_PRECISION) inline quad_float to_quad_float(int n) { return quad_float(n, 0); } inline quad_float to_quad_float(unsigned int n) { return quad_float(n, 0); } #else inline quad_float to_quad_float(int n) { return to_quad_float(long(n)); } inline quad_float to_quad_float(unsigned int n) { return to_quad_float((unsigned long) n); } #endif inline quad_float to_quad_float(double x) { return quad_float(x, 0); } // On platforms with extended doubles, this may result in an // improper quad_float object, but it should be converted to a proper // one when passed by reference to any of the arithmetic routines, // at which time x will be forced to memory. inline quad_float to_quad_float(float x) { return to_quad_float(double(x)); } inline quad_float& quad_float::operator=(double x) { *this = to_quad_float(x); return *this; } quad_float operator+(const quad_float&, const quad_float& ); inline quad_float operator+(const quad_float& x, double y ) { return x + to_quad_float(y); } inline quad_float operator+(double x, const quad_float& y) { return to_quad_float(x) + y; } quad_float operator-(const quad_float&, const quad_float& ); inline quad_float operator-(const quad_float& x, double y ) { return x - to_quad_float(y); } inline quad_float operator-(double x, const quad_float& y) { return to_quad_float(x) - y; } quad_float operator*(const quad_float&, const quad_float& ); inline quad_float operator*(const quad_float& x, double y ) { return x * to_quad_float(y); } inline quad_float operator*(double x, const quad_float& y) { return to_quad_float(x) * y; } quad_float operator/(const quad_float&, const quad_float& ); inline quad_float operator/(const quad_float& x, double y ) { return x / to_quad_float(y); } inline quad_float operator/(double x, const quad_float& y) { return to_quad_float(x) / y; } quad_float operator-(const quad_float& x); quad_float& operator+= (quad_float& x, const quad_float& y); inline quad_float& operator += (quad_float& x, double y) { x += to_quad_float(y); return x; } quad_float& operator-= (quad_float& x, const quad_float& y); inline quad_float& operator-= (quad_float& x, double y) { x -= to_quad_float(y); return x; } quad_float& operator*= (quad_float& x, const quad_float& y); inline quad_float& operator*= (quad_float& x, double y) { x *= to_quad_float(y); return x; } quad_float& operator/= (quad_float& x, const quad_float& y); inline quad_float& operator/= (quad_float& x, double y) { x /= to_quad_float(y); return x; } inline quad_float& operator++(quad_float& a) { a += 1.0; return a; } inline void operator++(quad_float& a, int) { a += 1.0; } inline quad_float& operator--(quad_float& a) { a -= 1.0; return a; } inline void operator--(quad_float& a, int) { a -= 1.0; } long operator> (const quad_float& x, const quad_float& y); long operator>=(const quad_float& x, const quad_float& y); long operator< (const quad_float& x, const quad_float& y); long operator<=(const quad_float& x, const quad_float& y); long operator==(const quad_float& x, const quad_float& y); long operator!=(const quad_float& x, const quad_float& y); inline long operator> (const quad_float& x, double y) { return x > to_quad_float(y); } inline long operator> (double x, const quad_float& y) { return to_quad_float(x) > y; } inline long operator>=(const quad_float& x, double y) { return x >= to_quad_float(y); } inline long operator>=(double x, const quad_float& y) { return to_quad_float(x) >= y; } inline long operator< (const quad_float& x, double y) { return x < to_quad_float(y); } inline long operator< (double x, const quad_float& y) { return to_quad_float(x) < y; } inline long operator<=(const quad_float& x, double y) { return x <= to_quad_float(y); } inline long operator<=(double x, const quad_float& y) { return to_quad_float(x) <= y; } inline long operator!=(const quad_float& x, double y) { return x != to_quad_float(y); } inline long operator!=(double x, const quad_float& y) { return to_quad_float(x) != y; } inline long operator==(const quad_float& x, double y) { return x == to_quad_float(y); } inline long operator==(double x, const quad_float& y) { return to_quad_float(x) == y; } inline long sign(const quad_float& x){ if (x.hi>0.0) return 1; else if (x.hi<0.0) return -1; else return 0; } long compare(const quad_float&, const quad_float&); inline long compare(const quad_float& x, double y) { return compare(x, to_quad_float(y)); } inline long compare(double x, const quad_float& y) { return compare(to_quad_float(x), y); } NTL_SNS istream& operator >> (NTL_SNS istream&, quad_float&); NTL_SNS ostream& operator << (NTL_SNS ostream&, const quad_float&); quad_float sqrt(const quad_float&); quad_float floor(const quad_float&); quad_float ceil(const quad_float&); quad_float trunc(const quad_float&); quad_float fabs(const quad_float&); void power(quad_float&, const quad_float&, long); inline quad_float power(const quad_float& x, long e) { quad_float z; power(z, x, e); return z; } void power2(quad_float&, long); inline quad_float power2_quad_float(long e) { quad_float z; power2(z, e); return z; } long to_long(const quad_float&); inline int to_int(const quad_float& x) { return to_int(to_long(x)); } inline double to_double(const quad_float& x) { return x.hi; } inline float to_float(const quad_float& x) { return float(x.hi); } inline void conv(quad_float& x, int a) { x = to_quad_float(a); } inline void conv(quad_float& x, long a) { x = to_quad_float(a); } inline void conv(quad_float& x, unsigned int a) { x = to_quad_float(a); } inline void conv(quad_float& x, unsigned long a) { x = to_quad_float(a); } inline void conv(quad_float& x, float a) { x = to_quad_float(a); } inline void conv(quad_float& x, double a) { x = to_quad_float(a); } inline void conv(long& x, const quad_float& a) { x = to_long(a); } inline void conv(int& x, const quad_float& a) { x = to_int(a); } inline void conv(double& x, const quad_float& a) { x = to_double(a); } inline void conv(float& x, const quad_float& a) { x = to_float(a); } void conv(quad_float&, const ZZ&); inline quad_float to_quad_float(const ZZ& x) { quad_float z; conv(z, x); return z; } void conv(ZZ&, const quad_float&); inline ZZ to_ZZ(const quad_float& a) { ZZ x; conv(x, a); NTL_OPT_RETURN(ZZ, x); } inline void conv(quad_float& x, const quad_float& a) { x = a; } inline quad_float to_quad_float(const quad_float& a) { return a; } quad_float to_quad_float(const char *s); inline void conv(quad_float& x, const char *s) { x = to_quad_float(s); } /* additional legacy conversions for v6 conversion regime */ inline void conv(unsigned int& x, const quad_float& a) { long z; conv(z, a); conv(x, z); } inline void conv(unsigned long& x, const quad_float& a) { long z; conv(z, a); conv(x, z); } /* ------------------------------------- */ long IsFinite(quad_float *x); long PrecisionOK(); quad_float ldexp(const quad_float& x, long exp); quad_float exp(const quad_float& x); quad_float log(const quad_float& x); void random(quad_float& x); quad_float random_quad_float(); NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/tools.h000644 000765 000024 00000022044 12377144457 016227 0ustar00shoupstaff000000 000000 #ifndef NTL_tools__H #define NTL_tools__H #include #if (defined(NTL_STD_CXX) || defined(NTL_PSTD_NHF)) // new header files #include #include #include #else // old header files #include #include #include #endif #if (defined(NTL_STD_CXX) || defined(NTL_PSTD_NHF)) #define NTL_SNS std :: #define NTL_USE_SNS using namespace std; #elif (defined(NTL_PSTD_NNS)) #define NTL_SNS :: #define NTL_USE_SNS #else #define NTL_SNS #define NTL_USE_SNS #endif #if (defined(NTL_STD_CXX) || defined(NTL_PSTD_NNS)) #define NTL_NAMESPACE NTL #define NTL_OPEN_NNS namespace NTL_NAMESPACE { #define NTL_CLOSE_NNS } #define NTL_USE_NNS using namespace NTL_NAMESPACE; #define NTL_NNS NTL_NAMESPACE :: // To make things work, we have to apply using declarations of all std // functions that are both overloaded by NTL and are used in // the implementation of NTL. #define NTL_START_IMPL NTL_USE_SNS NTL_OPEN_NNS \ using NTL_SNS abs; \ using NTL_SNS ceil; \ using NTL_SNS exp; \ using NTL_SNS fabs; \ using NTL_SNS floor; \ using NTL_SNS ldexp; \ using NTL_SNS log; \ using NTL_SNS sqrt; #define NTL_END_IMPL NTL_CLOSE_NNS #else #define NTL_NAMESPACE #define NTL_OPEN_NNS #define NTL_CLOSE_NNS #define NTL_USE_NNS #define NTL_NNS #define NTL_START_IMPL #define NTL_END_IMPL #endif #define NTL_CLIENT NTL_USE_SNS NTL_USE_NNS #if 0 // This is for debugging purposes only. namespace foo_bar { class ostream; class istream; typedef unsigned int size_t; double floor(double); float floor(float); } #endif double _ntl_GetTime(); typedef unsigned long _ntl_ulong; typedef _ntl_ulong *_ntl_ulong_ptr; // I made these have "obscure" names to avoid conflict with // (non-standard but common) definitions in standard headers. // Putting u_long inside namespace NTL only tends to creates ambiguities, // for no good reason. NTL_OPEN_NNS #define NTL_FILE_THRESH (64000.0) // threshold in KB for switching to external storage of certain // tables (currently in the DDF polynomial factoring routines) NTL_THREAD_LOCAL extern void (*ErrorCallback)(); struct INIT_SIZE_STRUCT { }; const INIT_SIZE_STRUCT INIT_SIZE = INIT_SIZE_STRUCT(); typedef const INIT_SIZE_STRUCT& INIT_SIZE_TYPE; struct INIT_VAL_STRUCT { }; const INIT_VAL_STRUCT INIT_VAL = INIT_VAL_STRUCT(); typedef const INIT_VAL_STRUCT& INIT_VAL_TYPE; struct INIT_TRANS_STRUCT { }; const INIT_TRANS_STRUCT INIT_TRANS = INIT_TRANS_STRUCT(); typedef const INIT_TRANS_STRUCT& INIT_TRANS_TYPE; struct INIT_LOOP_HOLE_STRUCT { }; const INIT_LOOP_HOLE_STRUCT INIT_LOOP_HOLE = INIT_LOOP_HOLE_STRUCT(); typedef const INIT_LOOP_HOLE_STRUCT& INIT_LOOP_HOLE_TYPE; struct INIT_FFT_STRUCT { }; const INIT_FFT_STRUCT INIT_FFT = INIT_FFT_STRUCT(); typedef const INIT_FFT_STRUCT& INIT_FFT_TYPE; struct INIT_USER_FFT_STRUCT { }; const INIT_USER_FFT_STRUCT INIT_USER_FFT = INIT_USER_FFT_STRUCT(); typedef const INIT_USER_FFT_STRUCT& INIT_USER_FFT_TYPE; struct INIT_NO_ALLOC_STRUCT { }; const INIT_NO_ALLOC_STRUCT INIT_NO_ALLOC = INIT_NO_ALLOC_STRUCT(); typedef const INIT_NO_ALLOC_STRUCT& INIT_NO_ALLOC_TYPE; struct INIT_ALLOC_STRUCT { }; const INIT_ALLOC_STRUCT INIT_ALLOC = INIT_ALLOC_STRUCT(); typedef const INIT_ALLOC_STRUCT& INIT_ALLOC_TYPE; struct INIT_MONO_STRUCT { }; const INIT_MONO_STRUCT INIT_MONO = INIT_MONO_STRUCT(); typedef const INIT_MONO_STRUCT& INIT_MONO_TYPE; #ifdef NTL_NO_INIT_TRANS #define NTL_OPT_RETURN(t, x) return x #else #define NTL_OPT_RETURN(t, x) return t(x, INIT_TRANS) #endif #ifndef NTL_NO_MIN_MAX inline int min(int a, int b) { return (a < b) ? a : b; } inline int max(int a, int b) { return (a < b) ? b : a; } inline long min(long a, long b) { return (a < b) ? a : b; } inline long max(long a, long b) { return (a < b) ? b : a; } inline long min(int a, long b) { return (a < b) ? long(a) : b; } inline long max(int a, long b) { return (a < b) ? b : long(a); } inline long min(long a, int b) { return (a < b) ? a : long(b); } inline long max(long a, int b) { return (a < b) ? long(b) : a; } #endif inline void swap(long& a, long& b) { long t; t = a; a = b; b = t; } inline void swap(int& a, int& b) { int t; t = a; a = b; b = t; } inline void conv(int& x, int a) { x = a; } inline void conv(int& x, long a) { unsigned y = (unsigned) a; x = NTL_UINT_TO_INT(y); } inline void conv(int& x, float a) { x = int(NTL_SNS floor(double(a))); } inline void conv(int& x, double a) { x = int(NTL_SNS floor(a)); } inline void conv(int& x, unsigned a) { x = NTL_UINT_TO_INT(a); } inline void conv(int& x, unsigned long a) { unsigned y = (unsigned) a; x = NTL_UINT_TO_INT(y); } inline int to_int(int a) { return a; } inline int to_int(long a) { unsigned y = (unsigned) a; return NTL_UINT_TO_INT(y); } inline int to_int(float a) { return int(NTL_SNS floor(double(a))); } inline int to_int(double a) { return int(NTL_SNS floor(a)); } inline int to_int(unsigned a) { return NTL_UINT_TO_INT(a); } inline int to_int(unsigned long a) { unsigned y = (unsigned) a; return NTL_UINT_TO_INT(y); } inline void conv(long& x, int a) { x = a; } inline void conv(long& x, long a) { x = a; } inline void conv(long& x, float a) { x = long(NTL_SNS floor(double(a))); } inline void conv(long& x, double a) { x = long(NTL_SNS floor(a)); } inline void conv(long& x, unsigned a) { unsigned long y = a; x = NTL_ULONG_TO_LONG(y); } inline void conv(long& x, unsigned long a) { x = NTL_ULONG_TO_LONG(a); } inline long to_long(int a) { return a; } inline long to_long(long a) { return a; } inline long to_long(float a) { return long(NTL_SNS floor(double(a))); } inline long to_long(double a) { return long(NTL_SNS floor(a)); } inline long to_long(unsigned a) { unsigned long y = a; return NTL_ULONG_TO_LONG(y); } inline long to_long(unsigned long a) { return NTL_ULONG_TO_LONG(a); } inline void conv(float& x, int a) { x = float(a); } inline void conv(float& x, long a) { x = float(a); } inline void conv(float& x, unsigned a) { x = float(a); } inline void conv(float& x, unsigned long a) { x = float(a); } inline void conv(float& x, float a) { x = a; } inline void conv(float& x, double a) { x = float(a); } inline float to_float(int a) { return float(a); } inline float to_float(long a) { return float(a); } inline float to_float(unsigned a) { return float(a); } inline float to_float(unsigned long a) { return float(a); } inline float to_float(float a) { return a; } inline float to_float(double a) { return float(a); } inline void conv(double& x, int a) { x = double(a); } inline void conv(double& x, long a) { x = double(a); } inline void conv(double& x, unsigned a) { x = double(a); } inline void conv(double& x, unsigned long a) { x = double(a); } inline void conv(double& x, float a) { x = double(a); } inline void conv(double& x, double a) { x = a; } inline double to_double(int a) { return double(a); } inline double to_double(long a) { return double(a); } inline double to_double(unsigned a) { return double(a); } inline double to_double(unsigned long a) { return double(a); } inline double to_double(float a) { return double(a); } inline double to_double(double a) { return a; } /* additional legacy conversions for v6 conversion regime */ inline void conv(unsigned int& x, int a) { x = ((unsigned int)(a)); } inline void conv(unsigned int& x, long a) { x = ((unsigned int)(a)); } inline void conv(unsigned int& x, unsigned a) { x = a; } inline void conv(unsigned int& x, unsigned long a) { x = ((unsigned int)(a)); } inline void conv(unsigned int& x, float a) { x = ((unsigned int) to_long(a)); } inline void conv(unsigned int& x, double a) { x = ((unsigned int) to_long(a)); } inline void conv(unsigned long& x, int a) { x = ((unsigned long)(a)); } inline void conv(unsigned long& x, long a) { x = ((unsigned long)(a)); } inline void conv(unsigned long& x, unsigned a) { x = ((unsigned long)(a)); } inline void conv(unsigned long& x, unsigned long a) { x = a; } inline void conv(unsigned long& x, float a) { x = ((unsigned int) to_long(a)); } inline void conv(unsigned long& x, double a) { x = ((unsigned int) to_long(a)); } /* ------------------------------------- */ // new style converson function // example: ZZ x = conv(1); // note: modern C++ compilers should implemented // "named return value optimization", so the // result statement should not create a temporary template T conv(const S& a) { T x; conv(x, a); return x; } long SkipWhiteSpace(NTL_SNS istream& s); long IsWhiteSpace(long c); long IsEOFChar(long c); long CharToIntVal(long c); char IntValToChar(long a); void Error(const char *s); inline double GetTime() { return _ntl_GetTime(); } inline long IsFinite(double *p) { return _ntl_IsFinite(p); } #if (NTL_EXT_DOUBLE) inline void ForceToMem(double *p) { _ntl_ForceToMem(p); } #else inline void ForceToMem(double *p) { } #endif void PrintTime(NTL_SNS ostream& s, double t); #if (defined(__GNUC__) && (__GNUC__ >= 4)) // on relative modern versions of gcc, we can // decalare "restricted" pointers in C++ #define NTL_RESTRICT __restrict #else #define NTL_RESTRICT #endif NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_GF2.h000644 000765 000024 00000012125 12377144457 016301 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_GF2__H #define NTL_vec_GF2__H #include #include NTL_OPEN_NNS // Vec is an explicit specialization of Vec. // Vec is declared, but not defined, in GF2.h, // to prevent the generic Vec from being used. template<> class Vec { public: // these should be private, but they are not WordVector rep; long _len; // length (in bits) long _maxlen; // (MaxLength << 1) | (fixed) // invariants: rep.length() "tracks" length() ( = _len) // All bits in positions >= length are zero. // Note: rep.MaxLength() may exceed the value // indicated by MaxLength(). //the following are "really" public Vec() : _len(0), _maxlen(0) {} Vec(INIT_SIZE_TYPE, long n) : _len(0), _maxlen(0) { SetLength(n); } Vec(const Vec& a) : _len(0), _maxlen(0) { *this = a; } Vec& operator=(const Vec& a); ~Vec() {} void kill(); void SetLength(long n); void SetLength(long n, GF2 a); void SetMaxLength(long n); void FixLength(long n); long length() const { return _len; } long MaxLength() const { return _maxlen >> 1; } long allocated() const { return rep.MaxLength() * NTL_BITS_PER_LONG; } long fixed() const { return _maxlen & 1; } Vec(Vec& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS), _len(x._len), _maxlen(x._maxlen) { } const GF2 get(long i) const; void put(long i, GF2 a); void put(long i, long a) { put(i, to_GF2(a)); } ref_GF2 operator[](long i); ref_GF2 operator()(long i) { return (*this)[i-1]; } const GF2 operator[](long i) const { return get(i); } const GF2 operator()(long i) const { return get(i-1); } void swap(Vec& y); void append(GF2 a); void append(const Vec& w); // Some partial STL compatibility...also used // to interface with the Matrix template class typedef GF2 value_type; typedef ref_GF2 reference; typedef const GF2 const_reference; }; typedef Vec vec_GF2; // sepcialized conversion inline void conv(vec_GF2& x, const vec_GF2& a) { x = a; } inline void swap(vec_GF2& x, vec_GF2& y) { x.swap(y); } inline void append(vec_GF2& v, const GF2 a) { v.append(a); } inline void append(vec_GF2& v, const vec_GF2& a) { v.append(a); } long operator==(const vec_GF2& a, const vec_GF2& b); inline long operator!=(const vec_GF2& a, const vec_GF2& b) { return !(a == b); } NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const vec_GF2& a); NTL_SNS istream& operator>>(NTL_SNS istream& s, vec_GF2& a); void shift(vec_GF2& x, const vec_GF2& a, long n); // x = a shifted n places, i.e., if l = a.length(), // x.length() = l, x[i] = a[i-n] for 0 <= i-n < l, // and x[i] = 0 for all other i such that 0 <= i < l. inline vec_GF2 shift(const vec_GF2& a, long n) { vec_GF2 x; shift(x, a, n); NTL_OPT_RETURN(vec_GF2, x); } void reverse(vec_GF2& x, const vec_GF2& a); inline vec_GF2 reverse(const vec_GF2& a) { vec_GF2 x; reverse(x, a); NTL_OPT_RETURN(vec_GF2, x); } void random(vec_GF2& x, long n); inline vec_GF2 random_vec_GF2(long n) { vec_GF2 x; random(x, n); NTL_OPT_RETURN(vec_GF2, x); } long weight(const vec_GF2& a); void mul(vec_GF2& x, const vec_GF2& a, GF2 b); inline void mul(vec_GF2& x, GF2 a, const vec_GF2& b) { mul(x, b, a); } inline void mul(vec_GF2& x, const vec_GF2& a, long b) { mul(x, a, to_GF2(b)); } inline void mul(vec_GF2& x, long a, const vec_GF2& b) { mul(x, b, a); } void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b); inline void sub(vec_GF2& x, const vec_GF2& a, const vec_GF2& b) { add(x, a, b); } void clear(vec_GF2& x); inline void negate(vec_GF2& x, const vec_GF2& a) { x = a; } inline void InnerProduct(ref_GF2 x, const vec_GF2& a, const vec_GF2& b) { x = to_GF2(InnerProduct(a.rep, b.rep)); } long IsZero(const vec_GF2& a); vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b); vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b); inline vec_GF2 operator-(const vec_GF2& a) { return a; } inline vec_GF2 operator*(const vec_GF2& a, GF2 b) { vec_GF2 x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2, x); } inline vec_GF2 operator*(const vec_GF2& a, long b) { vec_GF2 x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2, x); } inline vec_GF2 operator*(GF2 a, const vec_GF2& b) { vec_GF2 x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2, x); } inline vec_GF2 operator*(long a, const vec_GF2& b) { vec_GF2 x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2, x); } inline GF2 operator*(const vec_GF2& a, const vec_GF2& b) { return to_GF2(InnerProduct(a.rep, b.rep)); } // assignment operator notation: inline vec_GF2& operator+=(vec_GF2& x, const vec_GF2& a) { add(x, x, a); return x; } inline vec_GF2& operator-=(vec_GF2& x, const vec_GF2& a) { sub(x, x, a); return x; } inline vec_GF2& operator*=(vec_GF2& x, GF2 a) { mul(x, x, a); return x; } inline vec_GF2& operator*=(vec_GF2& x, long a) { mul(x, x, a); return x; } void VectorCopy(vec_GF2& x, const vec_GF2& a, long n); inline vec_GF2 VectorCopy(const vec_GF2& a, long n) { vec_GF2 x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_GF2, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_GF2E.h000644 000765 000024 00000005051 12377144457 016406 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_GF2E__H #define NTL_vec_GF2E__H #include NTL_OPEN_NNS typedef Vec vec_GF2E; void mul(vec_GF2E& x, const vec_GF2E& a, const GF2E& b); inline void mul(vec_GF2E& x, const GF2E& a, const vec_GF2E& b) { mul(x, b, a); } void mul(vec_GF2E& x, const vec_GF2E& a, GF2 b); inline void mul(vec_GF2E& x, GF2 a, const vec_GF2E& b) { mul(x, b, a); } inline void mul(vec_GF2E& x, const vec_GF2E& a, long b) { mul(x, a, to_GF2(b)); } inline void mul(vec_GF2E& x, long a, const vec_GF2E& b) { mul(x, b, a); } void add(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b); inline void sub(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b) { add(x, a, b); } inline void negate(vec_GF2E& x, const vec_GF2E& a) { x = a; } void clear(vec_GF2E& x); void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b); void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b, long offset); long IsZero(const vec_GF2E& a); vec_GF2E operator+(const vec_GF2E& a, const vec_GF2E& b); vec_GF2E operator-(const vec_GF2E& a, const vec_GF2E& b); vec_GF2E operator-(const vec_GF2E& a); GF2E operator*(const vec_GF2E& a, const vec_GF2E& b); inline vec_GF2E operator*(const vec_GF2E& a, const GF2E& b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(const vec_GF2E& a, GF2 b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(const vec_GF2E& a, long b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(const GF2E& a, const vec_GF2E& b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(GF2 a, const vec_GF2E& b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(long a, const vec_GF2E& b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } // assignment operator notation: inline vec_GF2E& operator+=(vec_GF2E& x, const vec_GF2E& a) { add(x, x, a); return x; } inline vec_GF2E& operator-=(vec_GF2E& x, const vec_GF2E& a) { sub(x, x, a); return x; } inline vec_GF2E& operator*=(vec_GF2E& x, const GF2E& a) { mul(x, x, a); return x; } inline vec_GF2E& operator*=(vec_GF2E& x, GF2 a) { mul(x, x, a); return x; } inline vec_GF2E& operator*=(vec_GF2E& x, long a) { mul(x, x, a); return x; } void VectorCopy(vec_GF2E& x, const vec_GF2E& a, long n); inline vec_GF2E VectorCopy(const vec_GF2E& a, long n) { vec_GF2E x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_GF2E, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_GF2XVec.h000644 000765 000024 00000000261 12377144457 017065 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_GF2XVec__H #define NTL_vec_GF2XVec__H #include #include NTL_OPEN_NNS typedef Vec vec_GF2XVec; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_RR.h000644 000765 000024 00000003516 12377144457 016252 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_RR__H #define NTL_vec_RR__H #include #include NTL_OPEN_NNS typedef Vec vec_RR; void mul(vec_RR& x, const vec_RR& a, const RR& b); inline void mul(vec_RR& x, const RR& a, const vec_RR& b) { mul(x, b, a); } void mul(vec_RR& x, const vec_RR& a, double b); inline void mul(vec_RR& x, double a, const vec_RR& b) { mul(x, b, a); } void add(vec_RR& x, const vec_RR& a, const vec_RR& b); void sub(vec_RR& x, const vec_RR& a, const vec_RR& b); void clear(vec_RR& x); void negate(vec_RR& x, const vec_RR& a); void InnerProduct(RR& x, const vec_RR& a, const vec_RR& b); long IsZero(const vec_RR& a); void VectorCopy(vec_RR& x, const vec_RR& a, long n); inline vec_RR VectorCopy(const vec_RR& a, long n) { vec_RR x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_RR, x); } vec_RR operator+(const vec_RR& a, const vec_RR& b); vec_RR operator-(const vec_RR& a, const vec_RR& b); vec_RR operator-(const vec_RR& a); inline vec_RR operator*(const vec_RR& a, const RR& b) { vec_RR x; mul(x, a, b); NTL_OPT_RETURN(vec_RR, x); } inline vec_RR operator*(const vec_RR& a, double b) { vec_RR x; mul(x, a, b); NTL_OPT_RETURN(vec_RR, x); } inline vec_RR operator*(const RR& a, const vec_RR& b) { vec_RR x; mul(x, a, b); NTL_OPT_RETURN(vec_RR, x); } inline vec_RR operator*(double a, const vec_RR& b) { vec_RR x; mul(x, a, b); NTL_OPT_RETURN(vec_RR, x); } RR operator*(const vec_RR& a, const vec_RR& b); // assignment operator notation: inline vec_RR& operator+=(vec_RR& x, const vec_RR& a) { add(x, x, a); return x; } inline vec_RR& operator-=(vec_RR& x, const vec_RR& a) { sub(x, x, a); return x; } inline vec_RR& operator*=(vec_RR& x, const RR& a) { mul(x, x, a); return x; } inline vec_RR& operator*=(vec_RR& x, double a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_ZZ.h000644 000765 000024 00000003505 12377144457 016270 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_ZZ__H #define NTL_vec_ZZ__H #include #include NTL_OPEN_NNS typedef Vec vec_ZZ; void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b); inline void mul(vec_ZZ& x, const ZZ& a, const vec_ZZ& b) { mul(x, b, a); } void mul(vec_ZZ& x, const vec_ZZ& a, long b); inline void mul(vec_ZZ& x, long a, const vec_ZZ& b) { mul(x, b, a); } void add(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b); void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b); void clear(vec_ZZ& x); void negate(vec_ZZ& x, const vec_ZZ& a); void InnerProduct(ZZ& x, const vec_ZZ& a, const vec_ZZ& b); long IsZero(const vec_ZZ& a); vec_ZZ operator+(const vec_ZZ& a, const vec_ZZ& b); vec_ZZ operator-(const vec_ZZ& a, const vec_ZZ& b); vec_ZZ operator-(const vec_ZZ& a); inline vec_ZZ operator*(const vec_ZZ& a, const ZZ& b) { vec_ZZ x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ, x); } inline vec_ZZ operator*(const vec_ZZ& a, long b) { vec_ZZ x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ, x); } inline vec_ZZ operator*(const ZZ& a, const vec_ZZ& b) { vec_ZZ x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ, x); } inline vec_ZZ operator*(long a, const vec_ZZ& b) { vec_ZZ x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ, x); } ZZ operator*(const vec_ZZ& a, const vec_ZZ& b); // assignment operator notation: inline vec_ZZ& operator+=(vec_ZZ& x, const vec_ZZ& a) { add(x, x, a); return x; } inline vec_ZZ& operator-=(vec_ZZ& x, const vec_ZZ& a) { sub(x, x, a); return x; } inline vec_ZZ& operator*=(vec_ZZ& x, const ZZ& a) { mul(x, x, a); return x; } inline vec_ZZ& operator*=(vec_ZZ& x, long a) { mul(x, x, a); return x; } void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n); inline vec_ZZ VectorCopy(const vec_ZZ& a, long n) { vec_ZZ x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_ZZ, x); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_ZZVec.h000644 000765 000024 00000000247 12377144457 016726 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_ZZVec__H #define NTL_vec_ZZVec__H #include #include NTL_OPEN_NNS typedef Vec vec_ZZVec; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_ZZ_p.h000644 000765 000024 00000004532 12377144457 016610 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_ZZ_p__H #define NTL_vec_ZZ_p__H #include #include NTL_OPEN_NNS typedef Vec vec_ZZ_p; void conv(vec_ZZ_p& x, const vec_ZZ& a); inline vec_ZZ_p to_vec_ZZ_p(const vec_ZZ& a) { vec_ZZ_p x; conv(x, a); NTL_OPT_RETURN(vec_ZZ_p, x); } void conv(vec_ZZ& x, const vec_ZZ_p& a); inline vec_ZZ to_vec_ZZ(const vec_ZZ_p& a) { vec_ZZ x; conv(x, a); NTL_OPT_RETURN(vec_ZZ, x); } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_p& b); inline void mul(vec_ZZ_p& x, const ZZ_p& a, const vec_ZZ_p& b) { mul(x, b, a); } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, long b); inline void mul(vec_ZZ_p& x, long a, const vec_ZZ_p& b) { mul(x, b, a); } void add(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); void sub(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); void clear(vec_ZZ_p& x); void negate(vec_ZZ_p& x, const vec_ZZ_p& a); void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b, long offset); long IsZero(const vec_ZZ_p& a); void VectorCopy(vec_ZZ_p& x, const vec_ZZ_p& a, long n); inline vec_ZZ_p VectorCopy(const vec_ZZ_p& a, long n) { vec_ZZ_p x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_ZZ_p, x); } vec_ZZ_p operator+(const vec_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator-(const vec_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator-(const vec_ZZ_p& a); inline vec_ZZ_p operator*(const vec_ZZ_p& a, const ZZ_p& b) { vec_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_p, x); } inline vec_ZZ_p operator*(const vec_ZZ_p& a, long b) { vec_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_p, x); } inline vec_ZZ_p operator*(const ZZ_p& a, const vec_ZZ_p& b) { vec_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_p, x); } inline vec_ZZ_p operator*(long a, const vec_ZZ_p& b) { vec_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_p, x); } ZZ_p operator*(const vec_ZZ_p& a, const vec_ZZ_p& b); // assignment operator notation: inline vec_ZZ_p& operator+=(vec_ZZ_p& x, const vec_ZZ_p& a) { add(x, x, a); return x; } inline vec_ZZ_p& operator-=(vec_ZZ_p& x, const vec_ZZ_p& a) { sub(x, x, a); return x; } inline vec_ZZ_p& operator*=(vec_ZZ_p& x, const ZZ_p& a) { mul(x, x, a); return x; } inline vec_ZZ_p& operator*=(vec_ZZ_p& x, long a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_ZZ_pE.h000644 000765 000024 00000005135 12377144457 016715 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_ZZ_pE__H #define NTL_vec_ZZ_pE__H #include NTL_OPEN_NNS typedef Vec vec_ZZ_pE; void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pE& b); inline void mul(vec_ZZ_pE& x, const ZZ_pE& a, const vec_ZZ_pE& b) { mul(x, b, a); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_p& b); inline void mul(vec_ZZ_pE& x, const ZZ_p& a, const vec_ZZ_pE& b) { mul(x, b, a); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, long b); inline void mul(vec_ZZ_pE& x, long a, const vec_ZZ_pE& b) { mul(x, b, a); } void add(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); void sub(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); void negate(vec_ZZ_pE& x, const vec_ZZ_pE& a); void clear(vec_ZZ_pE& x); void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b, long offset); long IsZero(const vec_ZZ_pE& a); void VectorCopy(vec_ZZ_pE& x, const vec_ZZ_pE& a, long n); inline vec_ZZ_pE VectorCopy(const vec_ZZ_pE& a, long n) { vec_ZZ_pE x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_ZZ_pE, x); } vec_ZZ_pE operator+(const vec_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator-(const vec_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator-(const vec_ZZ_pE& a); inline vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_pE& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_p& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(const vec_ZZ_pE& a, long b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(const ZZ_pE& a, const vec_ZZ_pE& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(const ZZ_p& a, const vec_ZZ_pE& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(long a, const vec_ZZ_pE& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } ZZ_pE operator*(const vec_ZZ_pE& a, const vec_ZZ_pE& b); // assignment operator notation: inline vec_ZZ_pE& operator+=(vec_ZZ_pE& x, const vec_ZZ_pE& a) { add(x, x, a); return x; } inline vec_ZZ_pE& operator-=(vec_ZZ_pE& x, const vec_ZZ_pE& a) { sub(x, x, a); return x; } inline vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_pE& a) { mul(x, x, a); return x; } inline vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_p& a) { mul(x, x, a); return x; } inline vec_ZZ_pE& operator*=(vec_ZZ_pE& x, long a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_double.h000644 000765 000024 00000000224 12377144457 017172 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_double__H #define NTL_vec_double__H #include NTL_OPEN_NNS typedef Vec vec_double; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_long.h000644 000765 000024 00000000214 12377144457 016656 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_long__H #define NTL_vec_long__H #include NTL_OPEN_NNS typedef Vec vec_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_lzz_p.h000644 000765 000024 00000004555 12377144457 017071 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_zz_p__H #define NTL_vec_zz_p__H #include #include NTL_OPEN_NNS typedef Vec vec_zz_p; void conv(vec_zz_p& x, const vec_ZZ& a); inline vec_zz_p to_vec_zz_p(const vec_ZZ& a) { vec_zz_p x; conv(x, a); NTL_OPT_RETURN(vec_zz_p, x); } void conv(vec_ZZ& x, const vec_zz_p& a); inline vec_ZZ to_vec_ZZ(const vec_zz_p& a) { vec_ZZ x; conv(x, a); NTL_OPT_RETURN(vec_ZZ, x); } long CRT(vec_ZZ& g, ZZ& a, const vec_zz_p& G); void add(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b); void sub(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b); void clear(vec_zz_p& x); void negate(vec_zz_p& x, const vec_zz_p& a); void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b); void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b, long offset); void mul(vec_zz_p& x, const vec_zz_p& a, zz_p b); inline void mul(vec_zz_p& x, zz_p a, const vec_zz_p& b) { mul(x, b, a); } void mul(vec_zz_p& x, const vec_zz_p& a, long b); inline void mul(vec_zz_p& x, long a, const vec_zz_p& b) { mul(x, b, a); } long IsZero(const vec_zz_p& a); void VectorCopy(vec_zz_p& x, const vec_zz_p& a, long n); inline vec_zz_p VectorCopy(const vec_zz_p& a, long n) { vec_zz_p x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_zz_p, x); } vec_zz_p operator+(const vec_zz_p& a, const vec_zz_p& b); vec_zz_p operator-(const vec_zz_p& a, const vec_zz_p& b); vec_zz_p operator-(const vec_zz_p& a); zz_p operator*(const vec_zz_p& a, const vec_zz_p& b); inline vec_zz_p operator*(const vec_zz_p& a, zz_p b) { vec_zz_p x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_p, x); } inline vec_zz_p operator*(const vec_zz_p& a, long b) { vec_zz_p x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_p, x); } inline vec_zz_p operator*(zz_p a, const vec_zz_p& b) { vec_zz_p x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_p, x); } inline vec_zz_p operator*(long a, const vec_zz_p& b) { vec_zz_p x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_p, x); } // assignment operator notation: inline vec_zz_p& operator+=(vec_zz_p& x, const vec_zz_p& a) { add(x, x, a); return x; } inline vec_zz_p& operator-=(vec_zz_p& x, const vec_zz_p& a) { sub(x, x, a); return x; } inline vec_zz_p& operator*=(vec_zz_p& x, zz_p a) { mul(x, x, a); return x; } inline vec_zz_p& operator*=(vec_zz_p& x, long a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_lzz_pE.h000644 000765 000024 00000005136 12377144457 017172 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_zz_pE__H #define NTL_vec_zz_pE__H #include NTL_OPEN_NNS typedef Vec vec_zz_pE; void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_pE& b); inline void mul(vec_zz_pE& x, const zz_pE& a, const vec_zz_pE& b) { mul(x, b, a); } void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_p& b); inline void mul(vec_zz_pE& x, const zz_p& a, const vec_zz_pE& b) { mul(x, b, a); } void mul(vec_zz_pE& x, const vec_zz_pE& a, long b); inline void mul(vec_zz_pE& x, long a, const vec_zz_pE& b) { mul(x, b, a); } void add(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); void sub(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); void negate(vec_zz_pE& x, const vec_zz_pE& a); void clear(vec_zz_pE& x); void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b, long offset); long IsZero(const vec_zz_pE& a); void VectorCopy(vec_zz_pE& x, const vec_zz_pE& a, long n); inline vec_zz_pE VectorCopy(const vec_zz_pE& a, long n) { vec_zz_pE x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_zz_pE, x); } vec_zz_pE operator+(const vec_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator-(const vec_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator-(const vec_zz_pE& a); inline vec_zz_pE operator*(const vec_zz_pE& a, const zz_pE& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(const vec_zz_pE& a, const zz_p& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(const vec_zz_pE& a, long b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(const zz_pE& a, const vec_zz_pE& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(const zz_p& a, const vec_zz_pE& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(long a, const vec_zz_pE& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } zz_pE operator*(const vec_zz_pE& a, const vec_zz_pE& b); // assignment operator notation: inline vec_zz_pE& operator+=(vec_zz_pE& x, const vec_zz_pE& a) { add(x, x, a); return x; } inline vec_zz_pE& operator-=(vec_zz_pE& x, const vec_zz_pE& a) { sub(x, x, a); return x; } inline vec_zz_pE& operator*=(vec_zz_pE& x, const zz_pE& a) { mul(x, x, a); return x; } inline vec_zz_pE& operator*=(vec_zz_pE& x, const zz_p& a) { mul(x, x, a); return x; } inline vec_zz_pE& operator*=(vec_zz_pE& x, long a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_quad_float.h000644 000765 000024 00000000300 12377144457 020032 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_quad_float__H #define NTL_vec_quad_float__H #include #include NTL_OPEN_NNS typedef Vec vec_quad_float; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_ulong.h000644 000765 000024 00000000230 12377144460 017033 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_ulong__H #define NTL_vec_ulong__H #include NTL_OPEN_NNS typedef Vec vec_ulong; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_GF2.h000644 000765 000024 00000000264 12377144457 017137 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_GF2__H #define NTL_vec_vec_GF2__H #include #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_GF2; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_GF2E.h000644 000765 000024 00000000241 12377144457 017237 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_GF2E__H #define NTL_vec_vec_GF2E__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_GF2E; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_RR.h000644 000765 000024 00000000227 12377144457 017103 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_RR__H #define NTL_vec_vec_RR__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_RR; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_ZZ.h000644 000765 000024 00000000227 12377144457 017123 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_ZZ__H #define NTL_vec_vec_ZZ__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_ZZ; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_ZZ_p.h000644 000765 000024 00000000241 12377144457 017436 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_ZZ_p__H #define NTL_vec_vec_ZZ_p__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_ZZ_p; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_ZZ_pE.h000644 000765 000024 00000000246 12377144457 017550 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_ZZ_pE__H #define NTL_vec_vec_ZZ_pE__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_ZZ_pE; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_long.h000644 000765 000024 00000000242 12377144457 017514 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_long__H #define NTL_vec_vec_long__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_long; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_lzz_p.h000644 000765 000024 00000000242 12377144457 017713 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_zz_p__H #define NTL_vec_vec_zz_p__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_zz_p; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_lzz_pE.h000644 000765 000024 00000000247 12377144457 020025 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_zz_pE__H #define NTL_vec_vec_zz_pE__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_zz_pE; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_vec_ulong.h000644 000765 000024 00000000257 12377144460 017701 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_vec_ulong__H #define NTL_vec_vec_ulong__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_ulong; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vec_xdouble.h000644 000765 000024 00000000262 12377144457 017364 0ustar00shoupstaff000000 000000 #ifndef NTL_vec_xdouble__H #define NTL_vec_xdouble__H #include #include NTL_OPEN_NNS typedef Vec vec_xdouble; NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/vector.h000644 000765 000024 00000037313 12377144457 016376 0ustar00shoupstaff000000 000000 #ifndef NTL_vector__H #define NTL_vector__H #include struct _ntl_VectorHeader { long length; long alloc; long init; long fixed; }; union _ntl_AlignedVectorHeader { _ntl_VectorHeader h; double x1; long x2; char *x3; }; #define NTL_VECTOR_HEADER_SIZE (sizeof(_ntl_AlignedVectorHeader)) #define NTL_VEC_HEAD(p) (& (((_ntl_AlignedVectorHeader *) p)[-1].h)) struct _ntl_vector_placement { void *p; }; inline _ntl_vector_placement _ntl_vector_placement_fn(void *p) { _ntl_vector_placement x; x.p = p; return x; } inline void *operator new(NTL_SNS size_t, _ntl_vector_placement x) { return x.p; } // All of this monkey business is to avoid possible clashes with // a "placement new" operator which may or may not be defined // in a standard header file....why wasn't this just built // into the language to begin with? #ifndef NTL_RANGE_CHECK #define NTL_RANGE_CHECK_CODE #define NTL_RANGE_CHECK_CODE1(i) #else #define NTL_RANGE_CHECK_CODE if (l__i < 0 || !_vec__rep || l__i >= NTL_VEC_HEAD(_vec__rep)->length) RangeError(l__i); #define NTL_RANGE_CHECK_CODE1(i) if ((i) < 0 || !_vec__rep || (i) >= NTL_VEC_HEAD(_vec__rep)->length) RangeError(i); #endif // vectors are allocated in chunks of this size #ifndef NTL_VectorMinAlloc #define NTL_VectorMinAlloc (4) #endif // vectors are always expanded by at least this ratio #ifndef NTL_VectorExpansionRatio #define NTL_VectorExpansionRatio (1.2) #endif // controls initialization during input #ifndef NTL_VectorInputBlock #define NTL_VectorInputBlock 50 #endif NTL_OPEN_NNS template void BlockConstruct(T* p, long n) { for (long i = 0; i < n; i++) (void) new(_ntl_vector_placement_fn(&p[i])) T; } template void BlockConstructFromVec(T* p, long n, const T* q) { for (long i = 0; i < n; i++) (void) new(_ntl_vector_placement_fn(&p[i])) T(q[i]); } template void BlockConstructFromObj(T* p, long n, const T& q) { for (long i = 0; i < n; i++) (void) new(_ntl_vector_placement_fn(&p[i])) T(q); } template void BlockDestroy(T* p, long n) { for (long i = 0; i < n; i++) p[i].~T(); } template class Vec { public: T *_vec__rep; void RangeError(long i) const; Vec() : _vec__rep(0) { } Vec(INIT_SIZE_TYPE, long n) : _vec__rep(0) { SetLength(n); } Vec(const Vec& a) : _vec__rep(0) { *this = a; } Vec& operator=(const Vec& a); ~Vec(); void kill(); void SetMaxLength(long n); void FixLength(long n); void QuickSetLength(long n) { NTL_VEC_HEAD(_vec__rep)->length = n; } void SetLength(long n) { if (_vec__rep && !NTL_VEC_HEAD(_vec__rep)->fixed && n >= 0 && n <= NTL_VEC_HEAD(_vec__rep)->init) NTL_VEC_HEAD(_vec__rep)->length = n; else DoSetLength(n); } void SetLength(long n, const T& a) { if (_vec__rep && !NTL_VEC_HEAD(_vec__rep)->fixed && n >= 0 && n <= NTL_VEC_HEAD(_vec__rep)->init) NTL_VEC_HEAD(_vec__rep)->length = n; else DoSetLength(n, a); } long length() const { return (!_vec__rep) ? 0 : NTL_VEC_HEAD(_vec__rep)->length; } long MaxLength() const { return (!_vec__rep) ? 0 : NTL_VEC_HEAD(_vec__rep)->init; } long allocated() const { return (!_vec__rep) ? 0 : NTL_VEC_HEAD(_vec__rep)->alloc; } long fixed() const { return _vec__rep && NTL_VEC_HEAD(_vec__rep)->fixed; } T& operator[](long i) { NTL_RANGE_CHECK_CODE1(i) return _vec__rep[i]; } const T& operator[](long i) const { NTL_RANGE_CHECK_CODE1(i) return _vec__rep[i]; } T& RawGet(long i) { return _vec__rep[i]; } const T& RawGet(long i) const { return _vec__rep[i]; } T& operator()(long i) { return (*this)[i-1]; } const T& operator()(long i) const { return (*this)[i-1]; } const T* elts() const { return _vec__rep; } T* elts() { return _vec__rep; } Vec(Vec& x, INIT_TRANS_TYPE) { _vec__rep = x._vec__rep; x._vec__rep = 0; } long position(const T& a) const; long position1(const T& a) const; void swap(Vec& y); void append(const T& a); void append(const Vec& w); // Some compatibility with vec_GF2 const T& get(long i) const { return (*this)[i]; } void put(long i, const T& a) { (*this)[i] = a; } // Some STL compatibility typedef T value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type *iterator; typedef const value_type *const_iterator; const T* data() const { return elts(); } T* data() { return elts(); } T* begin() { return elts(); } const T* begin() const { return elts(); } T* end() { if (elts()) return elts() + length(); else return 0; } const T* end() const { if (elts()) return elts() + length(); else return 0; } T& at(long i) { if ((i) < 0 || !_vec__rep || (i) >= NTL_VEC_HEAD(_vec__rep)->length) RangeError(i); return _vec__rep[i]; } const T& at(long i) const { if ((i) < 0 || !_vec__rep || (i) >= NTL_VEC_HEAD(_vec__rep)->length) RangeError(i); return _vec__rep[i]; } private: void DoSetLength(long n); void DoSetLength(long n, const T& a); void AdjustLength(long n) { if (_vec__rep) NTL_VEC_HEAD(_vec__rep)->length = n; } void AdjustAlloc(long n) { if (_vec__rep) NTL_VEC_HEAD(_vec__rep)->alloc = n; } void AdjustMaxLength(long n) { if (_vec__rep) NTL_VEC_HEAD(_vec__rep)->init = n; } void AllocateTo(long n); // reserves space for n items, also checking void Init(long n); // make sure first n entries are initialized void Init(long n, const T* src); // same, but use src void Init(long n, const T& src); // same, but use src }; #if (!defined(NTL_CLEAN_PTR)) template long Vec::position(const T& a) const { if (!_vec__rep) return -1; long num_alloc = NTL_VEC_HEAD(_vec__rep)->alloc; long num_init = NTL_VEC_HEAD(_vec__rep)->init; if (&a < _vec__rep || &a >= _vec__rep + num_alloc) return -1; long res = (&a) - _vec__rep; if (res < 0 || res >= num_alloc || _vec__rep + res != &a) return -1; if (res >= num_init) Error("position: reference to uninitialized object"); return res; } template long Vec::position1(const T& a) const { if (!_vec__rep) return -1; long len = NTL_VEC_HEAD(_vec__rep)->length; if (&a < _vec__rep || &a >= _vec__rep + len) return -1; long res = (&a) - _vec__rep; if (res < 0 || res >= len || _vec__rep + res != &a) return -1; return res; } #else template long Vec::position(const T& a) const { if (!_vec__rep) return -1; long num_alloc = NTL_VEC_HEAD(_vec__rep)->alloc; long num_init = NTL_VEC_HEAD(_vec__rep)->init; long res; res = 0; while (res < num_alloc && _vec__rep + res != &a) res++; if (res >= num_alloc) return -1; if (res >= num_init) Error("position: reference to uninitialized object"); return res; } template long Vec::position1(const T& a) const { if (!_vec__rep) return -1; long len = NTL_VEC_HEAD(_vec__rep)->length; long res; res = 0; while (res < len && _vec__rep + res != &a) res++; if (res >= len) return -1; return res; } #endif template void Vec::AllocateTo(long n) { long m; if (n < 0) { Error("negative length in vector::SetLength"); } if (NTL_OVERFLOW(n, sizeof(T), 0)) Error("excessive length in vector::SetLength"); if (_vec__rep && NTL_VEC_HEAD(_vec__rep)->fixed) { if (NTL_VEC_HEAD(_vec__rep)->length == n) return; else Error("SetLength: can't change this vector's length"); } if (n == 0) { return; } if (!_vec__rep) { m = ((n+NTL_VectorMinAlloc-1)/NTL_VectorMinAlloc) * NTL_VectorMinAlloc; char *p = (char *) NTL_SNS_MALLOC(m, sizeof(T), sizeof(_ntl_AlignedVectorHeader)); if (!p) { Error("out of memory in vector::SetLength()"); } _vec__rep = (T *) (p + sizeof(_ntl_AlignedVectorHeader)); NTL_VEC_HEAD(_vec__rep)->length = 0; NTL_VEC_HEAD(_vec__rep)->alloc = m; NTL_VEC_HEAD(_vec__rep)->init = 0; NTL_VEC_HEAD(_vec__rep)->fixed = 0; } else if (n > NTL_VEC_HEAD(_vec__rep)->alloc) { m = max(n, long(NTL_VectorExpansionRatio*NTL_VEC_HEAD(_vec__rep)->alloc)); m = ((m+NTL_VectorMinAlloc-1)/NTL_VectorMinAlloc) * NTL_VectorMinAlloc; char *p = ((char *) _vec__rep) - sizeof(_ntl_AlignedVectorHeader); p = (char *) NTL_SNS_REALLOC(p, m, sizeof(T), sizeof(_ntl_AlignedVectorHeader)); if (!p) { Error("out of memory in vector::SetLength()"); } _vec__rep = (T *) (p + sizeof(_ntl_AlignedVectorHeader)); NTL_VEC_HEAD(_vec__rep)->alloc = m; } } template void Vec::Init(long n) { long num_init = MaxLength(); if (n <= num_init) return; BlockConstruct(_vec__rep + num_init, n-num_init); AdjustMaxLength(n); } template void Vec::Init(long n, const T *src) { long num_init = MaxLength(); if (n <= num_init) return; BlockConstructFromVec(_vec__rep + num_init, n-num_init, src); AdjustMaxLength(n); } template void Vec::Init(long n, const T& src) { long num_init = MaxLength(); if (n <= num_init) return; BlockConstructFromObj(_vec__rep + num_init, n-num_init, src); AdjustMaxLength(n); } template void Vec::DoSetLength(long n) { AllocateTo(n); Init(n); AdjustLength(n); } template void Vec::DoSetLength(long n, const T& a) { // if vector gets moved, we have to worry about // a aliasing a vector element const T *src = &a; long pos = -1; if (n >= allocated()) pos = position(a); AllocateTo(n); if (pos != -1) src = elts() + pos; Init(n, *src); AdjustLength(n); } template void Vec::SetMaxLength(long n) { long OldLength = length(); SetLength(n); SetLength(OldLength); } template void Vec::FixLength(long n) { if (_vec__rep) Error("FixLength: can't fix this vector"); if (n < 0) Error("FixLength: negative length"); if (n > 0) SetLength(n); else { char *p = (char *) NTL_SNS_MALLOC(0, sizeof(T), sizeof(_ntl_AlignedVectorHeader)); if (!p) { Error("out of memory in vector::FixLength()"); } _vec__rep = (T *) (p + sizeof(_ntl_AlignedVectorHeader)); NTL_VEC_HEAD(_vec__rep)->length = 0; NTL_VEC_HEAD(_vec__rep)->init = 0; NTL_VEC_HEAD(_vec__rep)->alloc = 0; } NTL_VEC_HEAD(_vec__rep)->fixed = 1; } template Vec& Vec::operator=(const Vec& a) { if (this == &a) return *this; long len = length(); long init = MaxLength(); long src_len = a.length(); const T *src = a.elts(); AllocateTo(src_len); T *dst = elts(); if (src_len <= init) { long i; for (i = 0; i < src_len; i++) dst[i] = src[i]; } else { long i; for (i = 0; i < init; i++) dst[i] = src[i]; Init(src_len, src+init); } AdjustLength(src_len); return *this; } template Vec::~Vec() { if (!_vec__rep) return; BlockDestroy(_vec__rep, NTL_VEC_HEAD(_vec__rep)->init); NTL_SNS free(((char *) _vec__rep) - sizeof(_ntl_AlignedVectorHeader)); } template void Vec::kill() { if (!_vec__rep) return; if (NTL_VEC_HEAD(_vec__rep)->fixed) Error("can't kill this vector"); BlockDestroy(_vec__rep, NTL_VEC_HEAD(_vec__rep)->init); NTL_SNS free(((char *) _vec__rep) - sizeof(_ntl_AlignedVectorHeader)); _vec__rep = 0; } template void Vec::RangeError(long i) const { NTL_SNS cerr << "index out of range in vector: "; NTL_SNS cerr << i; if (!_vec__rep) NTL_SNS cerr << "(0)"; else NTL_SNS cerr << "(" << NTL_VEC_HEAD(_vec__rep)->length << ")"; Error(""); } template void Vec::swap(Vec& y) { T* t; long xf = fixed(); long yf = y.fixed(); if (xf != yf || (xf && NTL_VEC_HEAD(_vec__rep)->length != NTL_VEC_HEAD(y._vec__rep)->length)) Error("swap: can't swap these vectors"); t = _vec__rep; _vec__rep = y._vec__rep; y._vec__rep = t; } template void swap(Vec& x, Vec& y) { x.swap(y); } template void Vec::append(const T& a) { long len = length(); long init = MaxLength(); long src_len = 1; // if vector gets moved, we have to worry about // a aliasing a vector element const T *src = &a; long pos = -1; if (len >= allocated()) pos = position(a); AllocateTo(len+src_len); long i; T *dst = elts(); if (pos != -1) src = dst + pos; if (len+src_len <= init) { for (i = 0; i < src_len; i++) dst[i+len] = src[i]; } else { for (i = 0; i < init-len; i++) dst[i+len] = src[i]; Init(src_len+len, src+init-len); } AdjustLength(len+src_len); } template void append(Vec& v, const T& a) { v.append(a); } template void Vec::append(const Vec& w) { long len = length(); long init = MaxLength(); long src_len = w.length(); AllocateTo(len+src_len); const T *src = w.elts(); T *dst = elts(); if (len+src_len <= init) { long i; for (i = 0; i < src_len; i++) dst[i+len] = src[i]; } else { long i; for (i = 0; i < init-len; i++) dst[i+len] = src[i]; Init(src_len+len, src+init-len); } AdjustLength(len+src_len); } template void append(Vec& v, const Vec& w) { v.append(w); } template NTL_SNS istream & operator>>(NTL_SNS istream& s, Vec& a) { Vec ibuf; long c; long n; if (!s) Error("bad vector input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != '[') { Error("bad vector input"); } n = 0; ibuf.SetLength(0); s.get(); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } while (c != ']' && !IsEOFChar(c)) { if (n % NTL_VectorInputBlock == 0) ibuf.SetMaxLength(n + NTL_VectorInputBlock); n++; ibuf.SetLength(n); if (!(s >> ibuf[n-1])) Error("bad vector input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } } if (IsEOFChar(c)) Error("bad vector input"); s.get(); a = ibuf; return s; } template NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const Vec& a) { long i, n; n = a.length(); s << '['; for (i = 0; i < n; i++) { s << a[i]; if (i < n-1) s << " "; } s << ']'; return s; } template long operator==(const Vec& a, const Vec& b) { long n = a.length(); if (b.length() != n) return 0; const T* ap = a.elts(); const T* bp = b.elts(); long i; for (i = 0; i < n; i++) if (ap[i] != bp[i]) return 0; return 1; } template long operator!=(const Vec& a, const Vec& b) { return !(a == b); } // conversions template void conv(Vec& x, const Vec& a) { long n = a.length(); x.SetLength(n); for (long i = 0; i < n; i++) conv(x[i], a[i]); } NTL_CLOSE_NNS #endif ntl-6.2.1/include/NTL/version.h000644 000765 000024 00000000263 12377144457 016553 0ustar00shoupstaff000000 000000 #ifndef NTL_version__H #define NTL_version__H #define NTL_VERSION "6.2.0" #define NTL_MAJOR_VERSION (6) #define NTL_MINOR_VERSION (2) #define NTL_REVISION (1) #endif ntl-6.2.1/include/NTL/xdouble.h000644 000765 000024 00000020161 12377144457 016527 0ustar00shoupstaff000000 000000 #ifndef NTL_xdouble__H #define NTL_xdouble__H #include NTL_OPEN_NNS // NTL_XD_HBOUND = 2^{max(NTL_DOUBLE_PRECISION,NTL_BITS_PER_LONG)+4} #if (NTL_DOUBLE_PRECISION > NTL_BITS_PER_LONG) #define NTL_XD_HBOUND (NTL_FDOUBLE_PRECISION*32.0) #define NTL_XD_HBOUND_LOG (NTL_DOUBLE_PRECISION+4) #else #define NTL_XD_HBOUND (double(1L << (NTL_BITS_PER_LONG - 2))*64.0) #define NTL_XD_HBOUND_LOG (NTL_BITS_PER_LONG+4) #endif #define NTL_XD_HBOUND_INV (double(1)/NTL_XD_HBOUND) #define NTL_XD_BOUND (NTL_XD_HBOUND*NTL_XD_HBOUND) #define NTL_XD_BOUND_INV (double(1)/NTL_XD_BOUND) class xdouble { public: double x; long e; xdouble() : x(0), e(0) { } explicit xdouble(double a) : x(0), e(0) { *this = a; } inline xdouble& operator=(double a); ~xdouble() { } void normalize(); NTL_THREAD_LOCAL static long oprec; static void SetOutputPrecision(long p); static long OutputPrecision() { return oprec; } double mantissa() const { return x; } long exponent() const { return e; } xdouble(double xx, long ee) : x(xx), e(ee) { } // internal use only }; inline xdouble to_xdouble(int a) { return xdouble(a, 0); } inline xdouble to_xdouble(long a) { return xdouble(a, 0); } inline xdouble to_xdouble(unsigned int a) { return xdouble(a, 0); } inline xdouble to_xdouble(unsigned long a) { return xdouble(a, 0); } xdouble to_xdouble(double a); inline xdouble to_xdouble(float a) { return to_xdouble(double(a)); } xdouble to_xdouble(const char *a); inline xdouble& xdouble::operator=(double a) { *this = to_xdouble(a); return *this; } xdouble operator+(const xdouble& a, const xdouble& b); inline xdouble operator+(const xdouble& a, double b) { return a + to_xdouble(b); } inline xdouble operator+(double a, const xdouble& b) { return to_xdouble(a) + b; } xdouble operator-(const xdouble& a, const xdouble& b); inline xdouble operator-(const xdouble& a, double b) { return a - to_xdouble(b); } inline xdouble operator-(double a, const xdouble& b) { return to_xdouble(a) - b; } xdouble operator*(const xdouble& a, const xdouble& b); inline xdouble operator*(const xdouble& a, double b) { return a * to_xdouble(b); } inline xdouble operator*(double a, const xdouble& b) { return to_xdouble(a) * b; } xdouble operator/(const xdouble& a, const xdouble& b); inline xdouble operator/(const xdouble& a, double b) { return a / to_xdouble(b); } inline xdouble operator/(double a, const xdouble& b) { return to_xdouble(a) / b; } xdouble operator-(const xdouble& a); inline xdouble& operator+=(xdouble& a, const xdouble& b) { a = a + b; return a; } inline xdouble& operator+=(xdouble& a, double b) { a = a + b; return a; } inline xdouble& operator-=(xdouble& a, const xdouble& b) { a = a - b; return a; } inline xdouble& operator-=(xdouble& a, double b) { a = a - b; return a; } inline xdouble& operator*=(xdouble& a, const xdouble& b) { a = a * b; return a; } inline xdouble& operator*=(xdouble& a, double b) { a = a * b; return a; } inline xdouble& operator/=(xdouble& a, const xdouble& b) { a = a / b; return a; } inline xdouble& operator/=(xdouble& a, double b) { a = a / b; return a; } inline xdouble& operator++(xdouble& a) { a = a + to_xdouble(1); return a; } inline xdouble& operator--(xdouble& a) { a = a - to_xdouble(1); return a; } inline void operator++(xdouble& a, int) { a = a + to_xdouble(1); } inline void operator--(xdouble& a, int) { a = a - to_xdouble(1); } long compare(const xdouble& a, const xdouble& b); inline long compare(const xdouble& a, double b) { return compare(a, to_xdouble(b)); } inline long compare(double a, const xdouble& b) { return compare(to_xdouble(a), b); } long sign(const xdouble& a); inline long operator==(const xdouble& a, const xdouble& b) { return compare(a, b) == 0; } inline long operator!=(const xdouble& a, const xdouble& b) { return compare(a, b) != 0; } inline long operator<=(const xdouble& a, const xdouble& b) { return compare(a, b) <= 0; } inline long operator>=(const xdouble& a, const xdouble& b) { return compare(a, b) >= 0; } inline long operator <(const xdouble& a, const xdouble& b) { return compare(a, b) < 0; } inline long operator >(const xdouble& a, const xdouble& b) { return compare(a, b) > 0; } inline long operator==(const xdouble& a, double b) { return compare(a, b) == 0; } inline long operator!=(const xdouble& a, double b) { return compare(a, b) != 0; } inline long operator<=(const xdouble& a, double b) { return compare(a, b) <= 0; } inline long operator>=(const xdouble& a, double b) { return compare(a, b) >= 0; } inline long operator <(const xdouble& a, double b) { return compare(a, b) < 0; } inline long operator >(const xdouble& a, double b) { return compare(a, b) > 0; } inline long operator==(double a, const xdouble& b) { return compare(a, b) == 0; } inline long operator!=(double a, const xdouble& b) { return compare(a, b) != 0; } inline long operator<=(double a, const xdouble& b) { return compare(a, b) <= 0; } inline long operator>=(double a, const xdouble& b) { return compare(a, b) >= 0; } inline long operator <(double a, const xdouble& b) { return compare(a, b) < 0; } inline long operator >(double a, const xdouble& b) { return compare(a, b) > 0; } void conv(ZZ& x, const xdouble& a); // x = floor(a); inline ZZ to_ZZ(const xdouble& a) { ZZ x; conv(x, a); NTL_OPT_RETURN(ZZ, x); } xdouble to_xdouble(const ZZ& a); inline void conv(xdouble& z, const ZZ& a) { z = to_xdouble(a); } void conv(double& x, const xdouble& a); inline double to_double(const xdouble& a) { double z; conv(z, a); return z; } inline void conv(float& x, const xdouble& a) { double t; conv(t, a); x = float(t); } inline float to_float(const xdouble& a) { float z; conv(z, a); return z; } inline void conv(long& x, const xdouble& a) { double z; conv(z, a); x = long(NTL_SNS floor(z)); } inline long to_long(const xdouble& a) { long z; conv(z, a); return z; } inline void conv(int& x, const xdouble& a) { double z; conv(z, a); x = int(NTL_SNS floor(z)); } inline int to_int(const xdouble& a) { int z; conv(z, a); return z; } inline void conv(xdouble& x, const xdouble& a) { x = a; } inline xdouble to_xdouble(const xdouble& a) { return a; } inline void conv(xdouble& x, int a) { x = to_xdouble(a); } inline void conv(xdouble& x, long a) { x = to_xdouble(a); } inline void conv(xdouble& x, unsigned int a) { x = to_xdouble(a); } inline void conv(xdouble& x, unsigned long a) { x = to_xdouble(a); } inline void conv(xdouble& x, float a) { x = to_xdouble(a); } inline void conv(xdouble& x, double a) { x = to_xdouble(a); } inline void conv(xdouble& x, const char *a) { x = to_xdouble(a); } /* additional legacy conversions for v6 conversion regime */ inline void conv(unsigned int& x, const xdouble& a) { long z; conv(z, a); conv(x, z); } inline void conv(unsigned long& x, const xdouble& a) { long z; conv(z, a); conv(x, z); } /* ------------------------------------- */ NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const xdouble& a); NTL_SNS istream& operator>>(NTL_SNS istream& s, xdouble& x); xdouble trunc(const xdouble& a); xdouble floor(const xdouble& a); xdouble ceil(const xdouble& a); xdouble fabs(const xdouble& a); xdouble sqrt(const xdouble& a); void power(xdouble& z, const xdouble& a, const ZZ& e); inline xdouble power(const xdouble& a, const ZZ& e) { xdouble z; power(z, a, e); return z; } void power(xdouble& z, const xdouble& a, long e); inline xdouble power(const xdouble& a, long e) { xdouble z; power(z, a, e); return z; } void power2(xdouble& z, long e); inline xdouble power2_xdouble(long e) { xdouble z; power2(z, e); return z; } void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c); inline xdouble MulAdd(const xdouble& a, const xdouble& b, const xdouble& c) { xdouble z; MulAdd(z, a, b, c); return z; } void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c); inline xdouble MulSub(const xdouble& a, const xdouble& b, const xdouble& c) { xdouble z; MulSub(z, a, b, c); return z; } double log(const xdouble& a); xdouble xexp(double x); NTL_CLOSE_NNS #endif ntl-6.2.1/doc/GF2.cpp.html000644 000765 000024 00000030320 12377144460 015416 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/GF2.cpp.html


/**************************************************************************\

MODULE: GF2

SUMMARY:

The class GF2 represents the field GF(2).
Computationally speaking, it is not a particularly useful class.
Its main use is to make the interfaces to the various finite 
field classes as uniform as possible.

The header file for GF2 also declares the class ref_GF2, which
use used to represent non-const references to GF2's, such as
those obtained from indexing a vec_GF2, which "packs" GF2's
into words.

There are implicit conversions from ref_GF2 to const GF2
and from GF2& to ref_GF2.  Therefore, if you want to declare
a function that takes a non-const reference to a GF2, you
should declare the parameter of type ref_GF2: this will
allow you to pass variables of type GF2 as well as 
elements of vec_GF2's obtained through indexing.

For all functions defined below which take a parameter of type
GF2&, there is also a function that takes a parameter of type ref_GF2.
Theoretically, we could have just defined the functions that take
the ref_GF2 parameter type, because of the implicit conversion
from GF2& to ref_GF2; however, for efficiency reasons, both
flavors are actually provided.   It is recommended that higher-level
functions use the ref_GF2 type exclusively.


\**************************************************************************/

#include <NTL/ZZ.h>
#include <NTL/vector.h>


class GF2 {
public:

   GF2(); // initial value 0

   GF2(const GF2& a); // copy constructor
   explicit GF2(long a); // promotion constructor

   GF2& operator=(const GF2& a); // assignment
   GF2& operator=(long a); // assignment

   // typedefs to aid in generic programming
   typedef long rep_type;
   typedef GF2Context context_type;
   typedef GF2Bak bak_type;
   typedef GF2Push push_type;
   typedef GF2X poly_type;

};


long rep(GF2 a); // read-only access to representation of a





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(GF2 a, GF2 b);
long operator!=(GF2 a, GF2 b);

long IsZero(GF2 a);  // test for 0
long IsOne(GF2 a);  // test for 1

// PROMOTIONS: operators ==, != promote long to GF2 on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

GF2 operator+(GF2 a, GF2 b);
GF2 operator-(GF2 a, GF2 b);

GF2 operator-(GF2 a); // unary -

GF2& operator+=(GF2& x, GF2 a);
GF2& operator+=(GF2& x, long a);

GF2& operator-=(GF2& x, GF2 a);
GF2& operator-=(GF2& x, long a);

GF2& operator++(GF2& x);  // prefix
void operator++(GF2& x, int);  // postfix

GF2& operator--(GF2& x);  // prefix
void operator--(GF2& x, int);  // postfix

// procedural versions:


void add(GF2& x, GF2 a, GF2 b); // x = a + b
void sub(GF2& x, GF2 a, GF2 b); // x = a - b 
void negate(GF2& x, GF2 a); // x = -a

// PROMOTIONS: binary +, -, and procedures add, sub promote
// from long to GF2 on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/

// operator notation:

GF2 operator*(GF2 a, GF2 b);

GF2& operator*=(GF2& x, GF2 a);
GF2& operator*=(GF2& x, long a);

// procedural versions:

void mul(GF2& x, GF2 a, GF2 b); // x = a * b

void sqr(GF2& x, GF2 a); // x = a^2
GF2 sqr(GF2 a);

// PROMOTIONS: operator * and procedure mul promote from long to GF2
// on (a, b).


/**************************************************************************\

                                  Division

\**************************************************************************/

operator notation:

GF2 operator/(z_p a, GF2 b);

GF2& operator/=(GF2& x, GF2 a);
GF2& operator/=(GF2& x, long a);

procedural versions:

void div(GF2& x, GF2 a, GF2 b);
// x = a/b

void inv(GF2& x, GF2 a);
GF2 inv(GF2 a);
// x = 1/a

// PROMOTIONS: operator / and procedure div promote from long to GF2
// on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/


void power(GF2& x, GF2 a, long e); // x = a^e (e may be negative)
GF2 power(GF2 a, long e);


/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(GF2& x);
GF2 random_GF2();
// x = random element in GF2.  Uses RandomBnd from ZZ.


/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, GF2 a);

istream& operator>>(istream& s, GF2& x);
// a ZZ is read and reduced mod 2


/**************************************************************************\

                               Miscellany

\**************************************************************************/


void clear(GF2& x); // x = 0
void set(GF2& x); // x = 1

void swap(GF2& x, GF2& y);
// swap x and y 

static GF2 GF2::zero();
// GF2::zero() yields a read-only reference to zero

static long GF2::modulus();
// GF2::modulus() returns the value 2

template<> class Vec<GF2>;
// Forward declaration of the explicit specialization
// of Vec<GF2>.  This specialization is defined in <NTL/vec_GF2.h>,
// which must be included in source files that need to use Vec<GF2>.

GF2::GF2(INIT_NO_ALLOC_TYPE);
// provided for consistency with other classes, initialize to zero

GF2::GF2(INIT_ALLOC_TYPE);
// provided for consistency with other classes, initialize to zero

GF2::allocate();
// provided for consistency with other classes, no action



ntl-6.2.1/doc/GF2.txt000644 000765 000024 00000013676 12377144460 014527 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: GF2 SUMMARY: The class GF2 represents the field GF(2). Computationally speaking, it is not a particularly useful class. Its main use is to make the interfaces to the various finite field classes as uniform as possible. The header file for GF2 also declares the class ref_GF2, which use used to represent non-const references to GF2's, such as those obtained from indexing a vec_GF2, which "packs" GF2's into words. There are implicit conversions from ref_GF2 to const GF2 and from GF2& to ref_GF2. Therefore, if you want to declare a function that takes a non-const reference to a GF2, you should declare the parameter of type ref_GF2: this will allow you to pass variables of type GF2 as well as elements of vec_GF2's obtained through indexing. For all functions defined below which take a parameter of type GF2&, there is also a function that takes a parameter of type ref_GF2. Theoretically, we could have just defined the functions that take the ref_GF2 parameter type, because of the implicit conversion from GF2& to ref_GF2; however, for efficiency reasons, both flavors are actually provided. It is recommended that higher-level functions use the ref_GF2 type exclusively. \**************************************************************************/ #include #include class GF2 { public: GF2(); // initial value 0 GF2(const GF2& a); // copy constructor explicit GF2(long a); // promotion constructor GF2& operator=(const GF2& a); // assignment GF2& operator=(long a); // assignment // typedefs to aid in generic programming typedef long rep_type; typedef GF2Context context_type; typedef GF2Bak bak_type; typedef GF2Push push_type; typedef GF2X poly_type; }; long rep(GF2 a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(GF2 a, GF2 b); long operator!=(GF2 a, GF2 b); long IsZero(GF2 a); // test for 0 long IsOne(GF2 a); // test for 1 // PROMOTIONS: operators ==, != promote long to GF2 on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: GF2 operator+(GF2 a, GF2 b); GF2 operator-(GF2 a, GF2 b); GF2 operator-(GF2 a); // unary - GF2& operator+=(GF2& x, GF2 a); GF2& operator+=(GF2& x, long a); GF2& operator-=(GF2& x, GF2 a); GF2& operator-=(GF2& x, long a); GF2& operator++(GF2& x); // prefix void operator++(GF2& x, int); // postfix GF2& operator--(GF2& x); // prefix void operator--(GF2& x, int); // postfix // procedural versions: void add(GF2& x, GF2 a, GF2 b); // x = a + b void sub(GF2& x, GF2 a, GF2 b); // x = a - b void negate(GF2& x, GF2 a); // x = -a // PROMOTIONS: binary +, -, and procedures add, sub promote // from long to GF2 on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: GF2 operator*(GF2 a, GF2 b); GF2& operator*=(GF2& x, GF2 a); GF2& operator*=(GF2& x, long a); // procedural versions: void mul(GF2& x, GF2 a, GF2 b); // x = a * b void sqr(GF2& x, GF2 a); // x = a^2 GF2 sqr(GF2 a); // PROMOTIONS: operator * and procedure mul promote from long to GF2 // on (a, b). /**************************************************************************\ Division \**************************************************************************/ operator notation: GF2 operator/(z_p a, GF2 b); GF2& operator/=(GF2& x, GF2 a); GF2& operator/=(GF2& x, long a); procedural versions: void div(GF2& x, GF2 a, GF2 b); // x = a/b void inv(GF2& x, GF2 a); GF2 inv(GF2 a); // x = 1/a // PROMOTIONS: operator / and procedure div promote from long to GF2 // on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(GF2& x, GF2 a, long e); // x = a^e (e may be negative) GF2 power(GF2 a, long e); /**************************************************************************\ Random Elements \**************************************************************************/ void random(GF2& x); GF2 random_GF2(); // x = random element in GF2. Uses RandomBnd from ZZ. /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, GF2 a); istream& operator>>(istream& s, GF2& x); // a ZZ is read and reduced mod 2 /**************************************************************************\ Miscellany \**************************************************************************/ void clear(GF2& x); // x = 0 void set(GF2& x); // x = 1 void swap(GF2& x, GF2& y); // swap x and y static GF2 GF2::zero(); // GF2::zero() yields a read-only reference to zero static long GF2::modulus(); // GF2::modulus() returns the value 2 template<> class Vec; // Forward declaration of the explicit specialization // of Vec. This specialization is defined in , // which must be included in source files that need to use Vec. GF2::GF2(INIT_NO_ALLOC_TYPE); // provided for consistency with other classes, initialize to zero GF2::GF2(INIT_ALLOC_TYPE); // provided for consistency with other classes, initialize to zero GF2::allocate(); // provided for consistency with other classes, no action ntl-6.2.1/doc/GF2E.cpp.html000644 000765 000024 00000053522 12377144460 015534 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/GF2E.cpp.html


/**************************************************************************\

MODULE: GF2E

SUMMARY:

The class GF2E is used to represent polynomials in F_2[X] modulo a
polynomial P.  The modulus P may be any polynomial with deg(P) > 0,
not necessarily irreducible.  

Objects of the class GF2E are represented as a GF2X of degree < deg(P).

An executing program maintains a "current modulus", which is set to P using
GF2E::init(P).  The current modulus *must* be initialized before any operations
on GF2E's are performed.  The modulus may be changed, and a mechanism is provided
for saving and restoring a modulus (see classes GF2EPush and GF2EContext below).


NOTE: if P is a trinomial X^n + X^k + 1, or a pentanomial
X^n + X^k3 + X^k2 + X^k1 + 1, or of the form X^n + g, where
g has low degree, then performance will be somewhat improved.
Such polynomials are constructed by the routines
BuildSparseIrred and BuildIrred in GF2XFactoring.


\**************************************************************************/

#include <NTL/GF2X.h>

class GF2E {
public:

   GF2E(); // initial value 0

   GF2E(const GF2E& a); // copy constructor
   explicit GF2E(GF2 a); // promotion constructor
   explicit GF2E(long a); // promotion constructor

   GF2E& operator=(const GF2E& a); // assignment
   GF2E& operator=(GF2 a); // assignment
   GF2E& operator=(long a); // assignment

   ~GF2E(); // destructor

   void init(const GF2X& P);
   // GF2E::init(P) initializes the current modulus to P;
   // required: deg(P) >= 1.

   static const GF2XModulus& modulus();
   // GF2E::modulus() yields read-only reference to the current modulus 

   static long degree();
   // GF2E::degree() returns deg(P)

   // typedefs to aid generic programming
   typedef GF2X rep_type;
   typedef GF2EContext context_type;
   typedef GF2EBak bak_type;
   typedef GF2EPush push_type;
   typedef GF2EX poly_type;

};


const GF2X& rep(const GF2E& a); // read-only access to representation of a



/**************************************************************************\

                                  Comparison

\**************************************************************************/

long operator==(const GF2E& a, const GF2E& b);
long operator!=(const GF2E& a, const GF2E& b);

long IsZero(const GF2E& a);  // test for 0
long IsOne(const GF2E& a);  // test for 1

// PROMOTIONS: ==, != promote {long, GF2} to GF2E on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

GF2E operator+(const GF2E& a, const GF2E& b);

GF2E operator-(const GF2E& a, const GF2E& b);
GF2E operator-(const GF2E& a);

GF2E& operator+=(GF2E& x, const GF2E& a);
GF2E& operator+=(GF2E& x, GF2 a);
GF2E& operator+=(GF2E& x, long a);

GF2E& operator++(GF2E& x); // prefix
void operator++(GF2E& x, int); // postfix

GF2E& operator-=(GF2E& x, const GF2E& a);
GF2E& operator-=(GF2E& x, GF2 a);
GF2E& operator-=(GF2E& x, long a);

GF2E& operator--(GF2E& x); // prefix
void operator--(GF2E& x, int); // postfix

// procedural versions:

void add(GF2E& x, const GF2E& a, const GF2E& b); // x = a + b
void sub(GF2E& x, const GF2E& a, const GF2E& b); // x = a - b = a + b
void negate(GF2E& x, const GF2E& a); // x = - a = a

// PROMOTIONS: +, -, add, sub promote {long, GF2} to GF2E on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/


// operator notation:

GF2E operator*(const GF2E& a, const GF2E& b);

GF2E& operator*=(GF2E& x, const GF2E& a);
GF2E& operator*=(GF2E& x, GF2 a);
GF2E& operator*=(GF2E& x, long a);

// procedural versions:


void mul(GF2E& x, const GF2E& a, const GF2E& b); // x = a * b

void sqr(GF2E& x, const GF2E& a); // x = a^2
GF2E sqr(const GF2E& a);

// PROMOTIONS: *, mul promote {long, GF2} to GF2E on (a, b).


/**************************************************************************\

                                     Division

\**************************************************************************/


// operator notation:

GF2E operator/(const GF2E& a, const GF2E& b);

GF2E& operator/=(GF2E& x, const GF2E& a);
GF2E& operator/=(GF2E& x, GF2 a);
GF2E& operator/=(GF2E& x, long a);


// procedural versions:

void div(GF2E& x, const GF2E& a, const GF2E& b);
// x = a/b.  If b is not invertible, an error is raised.

void inv(GF2E& x, const GF2E& a);
GF2E inv(const GF2E& a);
// x = 1/a

PROMOTIONS: /, div promote {long, GF2} to GF2E on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/



void power(GF2E& x, const GF2E& a, const ZZ& e);
GF2E power(const GF2E& a, const ZZ& e);

void power(GF2E& x, const GF2E& a, long e);
GF2E power(const GF2E& a, long e);

// x = a^e (e may be negative)



/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(GF2E& x);
GF2E random_GF2E();
// x = random element in GF2E.

/**************************************************************************\

                                  Traces

\**************************************************************************/


void trace(GF2& x, const GF2E& a);  // x = trace of a
GF2 trace(const GF2E& a);



/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, const GF2E& a);

istream& operator>>(istream& s, GF2E& x);
// a GF2X is read and reduced mod p


/**************************************************************************\

                       Modulus Switching 

A class GF2EPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to P, and automatically restore it:

   { 
      GF2EPush push(P); 

      ...

   }

The constructor for push will save the current modulus, and install P as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      GF2EPush push(); // just backup current modulus

        ...

      GF2E::init(P1); // install P1 

        ...

      GF2E::init(P2); // install P2

      // reinstall original modulus as close of scope
   }

      
The GF2EPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see GF2EContext below.  There is also an older GF2EBak class
that may also be useful.

..........................................................................

It is critical that GF2E objects created under one GF2E modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
GF2E modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any GF2E object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.


NOTE: the implementation of Vec<GF2E> is specialized to manage memory more
efficiently than in the default implementation of Vec<T>.  Specifically,
contiguous elements in a Vec<GF2E> are allocated in a contiguous region of
memory.  This reduces the number of calls to the memory allocator, and --- more
significantly --- leads to greater locality of reference.  A consequence of
this implementation is that any calls to SetLength on a Vec<GF2E> object will
need to use information about the current modulus, and so such calls should
only be done "in context".  That said, it is still safe to construct a
Vec<GF2E> using the default or copy contructor, and to assign or append one
Vec<GF2E> to another "out of context".

\**************************************************************************/


// A convenient interface for common cases

class GF2EPush {

public:
GF2EPush();  // backup current modulus
explicit GF2EPush(const GF2X& P);
explicit GF2EPush(const GF2EContext& context);
  // backup current modulus and install the given one

private:
GF2EPush(const GF2EPush&); // disabled
void operator=(const GF2EPush&); // disabled

};



// more general context switching:
// A GF2EContext object has a modulus Q (possibly "null"),

class GF2EContext {


public:

GF2EContext(); // Q = "null"
explicit GF2EContext(const GF2X& P); // Q = P

void save(); // Q = CurrentModulus
void restore() const; // CurrentModulus = Q

GF2EContext(const GF2EContext&);  // copy
GF2EContext& operator=(const GF2EContext&); // assignment
~GF2EContext(); // destructor


};


// An older interface:
// To describe this logic, think of a GF2EBak object
// of having two components: a modulus Q (possibly "null") and 
// an "auto-restore bit" b.


class GF2EBak {
public:


   GF2EBak();  // Q = "null", b = 0

   ~GF2EBak();  // if (b) CurrentModulus = Q

   void save();  // Q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = Q, b = 0


private:
   GF2EBak(const GF2EBak&);  // copy disabled
   void operator=(const GF2EBak&);  // assignment disabled
};






/**************************************************************************\

                               Miscellany

\**************************************************************************/

void clear(GF2E& x); // x = 0
void set(GF2E& x); // x = 1

static const GF2E& GF2E::zero();
// GF2E::zero() yields a read-only reference to zero

static long GF2X::WordLength();
// GF2E::size() returns # of words needed to store a polynomial of
// degree < GF2E::degree()

void swap(GF2E& x, GF2E& y);
// swap x and y (done by "pointer swapping", if possible).

static ZZ& GF2E::cardinality();
// yields the cardinality, i.e., 2^{GF2E::degree()}


GF2E::GF2E(INIT_NO_ALLOC_TYPE);
// special constructor: invoke as GF2E x(INIT_NO_ALLOC);
// initializes x to 0, but allocates no space (this is now the default)

GF2E::GF2E(INIT_ALLOC_TYPE);
// special constructor: invoke as GF2E x(INIT_ALLOC);
// initializes x to 0, but allocates space 

GF2E::allocate();
// useful in conjunction with the INIT_NO_ALLLOC constructor:
// x.allocate() will pre-allocate space for x, using the
// current modulus


ntl-6.2.1/doc/GF2E.txt000644 000765 000024 00000025371 12377144460 014627 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: GF2E SUMMARY: The class GF2E is used to represent polynomials in F_2[X] modulo a polynomial P. The modulus P may be any polynomial with deg(P) > 0, not necessarily irreducible. Objects of the class GF2E are represented as a GF2X of degree < deg(P). An executing program maintains a "current modulus", which is set to P using GF2E::init(P). The current modulus *must* be initialized before any operations on GF2E's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes GF2EPush and GF2EContext below). NOTE: if P is a trinomial X^n + X^k + 1, or a pentanomial X^n + X^k3 + X^k2 + X^k1 + 1, or of the form X^n + g, where g has low degree, then performance will be somewhat improved. Such polynomials are constructed by the routines BuildSparseIrred and BuildIrred in GF2XFactoring. \**************************************************************************/ #include class GF2E { public: GF2E(); // initial value 0 GF2E(const GF2E& a); // copy constructor explicit GF2E(GF2 a); // promotion constructor explicit GF2E(long a); // promotion constructor GF2E& operator=(const GF2E& a); // assignment GF2E& operator=(GF2 a); // assignment GF2E& operator=(long a); // assignment ~GF2E(); // destructor void init(const GF2X& P); // GF2E::init(P) initializes the current modulus to P; // required: deg(P) >= 1. static const GF2XModulus& modulus(); // GF2E::modulus() yields read-only reference to the current modulus static long degree(); // GF2E::degree() returns deg(P) // typedefs to aid generic programming typedef GF2X rep_type; typedef GF2EContext context_type; typedef GF2EBak bak_type; typedef GF2EPush push_type; typedef GF2EX poly_type; }; const GF2X& rep(const GF2E& a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const GF2E& a, const GF2E& b); long operator!=(const GF2E& a, const GF2E& b); long IsZero(const GF2E& a); // test for 0 long IsOne(const GF2E& a); // test for 1 // PROMOTIONS: ==, != promote {long, GF2} to GF2E on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: GF2E operator+(const GF2E& a, const GF2E& b); GF2E operator-(const GF2E& a, const GF2E& b); GF2E operator-(const GF2E& a); GF2E& operator+=(GF2E& x, const GF2E& a); GF2E& operator+=(GF2E& x, GF2 a); GF2E& operator+=(GF2E& x, long a); GF2E& operator++(GF2E& x); // prefix void operator++(GF2E& x, int); // postfix GF2E& operator-=(GF2E& x, const GF2E& a); GF2E& operator-=(GF2E& x, GF2 a); GF2E& operator-=(GF2E& x, long a); GF2E& operator--(GF2E& x); // prefix void operator--(GF2E& x, int); // postfix // procedural versions: void add(GF2E& x, const GF2E& a, const GF2E& b); // x = a + b void sub(GF2E& x, const GF2E& a, const GF2E& b); // x = a - b = a + b void negate(GF2E& x, const GF2E& a); // x = - a = a // PROMOTIONS: +, -, add, sub promote {long, GF2} to GF2E on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: GF2E operator*(const GF2E& a, const GF2E& b); GF2E& operator*=(GF2E& x, const GF2E& a); GF2E& operator*=(GF2E& x, GF2 a); GF2E& operator*=(GF2E& x, long a); // procedural versions: void mul(GF2E& x, const GF2E& a, const GF2E& b); // x = a * b void sqr(GF2E& x, const GF2E& a); // x = a^2 GF2E sqr(const GF2E& a); // PROMOTIONS: *, mul promote {long, GF2} to GF2E on (a, b). /**************************************************************************\ Division \**************************************************************************/ // operator notation: GF2E operator/(const GF2E& a, const GF2E& b); GF2E& operator/=(GF2E& x, const GF2E& a); GF2E& operator/=(GF2E& x, GF2 a); GF2E& operator/=(GF2E& x, long a); // procedural versions: void div(GF2E& x, const GF2E& a, const GF2E& b); // x = a/b. If b is not invertible, an error is raised. void inv(GF2E& x, const GF2E& a); GF2E inv(const GF2E& a); // x = 1/a PROMOTIONS: /, div promote {long, GF2} to GF2E on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(GF2E& x, const GF2E& a, const ZZ& e); GF2E power(const GF2E& a, const ZZ& e); void power(GF2E& x, const GF2E& a, long e); GF2E power(const GF2E& a, long e); // x = a^e (e may be negative) /**************************************************************************\ Random Elements \**************************************************************************/ void random(GF2E& x); GF2E random_GF2E(); // x = random element in GF2E. /**************************************************************************\ Traces \**************************************************************************/ void trace(GF2& x, const GF2E& a); // x = trace of a GF2 trace(const GF2E& a); /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, const GF2E& a); istream& operator>>(istream& s, GF2E& x); // a GF2X is read and reduced mod p /**************************************************************************\ Modulus Switching A class GF2EPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to P, and automatically restore it: { GF2EPush push(P); ... } The constructor for push will save the current modulus, and install P as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { GF2EPush push(); // just backup current modulus ... GF2E::init(P1); // install P1 ... GF2E::init(P2); // install P2 // reinstall original modulus as close of scope } The GF2EPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see GF2EContext below. There is also an older GF2EBak class that may also be useful. .......................................................................... It is critical that GF2E objects created under one GF2E modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) GF2E modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any GF2E object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. NOTE: the implementation of Vec is specialized to manage memory more efficiently than in the default implementation of Vec. Specifically, contiguous elements in a Vec are allocated in a contiguous region of memory. This reduces the number of calls to the memory allocator, and --- more significantly --- leads to greater locality of reference. A consequence of this implementation is that any calls to SetLength on a Vec object will need to use information about the current modulus, and so such calls should only be done "in context". That said, it is still safe to construct a Vec using the default or copy contructor, and to assign or append one Vec to another "out of context". \**************************************************************************/ // A convenient interface for common cases class GF2EPush { public: GF2EPush(); // backup current modulus explicit GF2EPush(const GF2X& P); explicit GF2EPush(const GF2EContext& context); // backup current modulus and install the given one private: GF2EPush(const GF2EPush&); // disabled void operator=(const GF2EPush&); // disabled }; // more general context switching: // A GF2EContext object has a modulus Q (possibly "null"), class GF2EContext { public: GF2EContext(); // Q = "null" explicit GF2EContext(const GF2X& P); // Q = P void save(); // Q = CurrentModulus void restore() const; // CurrentModulus = Q GF2EContext(const GF2EContext&); // copy GF2EContext& operator=(const GF2EContext&); // assignment ~GF2EContext(); // destructor }; // An older interface: // To describe this logic, think of a GF2EBak object // of having two components: a modulus Q (possibly "null") and // an "auto-restore bit" b. class GF2EBak { public: GF2EBak(); // Q = "null", b = 0 ~GF2EBak(); // if (b) CurrentModulus = Q void save(); // Q = CurrentModulus, b = 1 void restore(); // CurrentModulus = Q, b = 0 private: GF2EBak(const GF2EBak&); // copy disabled void operator=(const GF2EBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(GF2E& x); // x = 0 void set(GF2E& x); // x = 1 static const GF2E& GF2E::zero(); // GF2E::zero() yields a read-only reference to zero static long GF2X::WordLength(); // GF2E::size() returns # of words needed to store a polynomial of // degree < GF2E::degree() void swap(GF2E& x, GF2E& y); // swap x and y (done by "pointer swapping", if possible). static ZZ& GF2E::cardinality(); // yields the cardinality, i.e., 2^{GF2E::degree()} GF2E::GF2E(INIT_NO_ALLOC_TYPE); // special constructor: invoke as GF2E x(INIT_NO_ALLOC); // initializes x to 0, but allocates no space (this is now the default) GF2E::GF2E(INIT_ALLOC_TYPE); // special constructor: invoke as GF2E x(INIT_ALLOC); // initializes x to 0, but allocates space GF2E::allocate(); // useful in conjunction with the INIT_NO_ALLLOC constructor: // x.allocate() will pre-allocate space for x, using the // current modulus ntl-6.2.1/doc/GF2EX.cpp.html000644 000765 000024 00000154603 12377144460 015666 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/GF2EX.cpp.html

/**************************************************************************\

MODULE: GF2EX

SUMMARY:

The class GF2EX represents polynomials over GF2E,
and so can be used, for example, for arithmentic in GF(2^n)[X].
However, except where mathematically necessary (e.g., GCD computations),
GF2E need not be a field.

\**************************************************************************/

#include <NTL/GF2E.h>
#include <NTL/vec_GF2E.h>

class GF2EX {
public:

   GF2EX(); // initial value 0

   GF2EX(const GF2EX& a); // copy
   explicit GF2EX(const GF2E& a);  // promotion
   explicit GF2EX(GF2 a);
   explicit GF2EX(long a);

   GF2EX& operator=(const GF2EX& a); // assignment
   GF2EX& operator=(const GF2E& a);
   GF2EX& operator=(GF2 a);
   GF2EX& operator=(long a);

   ~GF2EX(); // destructor

   GF2EX(INIT_MONO_TYPE, long i, const GF2E& c);
   GF2EX(INIT_MONO_TYPE, long i, GF2 c);
   GF2EX(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as GF2EX(INIT_MONO, i)

   GF2EX(INIT_MONO_TYPE, long i);
   // initialize to X^i, invoke as GF2EX(INIT_MONO, i)




   // typedefs to aid in generic programming

   typedef GF2E coeff_type;
   typedef GF2EXModulus modulus_type;
   // ...

};





/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const GF2EX& a);  // return deg(a); deg(0) == -1.

const GF2E& coeff(const GF2EX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const GF2E& LeadCoeff(const GF2EX& a);
// returns leading term of a, or zero if a == 0

const GF2E& ConstTerm(const GF2EX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(GF2EX& x, long i, const GF2E& a);
void SetCoeff(GF2EX& x, long i, GF2 a);
void SetCoeff(GF2EX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(GF2EX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(GF2EX& x); // x is set to the monomial X

long IsX(const GF2EX& a); // test if x = X




GF2E& GF2EX::operator[](long i);
const GF2E& GF2EX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void GF2EX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void GF2EX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void GF2EX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.






/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const GF2EX& a, const GF2EX& b);
long operator!=(const GF2EX& a, const GF2EX& b);

long IsZero(const GF2EX& a); // test for 0
long IsOne(const GF2EX& a); // test for 1

// PROMOTIONS: ==, != promote {long,GF2,GF2E} to GF2EX on (a, b).

/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

GF2EX operator+(const GF2EX& a, const GF2EX& b);
GF2EX operator-(const GF2EX& a, const GF2EX& b);
GF2EX operator-(const GF2EX& a);

GF2EX& operator+=(GF2EX& x, const GF2EX& a);
GF2EX& operator+=(GF2EX& x, const GF2E& a);
GF2EX& operator+=(GF2EX& x, GF2 a);
GF2EX& operator+=(GF2EX& x, long a);


GF2EX& operator++(GF2EX& x);  // prefix
void operator++(GF2EX& x, int);  // postfix

GF2EX& operator-=(GF2EX& x, const GF2EX& a);
GF2EX& operator-=(GF2EX& x, const GF2E& a);
GF2EX& operator-=(GF2EX& x, GF2 a);
GF2EX& operator-=(GF2EX& x, long a);

GF2EX& operator--(GF2EX& x);  // prefix
void operator--(GF2EX& x, int);  // postfix

// procedural versions:

void add(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a + b
void sub(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a - b 
void negate(GF2EX& x, const GF2EX& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long,GF2,GF2E} to GF2EX on (a, b).



/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

GF2EX operator*(const GF2EX& a, const GF2EX& b);

GF2EX& operator*=(GF2EX& x, const GF2EX& a);
GF2EX& operator*=(GF2EX& x, const GF2E& a);
GF2EX& operator*=(GF2EX& x, GF2 a);
GF2EX& operator*=(GF2EX& x, long a);


// procedural versions:


void mul(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a * b

void sqr(GF2EX& x, const GF2EX& a); // x = a^2
GF2EX sqr(const GF2EX& a);

// PROMOTIONS: *, mul promote {long,GF2,GF2E} to GF2EX on (a, b).

void power(GF2EX& x, const GF2EX& a, long e);  // x = a^e (e >= 0)
GF2EX power(const GF2EX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

GF2EX operator<<(const GF2EX& a, long n);
GF2EX operator>>(const GF2EX& a, long n);

GF2EX& operator<<=(GF2EX& x, long n);
GF2EX& operator>>=(GF2EX& x, long n);

// procedural versions:

void LeftShift(GF2EX& x, const GF2EX& a, long n);
GF2EX LeftShift(const GF2EX& a, long n);

void RightShift(GF2EX& x, const GF2EX& a, long n);
GF2EX RightShift(const GF2EX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

GF2EX operator/(const GF2EX& a, const GF2EX& b);
GF2EX operator/(const GF2EX& a, const GF2E& b);
GF2EX operator/(const GF2EX& a, GF2 b);
GF2EX operator/(const GF2EX& a, long b);

GF2EX operator%(const GF2EX& a, const GF2EX& b);

GF2EX& operator/=(GF2EX& x, const GF2EX& a);
GF2EX& operator/=(GF2EX& x, const GF2E& a);
GF2EX& operator/=(GF2EX& x, GF2 a);
GF2EX& operator/=(GF2EX& x, long a);

GF2EX& operator%=(GF2EX& x, const GF2EX& a);

// procedural versions:


void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b);
// q = a/b, r = a%b

void div(GF2EX& q, const GF2EX& a, const GF2EX& b);
void div(GF2EX& q, const GF2EX& a, const GF2E& b);
void div(GF2EX& q, const GF2EX& a, GF2 b);
void div(GF2EX& q, const GF2EX& a, long b);
// q = a/b

void rem(GF2EX& r, const GF2EX& a, const GF2EX& b);
// r = a%b

long divide(GF2EX& q, const GF2EX& a, const GF2EX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const GF2EX& a, const GF2EX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


/**************************************************************************\

                                   GCD's

These routines are intended for use when GF2E is a field.

\**************************************************************************/


void GCD(GF2EX& x, const GF2EX& a, const GF2EX& b);
GF2EX GCD(const GF2EX& a, const GF2EX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(GF2EX& d, GF2EX& s, GF2EX& t, const GF2EX& a, const GF2EX& b);
// d = gcd(a,b), a s + b t = d 


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be polynomials of degree < GF2E::degree() and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary polynomials which are reduced modulo GF2E::modulus(), and leading
zeros stripped.

\**************************************************************************/

istream& operator>>(istream& s, GF2EX& x);
ostream& operator<<(ostream& s, const GF2EX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(GF2EX& x, const GF2EX& a); // x = derivative of a
GF2EX diff(const GF2EX& a);

void MakeMonic(GF2EX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case

void reverse(GF2EX& x, const GF2EX& a, long hi);
GF2EX reverse(const GF2EX& a, long hi);

void reverse(GF2EX& x, const GF2EX& a);
GF2EX reverse(const GF2EX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_GF2E& x, const GF2EX& a, long n);
vec_GF2E VectorCopy(const GF2EX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(GF2EX& x, long n);
GF2EX random_GF2EX(long n);
// x = random polynomial of degree < n 


/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(GF2EX& x, const vec_GF2E& a);
GF2EX BuildFromRoots(const vec_GF2E& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length()

void eval(GF2E& b, const GF2EX& f, const GF2E& a);
GF2E eval(const GF2EX& f, const GF2E& a);
// b = f(a)

void eval(GF2E& b, const GF2X& f, const GF2E& a);
GF2E eval(const GF2EX& f, const GF2E& a);
// b = f(a); uses ModComp algorithm for GF2X

void eval(vec_GF2E& b, const GF2EX& f, const vec_GF2E& a);
vec_GF2E eval(const GF2EX& f, const vec_GF2E& a);
//  b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(GF2EX& f, const vec_GF2E& a, const vec_GF2E& b);
GF2EX interpolate(const vec_GF2E& a, const vec_GF2E& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  

/**************************************************************************\

                       Arithmetic mod X^n

Required: n >= 0; otherwise, an error is raised.

\**************************************************************************/

void trunc(GF2EX& x, const GF2EX& a, long n); // x = a % X^n
GF2EX trunc(const GF2EX& a, long n);

void MulTrunc(GF2EX& x, const GF2EX& a, const GF2EX& b, long n);
GF2EX MulTrunc(const GF2EX& a, const GF2EX& b, long n);
// x = a * b % X^n

void SqrTrunc(GF2EX& x, const GF2EX& a, long n);
GF2EX SqrTrunc(const GF2EX& a, long n);
// x = a^2 % X^n

void InvTrunc(GF2EX& x, const GF2EX& a, long n);
GF2EX InvTrunc(GF2EX& x, const GF2EX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.


NOTE: if you want to do many computations with a fixed f, use the
GF2EXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EX& f);
GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EX& f);
// x = (a * b) % f

void SqrMod(GF2EX& x, const GF2EX& a, const GF2EX& f);
GF2EX SqrMod(const GF2EX& a, const GF2EX& f);
// x = a^2 % f

void MulByXMod(GF2EX& x, const GF2EX& a, const GF2EX& f);
GF2EX MulByXMod(const GF2EX& a, const GF2EX& f);
// x = (a * X) mod f

void InvMod(GF2EX& x, const GF2EX& a, const GF2EX& f);
GF2EX InvMod(const GF2EX& a, const GF2EX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(GF2EX& x, const GF2EX& a, const GF2EX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
GF2EXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

As an example, the following routine the product modulo f of a vector
of polynomials.

#include <NTL/GF2EX.h>

void product(GF2EX& x, const vec_GF2EX& v, const GF2EX& f)
{
   GF2EXModulus F(f);
   GF2EX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}

NOTE: A GF2EX may be used wherever a GF2EXModulus is required,
and a GF2EXModulus may be used wherever a GF2EX is required.


\**************************************************************************/

class GF2EXModulus {
public:
   GF2EXModulus(); // initially in an unusable state

   GF2EXModulus(const GF2EX& f); // initialize with f, deg(f) > 0

   GF2EXModulus(const GF2EXModulus&); // copy

   GF2EXModulus& operator=(const GF2EXModulus&); // assignment

   ~GF2EXModulus(); // destructor

   operator const GF2EX& () const; // implicit read-only access to f

   const GF2EX& val() const; // explicit read-only access to f
};

void build(GF2EXModulus& F, const GF2EX& f);
// pre-computes information about f and stores it in F.  Must have
// deg(f) > 0.  Note that the declaration GF2EXModulus F(f) is
// equivalent to GF2EXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).


long deg(const GF2EXModulus& F);  // return n=deg(f)

void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F);
GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(GF2EX& x, const GF2EX& a, const GF2EXModulus& F);
GF2EX SqrMod(const GF2EX& a, const GF2EXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(GF2EX& x, const GF2EX& a, const ZZ& e, const GF2EXModulus& F);
GF2EX PowerMod(const GF2EX& a, const ZZ& e, const GF2EXModulus& F);

void PowerMod(GF2EX& x, const GF2EX& a, long e, const GF2EXModulus& F);
GF2EX PowerMod(const GF2EX& a, long e, const GF2EXModulus& F);

// x = a^e % f; e >= 0, deg(a) < n.  Uses a sliding window algorithm.
// (e may be negative)

void PowerXMod(GF2EX& x, const ZZ& e, const GF2EXModulus& F);
GF2EX PowerXMod(const ZZ& e, const GF2EXModulus& F);

void PowerXMod(GF2EX& x, long e, const GF2EXModulus& F);
GF2EX PowerXMod(long e, const GF2EXModulus& F);

// x = X^e % f (e may be negative)

void rem(GF2EX& x, const GF2EX& a, const GF2EXModulus& F);
// x = a % f

void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F);
// q = a/f, r = a%f

void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F);
// q = a/f

// operator notation:

GF2EX operator/(const GF2EX& a, const GF2EXModulus& F);
GF2EX operator%(const GF2EX& a, const GF2EXModulus& F);

GF2EX& operator/=(GF2EX& x, const GF2EXModulus& F);
GF2EX& operator%=(GF2EX& x, const GF2EXModulus& F);



/**************************************************************************\

                             vectors of GF2EX's

\**************************************************************************/

typedef Vec<GF2EX> vec_GF2EX; // backward compatibility



/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.


\**************************************************************************/

void CompMod(GF2EX& x, const GF2EX& g, const GF2EX& h, const GF2EXModulus& F);
GF2EX CompMod(const GF2EX& g, const GF2EX& h,
                    const GF2EXModulus& F);

// x = g(h) mod f; deg(h) < n

void Comp2Mod(GF2EX& x1, GF2EX& x2, const GF2EX& g1, const GF2EX& g2,
              const GF2EX& h, const GF2EXModulus& F);
// xi = gi(h) mod f (i=1,2); deg(h) < n.


void Comp3Mod(GF2EX& x1, GF2EX& x2, GF2EX& x3,
              const GF2EX& g1, const GF2EX& g2, const GF2EX& g3,
              const GF2EX& h, const GF2EXModulus& F);
// xi = gi(h) mod f (i=1..3); deg(h) < n.



/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a GF2EXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct GF2EXArgument {
   vec_GF2EX H;
};

void build(GF2EXArgument& H, const GF2EX& h, const GF2EXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n.

void CompMod(GF2EX& x, const GF2EX& g, const GF2EXArgument& H,
             const GF2EXModulus& F);

GF2EX CompMod(const GF2EX& g, const GF2EXArgument& H,
                    const GF2EXModulus& F);

extern long GF2EXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// GF2EXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in GF2EXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(GF2E& x, const GF2EVector& a, const GF2EX& b);
GF2E project(const GF2EVector& a, const GF2EX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k,
                   const GF2EX& h, const GF2EXModulus& F);

vec_GF2E ProjectPowers(const vec_GF2E& a, long k,
                   const GF2EX& h, const GF2EXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.

void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k,
                   const GF2EXArgument& H, const GF2EXModulus& F);

vec_GF2E ProjectPowers(const vec_GF2E& a, long k,
                   const GF2EXArgument& H, const GF2EXModulus& F);

// same as above, but uses a pre-computed GF2EXArgument

class GF2EXTransMultiplier { /* ... */ };

void build(GF2EXTransMultiplier& B, const GF2EX& b, const GF2EXModulus& F);



void UpdateMap(vec_GF2E& x, const vec_GF2E& a,
               const GF2EXMultiplier& B, const GF2EXModulus& F);

vec_GF2E UpdateMap(const vec_GF2E& a,
               const GF2EXMultiplier& B, const GF2EXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Restriction: a.length() <= deg(F), deg(b) < deg(F).
// This is "transposed" MulMod by B.
// Input may have "high order" zeroes stripped.
// Output always has high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

These routines should be used only when GF2E is a field.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(GF2EX& h, const vec_GF2E& a, long m);
GF2EX MinPolySeq(const vec_GF2E& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m


void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m);
GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m);

void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F);
GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/2^{GF2E::degree()}.

void MinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m);
GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m);

void MinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F);
GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m);
GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F, long m);

void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F);
GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).


/**************************************************************************\

           Composition and Minimal Polynomials in towers

These are implementations of algorithms that will be described
and analyzed in a forthcoming paper.

GF2E need not be a field.

\**************************************************************************/


void CompTower(GF2EX& x, const GF2X& g, const GF2EXArgument& h,
             const GF2EXModulus& F);

GF2EX CompTower(const GF2X& g, const GF2EXArgument& h,
             const GF2EXModulus& F);

void CompTower(GF2EX& x, const GF2X& g, const GF2EX& h,
             const GF2EXModulus& F);

GF2EX CompTower(const GF2X& g, const GF2EX& h,
             const GF2EXModulus& F);


// x = g(h) mod f


void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F,
                      long m);

GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m);

void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F);

GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F);

// Uses a probabilistic algorithm to compute the minimal
// polynomial of (g mod f) over GF2.
// The parameter m is a bound on the degree of the minimal polynomial
// (default = deg(f)*GF2E::degree()).
// In general, the result will be a divisor of the true minimimal
// polynomial.  For correct results, use the MinPoly routines below.



void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m);

GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m);

void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F);

GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F);

// Same as above, but result is always correct.


void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m);

GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F, long m);

void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F);

GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F);

// Same as above, but assumes the minimal polynomial is
// irreducible, and uses a slightly faster, deterministic algorithm.



/**************************************************************************\

                   Traces, norms, resultants

\**************************************************************************/


void TraceMod(GF2E& x, const GF2EX& a, const GF2EXModulus& F);
GF2E TraceMod(const GF2EX& a, const GF2EXModulus& F);

void TraceMod(GF2E& x, const GF2EX& a, const GF2EX& f);
GF2E TraceMod(const GF2EX& a, const GF2EXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_GF2E& S, const GF2EX& f);
vec_GF2E TraceVec(const GF2EX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above trace routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(GF2E& x, const GF2EX& a, const GF2EX& f);
GF2E NormMod(const GF2EX& a, const GF2EX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)

void resultant(GF2E& x, const GF2EX& a, const GF2EX& b);
GF2E resultant(const GF2EX& a, const GF2EX& b);
// x = resultant(a, b)

// NormMod and resultant require that GF2E is a field.



/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(GF2EX& x) // x = 0
void set(GF2EX& x); // x = 1


void GF2EX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

GF2EX::GF2EX(INIT_SIZE_TYPE, long n);
// GF2EX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const GF2EX& zero();
// GF2EX::zero() is a read-only reference to 0

void swap(GF2EX& x, GF2EX& y);
// swap x and y (via "pointer swapping")

GF2EX::GF2EX(long i, const GF2E& c);
GF2EX::GF2EX(long i, GF2 c);
GF2EX::GF2EX(long i, long c);
// initialize to X^i*c, provided for backward compatibility

ntl-6.2.1/doc/GF2EX.txt000644 000765 000024 00000065424 12377144460 014762 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: GF2EX SUMMARY: The class GF2EX represents polynomials over GF2E, and so can be used, for example, for arithmentic in GF(2^n)[X]. However, except where mathematically necessary (e.g., GCD computations), GF2E need not be a field. \**************************************************************************/ #include #include class GF2EX { public: GF2EX(); // initial value 0 GF2EX(const GF2EX& a); // copy explicit GF2EX(const GF2E& a); // promotion explicit GF2EX(GF2 a); explicit GF2EX(long a); GF2EX& operator=(const GF2EX& a); // assignment GF2EX& operator=(const GF2E& a); GF2EX& operator=(GF2 a); GF2EX& operator=(long a); ~GF2EX(); // destructor GF2EX(INIT_MONO_TYPE, long i, const GF2E& c); GF2EX(INIT_MONO_TYPE, long i, GF2 c); GF2EX(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as GF2EX(INIT_MONO, i) GF2EX(INIT_MONO_TYPE, long i); // initialize to X^i, invoke as GF2EX(INIT_MONO, i) // typedefs to aid in generic programming typedef GF2E coeff_type; typedef GF2EXModulus modulus_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const GF2EX& a); // return deg(a); deg(0) == -1. const GF2E& coeff(const GF2EX& a, long i); // returns the coefficient of X^i, or zero if i not in range const GF2E& LeadCoeff(const GF2EX& a); // returns leading term of a, or zero if a == 0 const GF2E& ConstTerm(const GF2EX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(GF2EX& x, long i, const GF2E& a); void SetCoeff(GF2EX& x, long i, GF2 a); void SetCoeff(GF2EX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(GF2EX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(GF2EX& x); // x is set to the monomial X long IsX(const GF2EX& a); // test if x = X GF2E& GF2EX::operator[](long i); const GF2E& GF2EX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void GF2EX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void GF2EX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void GF2EX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const GF2EX& a, const GF2EX& b); long operator!=(const GF2EX& a, const GF2EX& b); long IsZero(const GF2EX& a); // test for 0 long IsOne(const GF2EX& a); // test for 1 // PROMOTIONS: ==, != promote {long,GF2,GF2E} to GF2EX on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: GF2EX operator+(const GF2EX& a, const GF2EX& b); GF2EX operator-(const GF2EX& a, const GF2EX& b); GF2EX operator-(const GF2EX& a); GF2EX& operator+=(GF2EX& x, const GF2EX& a); GF2EX& operator+=(GF2EX& x, const GF2E& a); GF2EX& operator+=(GF2EX& x, GF2 a); GF2EX& operator+=(GF2EX& x, long a); GF2EX& operator++(GF2EX& x); // prefix void operator++(GF2EX& x, int); // postfix GF2EX& operator-=(GF2EX& x, const GF2EX& a); GF2EX& operator-=(GF2EX& x, const GF2E& a); GF2EX& operator-=(GF2EX& x, GF2 a); GF2EX& operator-=(GF2EX& x, long a); GF2EX& operator--(GF2EX& x); // prefix void operator--(GF2EX& x, int); // postfix // procedural versions: void add(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a + b void sub(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a - b void negate(GF2EX& x, const GF2EX& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long,GF2,GF2E} to GF2EX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: GF2EX operator*(const GF2EX& a, const GF2EX& b); GF2EX& operator*=(GF2EX& x, const GF2EX& a); GF2EX& operator*=(GF2EX& x, const GF2E& a); GF2EX& operator*=(GF2EX& x, GF2 a); GF2EX& operator*=(GF2EX& x, long a); // procedural versions: void mul(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a * b void sqr(GF2EX& x, const GF2EX& a); // x = a^2 GF2EX sqr(const GF2EX& a); // PROMOTIONS: *, mul promote {long,GF2,GF2E} to GF2EX on (a, b). void power(GF2EX& x, const GF2EX& a, long e); // x = a^e (e >= 0) GF2EX power(const GF2EX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: GF2EX operator<<(const GF2EX& a, long n); GF2EX operator>>(const GF2EX& a, long n); GF2EX& operator<<=(GF2EX& x, long n); GF2EX& operator>>=(GF2EX& x, long n); // procedural versions: void LeftShift(GF2EX& x, const GF2EX& a, long n); GF2EX LeftShift(const GF2EX& a, long n); void RightShift(GF2EX& x, const GF2EX& a, long n); GF2EX RightShift(const GF2EX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: GF2EX operator/(const GF2EX& a, const GF2EX& b); GF2EX operator/(const GF2EX& a, const GF2E& b); GF2EX operator/(const GF2EX& a, GF2 b); GF2EX operator/(const GF2EX& a, long b); GF2EX operator%(const GF2EX& a, const GF2EX& b); GF2EX& operator/=(GF2EX& x, const GF2EX& a); GF2EX& operator/=(GF2EX& x, const GF2E& a); GF2EX& operator/=(GF2EX& x, GF2 a); GF2EX& operator/=(GF2EX& x, long a); GF2EX& operator%=(GF2EX& x, const GF2EX& a); // procedural versions: void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b); // q = a/b, r = a%b void div(GF2EX& q, const GF2EX& a, const GF2EX& b); void div(GF2EX& q, const GF2EX& a, const GF2E& b); void div(GF2EX& q, const GF2EX& a, GF2 b); void div(GF2EX& q, const GF2EX& a, long b); // q = a/b void rem(GF2EX& r, const GF2EX& a, const GF2EX& b); // r = a%b long divide(GF2EX& q, const GF2EX& a, const GF2EX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const GF2EX& a, const GF2EX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 /**************************************************************************\ GCD's These routines are intended for use when GF2E is a field. \**************************************************************************/ void GCD(GF2EX& x, const GF2EX& a, const GF2EX& b); GF2EX GCD(const GF2EX& a, const GF2EX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(GF2EX& d, GF2EX& s, GF2EX& t, const GF2EX& a, const GF2EX& b); // d = gcd(a,b), a s + b t = d /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be polynomials of degree < GF2E::degree() and a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary polynomials which are reduced modulo GF2E::modulus(), and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, GF2EX& x); ostream& operator<<(ostream& s, const GF2EX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(GF2EX& x, const GF2EX& a); // x = derivative of a GF2EX diff(const GF2EX& a); void MakeMonic(GF2EX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case void reverse(GF2EX& x, const GF2EX& a, long hi); GF2EX reverse(const GF2EX& a, long hi); void reverse(GF2EX& x, const GF2EX& a); GF2EX reverse(const GF2EX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_GF2E& x, const GF2EX& a, long n); vec_GF2E VectorCopy(const GF2EX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(GF2EX& x, long n); GF2EX random_GF2EX(long n); // x = random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(GF2EX& x, const vec_GF2E& a); GF2EX BuildFromRoots(const vec_GF2E& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(GF2E& b, const GF2EX& f, const GF2E& a); GF2E eval(const GF2EX& f, const GF2E& a); // b = f(a) void eval(GF2E& b, const GF2X& f, const GF2E& a); GF2E eval(const GF2EX& f, const GF2E& a); // b = f(a); uses ModComp algorithm for GF2X void eval(vec_GF2E& b, const GF2EX& f, const vec_GF2E& a); vec_GF2E eval(const GF2EX& f, const vec_GF2E& a); // b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(GF2EX& f, const vec_GF2E& a, const vec_GF2E& b); GF2EX interpolate(const vec_GF2E& a, const vec_GF2E& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. /**************************************************************************\ Arithmetic mod X^n Required: n >= 0; otherwise, an error is raised. \**************************************************************************/ void trunc(GF2EX& x, const GF2EX& a, long n); // x = a % X^n GF2EX trunc(const GF2EX& a, long n); void MulTrunc(GF2EX& x, const GF2EX& a, const GF2EX& b, long n); GF2EX MulTrunc(const GF2EX& a, const GF2EX& b, long n); // x = a * b % X^n void SqrTrunc(GF2EX& x, const GF2EX& a, long n); GF2EX SqrTrunc(const GF2EX& a, long n); // x = a^2 % X^n void InvTrunc(GF2EX& x, const GF2EX& a, long n); GF2EX InvTrunc(GF2EX& x, const GF2EX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the GF2EXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EX& f); GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EX& f); // x = (a * b) % f void SqrMod(GF2EX& x, const GF2EX& a, const GF2EX& f); GF2EX SqrMod(const GF2EX& a, const GF2EX& f); // x = a^2 % f void MulByXMod(GF2EX& x, const GF2EX& a, const GF2EX& f); GF2EX MulByXMod(const GF2EX& a, const GF2EX& f); // x = (a * X) mod f void InvMod(GF2EX& x, const GF2EX& a, const GF2EX& f); GF2EX InvMod(const GF2EX& a, const GF2EX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(GF2EX& x, const GF2EX& a, const GF2EX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build GF2EXModulus F for f. This pre-computes information about f that speeds up subsequent computations. As an example, the following routine the product modulo f of a vector of polynomials. #include void product(GF2EX& x, const vec_GF2EX& v, const GF2EX& f) { GF2EXModulus F(f); GF2EX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } NOTE: A GF2EX may be used wherever a GF2EXModulus is required, and a GF2EXModulus may be used wherever a GF2EX is required. \**************************************************************************/ class GF2EXModulus { public: GF2EXModulus(); // initially in an unusable state GF2EXModulus(const GF2EX& f); // initialize with f, deg(f) > 0 GF2EXModulus(const GF2EXModulus&); // copy GF2EXModulus& operator=(const GF2EXModulus&); // assignment ~GF2EXModulus(); // destructor operator const GF2EX& () const; // implicit read-only access to f const GF2EX& val() const; // explicit read-only access to f }; void build(GF2EXModulus& F, const GF2EX& f); // pre-computes information about f and stores it in F. Must have // deg(f) > 0. Note that the declaration GF2EXModulus F(f) is // equivalent to GF2EXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const GF2EXModulus& F); // return n=deg(f) void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F); GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(GF2EX& x, const GF2EX& a, const GF2EXModulus& F); GF2EX SqrMod(const GF2EX& a, const GF2EXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(GF2EX& x, const GF2EX& a, const ZZ& e, const GF2EXModulus& F); GF2EX PowerMod(const GF2EX& a, const ZZ& e, const GF2EXModulus& F); void PowerMod(GF2EX& x, const GF2EX& a, long e, const GF2EXModulus& F); GF2EX PowerMod(const GF2EX& a, long e, const GF2EXModulus& F); // x = a^e % f; e >= 0, deg(a) < n. Uses a sliding window algorithm. // (e may be negative) void PowerXMod(GF2EX& x, const ZZ& e, const GF2EXModulus& F); GF2EX PowerXMod(const ZZ& e, const GF2EXModulus& F); void PowerXMod(GF2EX& x, long e, const GF2EXModulus& F); GF2EX PowerXMod(long e, const GF2EXModulus& F); // x = X^e % f (e may be negative) void rem(GF2EX& x, const GF2EX& a, const GF2EXModulus& F); // x = a % f void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F); // q = a/f, r = a%f void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F); // q = a/f // operator notation: GF2EX operator/(const GF2EX& a, const GF2EXModulus& F); GF2EX operator%(const GF2EX& a, const GF2EXModulus& F); GF2EX& operator/=(GF2EX& x, const GF2EXModulus& F); GF2EX& operator%=(GF2EX& x, const GF2EXModulus& F); /**************************************************************************\ vectors of GF2EX's \**************************************************************************/ typedef Vec vec_GF2EX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(GF2EX& x, const GF2EX& g, const GF2EX& h, const GF2EXModulus& F); GF2EX CompMod(const GF2EX& g, const GF2EX& h, const GF2EXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(GF2EX& x1, GF2EX& x2, const GF2EX& g1, const GF2EX& g2, const GF2EX& h, const GF2EXModulus& F); // xi = gi(h) mod f (i=1,2); deg(h) < n. void Comp3Mod(GF2EX& x1, GF2EX& x2, GF2EX& x3, const GF2EX& g1, const GF2EX& g2, const GF2EX& g3, const GF2EX& h, const GF2EXModulus& F); // xi = gi(h) mod f (i=1..3); deg(h) < n. /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a GF2EXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct GF2EXArgument { vec_GF2EX H; }; void build(GF2EXArgument& H, const GF2EX& h, const GF2EXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n. void CompMod(GF2EX& x, const GF2EX& g, const GF2EXArgument& H, const GF2EXModulus& F); GF2EX CompMod(const GF2EX& g, const GF2EXArgument& H, const GF2EXModulus& F); extern long GF2EXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // GF2EXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in GF2EXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(GF2E& x, const GF2EVector& a, const GF2EX& b); GF2E project(const GF2EVector& a, const GF2EX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F); vec_GF2E ProjectPowers(const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F); vec_GF2E ProjectPowers(const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F); // same as above, but uses a pre-computed GF2EXArgument class GF2EXTransMultiplier { /* ... */ }; void build(GF2EXTransMultiplier& B, const GF2EX& b, const GF2EXModulus& F); void UpdateMap(vec_GF2E& x, const vec_GF2E& a, const GF2EXMultiplier& B, const GF2EXModulus& F); vec_GF2E UpdateMap(const vec_GF2E& a, const GF2EXMultiplier& B, const GF2EXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Restriction: a.length() <= deg(F), deg(b) < deg(F). // This is "transposed" MulMod by B. // Input may have "high order" zeroes stripped. // Output always has high order zeroes stripped. /**************************************************************************\ Minimum Polynomials These routines should be used only when GF2E is a field. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(GF2EX& h, const vec_GF2E& a, long m); GF2EX MinPolySeq(const vec_GF2E& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m); void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F); GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/2^{GF2E::degree()}. void MinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m); void MinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F); GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F, long m); void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F); GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Composition and Minimal Polynomials in towers These are implementations of algorithms that will be described and analyzed in a forthcoming paper. GF2E need not be a field. \**************************************************************************/ void CompTower(GF2EX& x, const GF2X& g, const GF2EXArgument& h, const GF2EXModulus& F); GF2EX CompTower(const GF2X& g, const GF2EXArgument& h, const GF2EXModulus& F); void CompTower(GF2EX& x, const GF2X& g, const GF2EX& h, const GF2EXModulus& F); GF2EX CompTower(const GF2X& g, const GF2EX& h, const GF2EXModulus& F); // x = g(h) mod f void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m); void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F); GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F); // Uses a probabilistic algorithm to compute the minimal // polynomial of (g mod f) over GF2. // The parameter m is a bound on the degree of the minimal polynomial // (default = deg(f)*GF2E::degree()). // In general, the result will be a divisor of the true minimimal // polynomial. For correct results, use the MinPoly routines below. void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m); void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F); GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F); // Same as above, but result is always correct. void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F, long m); void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F); GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F); // Same as above, but assumes the minimal polynomial is // irreducible, and uses a slightly faster, deterministic algorithm. /**************************************************************************\ Traces, norms, resultants \**************************************************************************/ void TraceMod(GF2E& x, const GF2EX& a, const GF2EXModulus& F); GF2E TraceMod(const GF2EX& a, const GF2EXModulus& F); void TraceMod(GF2E& x, const GF2EX& a, const GF2EX& f); GF2E TraceMod(const GF2EX& a, const GF2EXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_GF2E& S, const GF2EX& f); vec_GF2E TraceVec(const GF2EX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above trace routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(GF2E& x, const GF2EX& a, const GF2EX& f); GF2E NormMod(const GF2EX& a, const GF2EX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(GF2E& x, const GF2EX& a, const GF2EX& b); GF2E resultant(const GF2EX& a, const GF2EX& b); // x = resultant(a, b) // NormMod and resultant require that GF2E is a field. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(GF2EX& x) // x = 0 void set(GF2EX& x); // x = 1 void GF2EX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). GF2EX::GF2EX(INIT_SIZE_TYPE, long n); // GF2EX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const GF2EX& zero(); // GF2EX::zero() is a read-only reference to 0 void swap(GF2EX& x, GF2EX& y); // swap x and y (via "pointer swapping") GF2EX::GF2EX(long i, const GF2E& c); GF2EX::GF2EX(long i, GF2 c); GF2EX::GF2EX(long i, long c); // initialize to X^i*c, provided for backward compatibility ntl-6.2.1/doc/GF2EXFactoring.cpp.html000644 000765 000024 00000035704 12377144460 017523 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/GF2EXFactoring.cpp.html

/**************************************************************************\

MODULE: GF2EXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over GF2E, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/GF2EX.h>
#include <NTL/pair_GF2EX_long.h>

void SquareFreeDecomp(vec_pair_GF2EX_long& u, const GF2EX& f);
vec_pair_GF2EX_long SquareFreeDecomp(const GF2EX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a list of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_GF2E& x, const GF2EX& f);
vec_GF2E FindRoots(const GF2EX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(GF2E& root, const GF2EX& f);
GF2E FindRoot(const GF2EX& f);


// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void SFBerlekamp(vec_GF2EX& factors, const GF2EX& f, long verbose=0);
vec_GF2EX  SFBerlekamp(const GF2EX& f, long verbose=0);

// Assumes f is square-free and monic.  returns list of factors of f.
// Uses "Berlekamp" approach, as described in detail in [Shoup,
// J. Symbolic Comp. 20:363-397, 1995].


void berlekamp(vec_pair_GF2EX_long& factors, const GF2EX& f,
               long verbose=0);

vec_pair_GF2EX_long berlekamp(const GF2EX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SFBerlekamp.



void NewDDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h,
         long verbose=0);

vec_pair_GF2EX_long NewDDF(const GF2EX& f, const GF2EX& h,
         long verbose=0);


// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^{2^{GF2E::degree()}} mod f,
// which can be computed efficiently using the function FrobeniusMap 
// (see below).
// This routine  implements the baby step/giant step algorithm 
// of [Kaltofen and Shoup, STOC 1995], 
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

// NOTE: When factoring "large" polynomials,
// this routine uses external files to store some intermediate
// results, which are removed if the routine terminates normally.
// These files are stored in the current directory under names of the
// form ddf-*-baby-* and ddf-*-giant-*.
// The definition of "large" is controlled by the variable

      extern double GF2EXFileThresh

// which can be set by the user.  If the sizes of the tables
// exceeds GF2EXFileThresh KB, external files are used.
// Initial value is NTL_FILE_THRESH (defined in tools.h).



void EDF(vec_GF2EX& factors, const GF2EX& f, const GF2EX& h,
         long d, long verbose=0);

vec_GF2EX EDF(const GF2EX& f, const GF2EX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  
// h = X^{2^{GF2E::degree()}} mod f,
// which can be computed efficiently using the function FrobeniusMap 
// (see below).
// d = degree of irreducible factors of f.  
// This routine implements the algorithm of [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void RootEDF(vec_GF2EX& factors, const GF2EX& f, long verbose=0);
vec_GF2EX RootEDF(const GF2EX& f, long verbose=0);

// EDF for d==1


void SFCanZass(vec_GF2EX& factors, const GF2EX& f, long verbose=0);
vec_GF2EX SFCanZass(const GF2EX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_GF2EX_long& factors, const GF2EX& f,
             long verbose=0);

vec_pair_GF2EX_long CanZass(const GF2EX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: these routines use modular composition.  The space
// used for the required tables can be controlled by the variable
// GF2EXArgBound (see GF2EX.txt).



void mul(GF2EX& f, const vec_pair_GF2EX_long& v);
GF2EX mul(const vec_pair_GF2EX_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const GF2EX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// 2^{-iter*GF2E::degree()}.  This implements an algorithm from [Shoup,
// J. Symbolic Comp. 17:371-391, 1994].

long DetIrredTest(const GF2EX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const GF2EX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(GF2EX& f, long n);
GF2EX BuildIrred_GF2EX(long n);

// Build a monic irreducible poly of degree n. 

void BuildRandomIrred(GF2EX& f, const GF2EX& g);
GF2EX BuildRandomIrred(const GF2EX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.

void FrobeniusMap(GF2EX& h, const GF2EXModulus& F);
GF2EX FrobeniusMap(const GF2EXModulus& F);

// Computes h = X^{2^{GF2E::degree()}} mod F, 
// by either iterated squaring or modular
// composition.  The latter method is based on a technique developed
// in Kaltofen & Shoup (Faster polynomial factorization over high
// algebraic extensions of finite fields, ISSAC 1997).  This method is
// faster than iterated squaring when deg(F) is large relative to
// GF2E::degree().


long IterComputeDegree(const GF2EX& h, const GF2EXModulus& F);

// f is assumed to be an "equal degree" polynomial, and h =
// X^{2^{GF2E::degree()}} mod f (see function FrobeniusMap above) 
// The common degree of the irreducible factors
// of f is computed.  Uses a "baby step/giant step" algorithm, similar
// to NewDDF.  Although asymptotocally slower than RecComputeDegree
// (below), it is faster for reasonably sized inputs.

long RecComputeDegree(const GF2EX& h, const GF2EXModulus& F);

// f is assumed to be an "equal degree" polynomial, h = X^{2^{GF2E::degree()}}
// mod f (see function FrobeniusMap above).  
// The common degree of the irreducible factors of f is
// computed. Uses a recursive algorithm similar to DetIrredTest.

void TraceMap(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F,
              const GF2EX& h);

GF2EX TraceMap(const GF2EX& a, long d, const GF2EXModulus& F,
              const GF2EX& h);

// Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0,
// and h = X^q mod f, q a power of 2^{GF2E::degree()}.  This routine
// implements an algorithm from [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992].
// If q = 2^{GF2E::degree()}, then h can be computed most efficiently
// by using the function FrobeniusMap above.

void PowerCompose(GF2EX& w, const GF2EX& h, long d, const GF2EXModulus& F);

GF2EX PowerCompose(const GF2EX& h, long d, const GF2EXModulus& F);

// Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q
// mod f, q a power of 2^{GF2E::degree()}.  This routine implements an
// algorithm from [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992].
// If q = 2^{GF2E::degree()}, then h can be computed most efficiently
// by using the function FrobeniusMap above.

ntl-6.2.1/doc/GF2EXFactoring.txt000644 000765 000024 00000017617 12377144460 016620 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: GF2EXFactoring SUMMARY: Routines are provided for factorization of polynomials over GF2E, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_GF2EX_long& u, const GF2EX& f); vec_pair_GF2EX_long SquareFreeDecomp(const GF2EX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a list of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_GF2E& x, const GF2EX& f); vec_GF2E FindRoots(const GF2EX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(GF2E& root, const GF2EX& f); GF2E FindRoot(const GF2EX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void SFBerlekamp(vec_GF2EX& factors, const GF2EX& f, long verbose=0); vec_GF2EX SFBerlekamp(const GF2EX& f, long verbose=0); // Assumes f is square-free and monic. returns list of factors of f. // Uses "Berlekamp" approach, as described in detail in [Shoup, // J. Symbolic Comp. 20:363-397, 1995]. void berlekamp(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose=0); vec_pair_GF2EX_long berlekamp(const GF2EX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SFBerlekamp. void NewDDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h, long verbose=0); vec_pair_GF2EX_long NewDDF(const GF2EX& f, const GF2EX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^{2^{GF2E::degree()}} mod f, // which can be computed efficiently using the function FrobeniusMap // (see below). // This routine implements the baby step/giant step algorithm // of [Kaltofen and Shoup, STOC 1995], // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. // NOTE: When factoring "large" polynomials, // this routine uses external files to store some intermediate // results, which are removed if the routine terminates normally. // These files are stored in the current directory under names of the // form ddf-*-baby-* and ddf-*-giant-*. // The definition of "large" is controlled by the variable extern double GF2EXFileThresh // which can be set by the user. If the sizes of the tables // exceeds GF2EXFileThresh KB, external files are used. // Initial value is NTL_FILE_THRESH (defined in tools.h). void EDF(vec_GF2EX& factors, const GF2EX& f, const GF2EX& h, long d, long verbose=0); vec_GF2EX EDF(const GF2EX& f, const GF2EX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. // h = X^{2^{GF2E::degree()}} mod f, // which can be computed efficiently using the function FrobeniusMap // (see below). // d = degree of irreducible factors of f. // This routine implements the algorithm of [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void RootEDF(vec_GF2EX& factors, const GF2EX& f, long verbose=0); vec_GF2EX RootEDF(const GF2EX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_GF2EX& factors, const GF2EX& f, long verbose=0); vec_GF2EX SFCanZass(const GF2EX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose=0); vec_pair_GF2EX_long CanZass(const GF2EX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: these routines use modular composition. The space // used for the required tables can be controlled by the variable // GF2EXArgBound (see GF2EX.txt). void mul(GF2EX& f, const vec_pair_GF2EX_long& v); GF2EX mul(const vec_pair_GF2EX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const GF2EX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // 2^{-iter*GF2E::degree()}. This implements an algorithm from [Shoup, // J. Symbolic Comp. 17:371-391, 1994]. long DetIrredTest(const GF2EX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const GF2EX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(GF2EX& f, long n); GF2EX BuildIrred_GF2EX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(GF2EX& f, const GF2EX& g); GF2EX BuildRandomIrred(const GF2EX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. void FrobeniusMap(GF2EX& h, const GF2EXModulus& F); GF2EX FrobeniusMap(const GF2EXModulus& F); // Computes h = X^{2^{GF2E::degree()}} mod F, // by either iterated squaring or modular // composition. The latter method is based on a technique developed // in Kaltofen & Shoup (Faster polynomial factorization over high // algebraic extensions of finite fields, ISSAC 1997). This method is // faster than iterated squaring when deg(F) is large relative to // GF2E::degree(). long IterComputeDegree(const GF2EX& h, const GF2EXModulus& F); // f is assumed to be an "equal degree" polynomial, and h = // X^{2^{GF2E::degree()}} mod f (see function FrobeniusMap above) // The common degree of the irreducible factors // of f is computed. Uses a "baby step/giant step" algorithm, similar // to NewDDF. Although asymptotocally slower than RecComputeDegree // (below), it is faster for reasonably sized inputs. long RecComputeDegree(const GF2EX& h, const GF2EXModulus& F); // f is assumed to be an "equal degree" polynomial, h = X^{2^{GF2E::degree()}} // mod f (see function FrobeniusMap above). // The common degree of the irreducible factors of f is // computed. Uses a recursive algorithm similar to DetIrredTest. void TraceMap(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& h); GF2EX TraceMap(const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& h); // Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, // and h = X^q mod f, q a power of 2^{GF2E::degree()}. This routine // implements an algorithm from [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992]. // If q = 2^{GF2E::degree()}, then h can be computed most efficiently // by using the function FrobeniusMap above. void PowerCompose(GF2EX& w, const GF2EX& h, long d, const GF2EXModulus& F); GF2EX PowerCompose(const GF2EX& h, long d, const GF2EXModulus& F); // Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q // mod f, q a power of 2^{GF2E::degree()}. This routine implements an // algorithm from [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992]. // If q = 2^{GF2E::degree()}, then h can be computed most efficiently // by using the function FrobeniusMap above. ntl-6.2.1/doc/GF2X.cpp.html000644 000765 000024 00000142214 12377144460 015554 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/GF2X.cpp.html

/**************************************************************************\

MODULE: GF2X

SUMMARY:

The class GF2X implements polynomial arithmetic modulo 2.

Polynomial arithmetic is implemented using a combination of classical
routines and Karatsuba.

\**************************************************************************/

#include <NTL/GF2.h>
#include <NTL/vec_GF2.h>

class GF2X {
public:

   GF2X(); // initial value 0

   GF2X(const GF2X& a); // copy
   explicit GF2X(long a); // promotion
   explicit GF2X(GF2 a); // promotion

   GF2X& operator=(const GF2X& a); // assignment
   GF2X& operator=(GF2 a);
   GF2X& operator=(long a);

   ~GF2X(); // destructor

   GF2X(INIT_MONO_TYPE, long i, GF2 c);
   GF2X(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as GF2X(INIT_MONO, i, c)

   GF2X(INIT_MONO_TYPE, long i);
   // initialize to c*X^i, invoke as GF2X(INIT_MONO, i)

   // typedefs to aid in generic programming
   typedef GF2 coeff_type;
   typedef GF2E residue_type;
   typedef GF2XModulus modulus_type;


   // ...

};



/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: unlike other polynomial classes, the coefficient vector
for GF2X has a special representation, packing coefficients into 
words.  This has two consequences.  First, when using the indexing
notation on a non-const polynomial f, the return type is ref_GF2,
rather than GF2&.  For the most part, a ref_GF2 may be used like
a GF2& --- see GF2.txt for more details.  Second, when applying 
f.SetLength(n) to a polynomial f, this essentially has the effect
of zeroing out the coefficients of X^i for i >= n.

\**************************************************************************/

long deg(const GF2X& a);  // return deg(a); deg(0) == -1.

const GF2 coeff(const GF2X& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const GF2 LeadCoeff(const GF2X& a);
// returns leading term of a, or zero if a == 0

const GF2 ConstTerm(const GF2X& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(GF2X& x, long i, GF2 a);
void SetCoeff(GF2X& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(GF2X& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(GF2X& x); // x is set to the monomial X

long IsX(const GF2X& a); // test if x = X




ref_GF2 GF2X::operator[](long i);
const GF2 GF2X::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f)

void GF2X::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void GF2X::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void GF2X::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const GF2X& a, const GF2X& b);
long operator!=(const GF2X& a, const GF2X& b);

long IsZero(const GF2X& a); // test for 0
long IsOne(const GF2X& a); // test for 1

// PROMOTIONS: operators ==, != promote {long, GF2} to GF2X on (a, b)


/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

GF2X operator+(const GF2X& a, const GF2X& b);
GF2X operator-(const GF2X& a, const GF2X& b);

GF2X operator-(const GF2X& a); // unary -

GF2X& operator+=(GF2X& x, const GF2X& a);
GF2X& operator+=(GF2X& x, GF2 a);
GF2X& operator+=(GF2X& x, long a);

GF2X& operator-=(GF2X& x, const GF2X& a);
GF2X& operator-=(GF2X& x, GF2 a);
GF2X& operator-=(GF2X& x, long a);

GF2X& operator++(GF2X& x);  // prefix
void operator++(GF2X& x, int);  // postfix

GF2X& operator--(GF2X& x);  // prefix
void operator--(GF2X& x, int);  // postfix

// procedural versions:


void add(GF2X& x, const GF2X& a, const GF2X& b); // x = a + b
void sub(GF2X& x, const GF2X& a, const GF2X& b); // x = a - b
void negate(GF2X& x, const GF2X& a); // x = -a

// PROMOTIONS: binary +, - and procedures add, sub promote {long, GF2}
// to GF2X on (a, b).


/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

GF2X operator*(const GF2X& a, const GF2X& b);

GF2X& operator*=(GF2X& x, const GF2X& a);
GF2X& operator*=(GF2X& x, GF2 a);
GF2X& operator*=(GF2X& x, long a);

// procedural versions:

void mul(GF2X& x, const GF2X& a, const GF2X& b); // x = a * b

void sqr(GF2X& x, const GF2X& a); // x = a^2
GF2X sqr(const GF2X& a);

// PROMOTIONS: operator * and procedure mul promote {long, GF2} to GF2X
// on (a, b).


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

GF2X operator<<(const GF2X& a, long n);
GF2X operator>>(const GF2X& a, long n);

GF2X& operator<<=(GF2X& x, long n);
GF2X& operator>>=(GF2X& x, long n);

// procedural versions:

void LeftShift(GF2X& x, const GF2X& a, long n);
GF2X LeftShift(const GF2X& a, long n);

void RightShift(GF2X& x, const GF2X& a, long n);
GF2X RightShift(const GF2X& a, long n);

void MulByX(GF2X& x, const GF2X& a);
GF2X MulByX(const GF2X& a);


/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

GF2X operator/(const GF2X& a, const GF2X& b);
GF2X operator%(const GF2X& a, const GF2X& b);

GF2X& operator/=(GF2X& x, const GF2X& a);
GF2X& operator/=(GF2X& x, GF2 a);
GF2X& operator/=(GF2X& x, long a);

GF2X& operator%=(GF2X& x, const GF2X& b);


// procedural versions:


void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b);
// q = a/b, r = a%b

void div(GF2X& q, const GF2X& a, const GF2X& b);
// q = a/b

void rem(GF2X& r, const GF2X& a, const GF2X& b);
// r = a%b

long divide(GF2X& q, const GF2X& a, const GF2X& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const GF2X& a, const GF2X& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

// PROMOTIONS: operator / and procedure div promote {long, GF2} to GF2X
// on (a, b).


/**************************************************************************\

                                   GCD's

\**************************************************************************/


void GCD(GF2X& x, const GF2X& a, const GF2X& b);
GF2X GCD(const GF2X& a, const GF2X& b);
// x = GCD(a, b) (zero if a==b==0).


void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b);
// d = gcd(a,b), a s + b t = d 


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be 0 or 1, and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
may be arbitrary integers which are reduced modulo 2, and leading zeros
stripped.

There is also a more compact hex I/O format.  To output in this
format, set GF2X::HexOutput to a nonzero value.  On input, if the first
non-blank character read is 'x' or 'X', then a hex format is assumed.


\**************************************************************************/

istream& operator>>(istream& s, GF2X& x);
ostream& operator<<(ostream& s, const GF2X& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(GF2X& x, const GF2X& a);
GF2X diff(const GF2X& a);
// x = derivative of a


void reverse(GF2X& x, const GF2X& a, long hi);
GF2X reverse(const GF2X& a, long hi);

void reverse(GF2X& x, const GF2X& a);
GF2X reverse(const GF2X& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version


void VectorCopy(vec_GF2& x, const GF2X& a, long n);
vec_GF2 VectorCopy(const GF2X& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.

// Note that there is also a conversion routine from GF2X to vec_GF2
// that makes the length of the vector match the number of coefficients
// of the polynomial.

long weight(const GF2X& a);
// returns the # of nonzero coefficients in a

void GF2XFromBytes(GF2X& x, const unsigned char *p, long n);
GF2X GF2XFromBytes(const unsigned char *p, long n);
// conversion from byte vector to polynomial.
// x = sum(p[i]*X^(8*i), i = 0..n-1), where the bits of p[i] are interpretted
// as a polynomial in the natural way (i.e., p[i] = 1 is interpretted as 1,
// p[i] = 2 is interpretted as X, p[i] = 3 is interpretted as X+1, etc.).
// In the unusual event that characters are wider than 8 bits,
// only the low-order 8 bits of p[i] are used.

void BytesFromGF2X(unsigned char *p, const GF2X& a, long n);
// conversion from polynomial to byte vector.
// p[0..n-1] are computed so that 
//     a = sum(p[i]*X^(8*i), i = 0..n-1) mod X^(8*n),
// where the values p[i] are interpretted as polynomials as in GF2XFromBytes
// above.

long NumBits(const GF2X& a);
// returns number of bits of a, i.e., deg(a) + 1.

long NumBytes(const GF2X& a);
// returns number of bytes of a, i.e., floor((NumBits(a)+7)/8)




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(GF2X& x, long n);
GF2X random_GF2X(long n);
// x = random polynomial of degree < n 



/**************************************************************************\

                       Arithmetic mod X^n

Required: n >= 0; otherwise, an error is raised.

\**************************************************************************/

void trunc(GF2X& x, const GF2X& a, long n); // x = a % X^n
GF2X trunc(const GF2X& a, long n);

void MulTrunc(GF2X& x, const GF2X& a, const GF2X& b, long n);
GF2X MulTrunc(const GF2X& a, const GF2X& b, long n);
// x = a * b % X^n

void SqrTrunc(GF2X& x, const GF2X& a, long n);
GF2X SqrTrunc(const GF2X& a, long n);
// x = a^2 % X^n

void InvTrunc(GF2X& x, const GF2X& a, long n);
GF2X InvTrunc(const GF2X& a, long n);
// computes x = a^{-1} % X^n.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.

NOTE: if you want to do many computations with a fixed f, use the
GF2XModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(GF2X& x, const GF2X& a, const GF2X& b, const GF2X& f);
GF2X MulMod(const GF2X& a, const GF2X& b, const GF2X& f);
// x = (a * b) % f

void SqrMod(GF2X& x, const GF2X& a, const GF2X& f);
GF2X SqrMod(const GF2X& a, const GF2X& f);
// x = a^2 % f

void MulByXMod(GF2X& x, const GF2X& a, const GF2X& f);
GF2X MulByXMod(const GF2X& a, const GF2X& f);
// x = (a * X) mod f

void InvMod(GF2X& x, const GF2X& a, const GF2X& f);
GF2X InvMod(const GF2X& a, const GF2X& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(GF2X& x, const GF2X& a, const GF2X& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


// for modular exponentiation, see below



/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
GF2XModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

As an example, the following routine computes the product modulo f of a vector
of polynomials.

#include <NTL/GF2X.h>

void product(GF2X& x, const vec_GF2X& v, const GF2X& f)
{
   GF2XModulus F(f);
   GF2X res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}


Note that automatic conversions are provided so that a GF2X can
be used wherever a GF2XModulus is required, and a GF2XModulus
can be used wherever a GF2X is required.

The GF2XModulus routines optimize several important special cases:

  - f = X^n + X^k + 1, where k <= min((n+1)/2, n-NTL_BITS_PER_LONG)

  - f = X^n + X^{k_3} + X^{k_2} + X^{k_1} + 1,
      where k_3 <= min((n+1)/2, n-NTL_BITS_PER_LONG)

  - f = X^n + g, where deg(g) is small


\**************************************************************************/

class GF2XModulus {
public:
   GF2XModulus(); // initially in an unusable state
   ~GF2XModulus();

   GF2XModulus(const GF2XModulus&);  // copy

   GF2XModulus& operator=(const GF2XModulus&);   // assignment

   GF2XModulus(const GF2X& f); // initialize with f, deg(f) > 0

   operator const GF2X& () const;
   // read-only access to f, implicit conversion operator

   const GF2X& val() const;
   // read-only access to f, explicit notation

   long WordLength() const;
   // returns word-length of resisues
};

void build(GF2XModulus& F, const GF2X& f);
// pre-computes information about f and stores it in F; deg(f) > 0.
// Note that the declaration GF2XModulus F(f) is equivalent to
// GF2XModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).

long deg(const GF2XModulus& F);  // return deg(f)

void MulMod(GF2X& x, const GF2X& a, const GF2X& b, const GF2XModulus& F);
GF2X MulMod(const GF2X& a, const GF2X& b, const GF2XModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(GF2X& x, const GF2X& a, const GF2XModulus& F);
GF2X SqrMod(const GF2X& a, const GF2XModulus& F);
// x = a^2 % f; deg(a) < n

void MulByXMod(GF2X& x, const GF2X& a, const GF2XModulus& F);
GF2X MulByXMod(const GF2X& a, const GF2XModulus& F);
// x = (a * X) mod F

void PowerMod(GF2X& x, const GF2X& a, const ZZ& e, const GF2XModulus& F);
GF2X PowerMod(const GF2X& a, const ZZ& e, const GF2XModulus& F);

void PowerMod(GF2X& x, const GF2X& a, long e, const GF2XModulus& F);
GF2X PowerMod(const GF2X& a, long e, const GF2XModulus& F);

// x = a^e % f; deg(a) < n (e may be negative)

void PowerXMod(GF2X& x, const ZZ& e, const GF2XModulus& F);
GF2X PowerXMod(const ZZ& e, const GF2XModulus& F);

void PowerXMod(GF2X& x, long e, const GF2XModulus& F);
GF2X PowerXMod(long e, const GF2XModulus& F);

// x = X^e % f (e may be negative)


void rem(GF2X& x, const GF2X& a, const GF2XModulus& F);
// x = a % f

void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F);
// q = a/f, r = a%f

void div(GF2X& q, const GF2X& a, const GF2XModulus& F);
// q = a/f

// operator notation:

GF2X operator/(const GF2X& a, const GF2XModulus& F);
GF2X operator%(const GF2X& a, const GF2XModulus& F);

GF2X& operator/=(GF2X& x, const GF2XModulus& F);
GF2X& operator%=(GF2X& x, const GF2XModulus& F);


/**************************************************************************\

                             vectors of GF2X's

\**************************************************************************/


typedef Vec<GF2X> vec_GF2X; // backward compatibility


/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.



\**************************************************************************/

void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F);
GF2X CompMod(const GF2X& g, const GF2X& h, const GF2XModulus& F);
// x = g(h) mod f; deg(h) < n

void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2,
              const GF2X& h, const GF2XModulus& F);
// xi = gi(h) mod f (i=1,2), deg(h) < n.

void CompMod3(GF2X& x1, GF2X& x2, GF2X& x3,
              const GF2X& g1, const GF2X& g2, const GF2X& g3,
              const GF2X& h, const GF2XModulus& F);
// xi = gi(h) mod f (i=1..3), deg(h) < n


/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a GF2XArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct GF2XArgument {
   vec_GF2X H;
};

void build(GF2XArgument& H, const GF2X& h, const GF2XModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n

void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& H,
             const GF2XModulus& F);

GF2X CompMod(const GF2X& g, const GF2XArgument& H,
             const GF2XModulus& F);


extern long GF2XArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// GF2XArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in GF2XFactoring.

/**************************************************************************\

                     Power Projection routines

\**************************************************************************/

void project(GF2& x, const vec_GF2& a, const GF2X& b);
GF2 project(const vec_GF2& a, const GF2X& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k,
                   const GF2X& h, const GF2XModulus& F);

vec_GF2 ProjectPowers(const vec_GF2& a, long k,
                   const GF2X& h, const GF2XModulus& F);

// Computes the vector 

//   (project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// Restriction: must have a.length <= deg(F) and deg(h) < deg(F).
// This operation is really the "transpose" of the modular composition 
// operation.

void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k,
                   const GF2XArgument& H, const GF2XModulus& F);

vec_GF2 ProjectPowers(const vec_GF2& a, long k,
                   const GF2XArgument& H, const GF2XModulus& F);

// same as above, but uses a pre-computed GF2XArgument


// lower-level routines for transposed modular multiplication:

class GF2XTransMultiplier { /* ... */ };

void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F);

// build a GF2XTransMultiplier to use in the following routine:

void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B,
         const GF2XModulus& F);

vec_GF2 UpdateMap(const vec_GF2& a, const GF2XTransMultiplier& B,
         const GF2XModulus& F);

// Computes the vector

//   project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Restriction: must have a.length() <= deg(F) and deg(b) < deg(F).
// This is really the transpose of modular multiplication.
// Input may have "high order" zeroes stripped.
// Output always has high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(GF2X& h, const vec_GF2& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m

void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m);
GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F, long m);

void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F);
GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic; it always
// returns a divisor of the minimal polynomial, possibly a proper divisor.

void MinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m);
GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F, long m);

void MinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F);
GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m);
GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F, long m);

void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F);
GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F);

// same as above, but assumes that F is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).


/**************************************************************************\

                                Traces

\**************************************************************************/


void TraceMod(GF2& x, const GF2X& a, const GF2XModulus& F);
GF2 TraceMod(const GF2X& a, const GF2XModulus& F);

void TraceMod(GF2& x, const GF2X& a, const GF2X& f);
GF2 TraceMod(const GF2X& a, const GF2X& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_GF2& S, const GF2X& f);
vec_GF2 TraceVec(const GF2X& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].


/**************************************************************************\

                           Miscellany

\**************************************************************************/


void clear(GF2X& x) // x = 0
void set(GF2X& x); // x = 1


void GF2X::kill();
// f.kill() sets f to 0 and frees all memory held by f.  

GF2X::GF2X(INIT_SIZE_TYPE, long n);
// GF2X(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const GF2X& zero();
// GF2X::zero() is a read-only reference to 0

void swap(GF2X& x, GF2X& y);
// swap x and y (via "pointer swapping")

GF2X::GF2X(long i, GF2 c);
GF2X::GF2X(long i, long c);
// initialize to c*X^i, provided for backward compatibility

// SIZE INVARIANT: for any f in GF2X, deg(f)+1 < 2^(NTL_BITS_PER_LONG-4).
ntl-6.2.1/doc/GF2X.txt000644 000765 000024 00000060540 12377144460 014647 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: GF2X SUMMARY: The class GF2X implements polynomial arithmetic modulo 2. Polynomial arithmetic is implemented using a combination of classical routines and Karatsuba. \**************************************************************************/ #include #include class GF2X { public: GF2X(); // initial value 0 GF2X(const GF2X& a); // copy explicit GF2X(long a); // promotion explicit GF2X(GF2 a); // promotion GF2X& operator=(const GF2X& a); // assignment GF2X& operator=(GF2 a); GF2X& operator=(long a); ~GF2X(); // destructor GF2X(INIT_MONO_TYPE, long i, GF2 c); GF2X(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as GF2X(INIT_MONO, i, c) GF2X(INIT_MONO_TYPE, long i); // initialize to c*X^i, invoke as GF2X(INIT_MONO, i) // typedefs to aid in generic programming typedef GF2 coeff_type; typedef GF2E residue_type; typedef GF2XModulus modulus_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: unlike other polynomial classes, the coefficient vector for GF2X has a special representation, packing coefficients into words. This has two consequences. First, when using the indexing notation on a non-const polynomial f, the return type is ref_GF2, rather than GF2&. For the most part, a ref_GF2 may be used like a GF2& --- see GF2.txt for more details. Second, when applying f.SetLength(n) to a polynomial f, this essentially has the effect of zeroing out the coefficients of X^i for i >= n. \**************************************************************************/ long deg(const GF2X& a); // return deg(a); deg(0) == -1. const GF2 coeff(const GF2X& a, long i); // returns the coefficient of X^i, or zero if i not in range const GF2 LeadCoeff(const GF2X& a); // returns leading term of a, or zero if a == 0 const GF2 ConstTerm(const GF2X& a); // returns constant term of a, or zero if a == 0 void SetCoeff(GF2X& x, long i, GF2 a); void SetCoeff(GF2X& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(GF2X& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(GF2X& x); // x is set to the monomial X long IsX(const GF2X& a); // test if x = X ref_GF2 GF2X::operator[](long i); const GF2 GF2X::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f) void GF2X::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void GF2X::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void GF2X::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const GF2X& a, const GF2X& b); long operator!=(const GF2X& a, const GF2X& b); long IsZero(const GF2X& a); // test for 0 long IsOne(const GF2X& a); // test for 1 // PROMOTIONS: operators ==, != promote {long, GF2} to GF2X on (a, b) /**************************************************************************\ Addition \**************************************************************************/ // operator notation: GF2X operator+(const GF2X& a, const GF2X& b); GF2X operator-(const GF2X& a, const GF2X& b); GF2X operator-(const GF2X& a); // unary - GF2X& operator+=(GF2X& x, const GF2X& a); GF2X& operator+=(GF2X& x, GF2 a); GF2X& operator+=(GF2X& x, long a); GF2X& operator-=(GF2X& x, const GF2X& a); GF2X& operator-=(GF2X& x, GF2 a); GF2X& operator-=(GF2X& x, long a); GF2X& operator++(GF2X& x); // prefix void operator++(GF2X& x, int); // postfix GF2X& operator--(GF2X& x); // prefix void operator--(GF2X& x, int); // postfix // procedural versions: void add(GF2X& x, const GF2X& a, const GF2X& b); // x = a + b void sub(GF2X& x, const GF2X& a, const GF2X& b); // x = a - b void negate(GF2X& x, const GF2X& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub promote {long, GF2} // to GF2X on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: GF2X operator*(const GF2X& a, const GF2X& b); GF2X& operator*=(GF2X& x, const GF2X& a); GF2X& operator*=(GF2X& x, GF2 a); GF2X& operator*=(GF2X& x, long a); // procedural versions: void mul(GF2X& x, const GF2X& a, const GF2X& b); // x = a * b void sqr(GF2X& x, const GF2X& a); // x = a^2 GF2X sqr(const GF2X& a); // PROMOTIONS: operator * and procedure mul promote {long, GF2} to GF2X // on (a, b). /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: GF2X operator<<(const GF2X& a, long n); GF2X operator>>(const GF2X& a, long n); GF2X& operator<<=(GF2X& x, long n); GF2X& operator>>=(GF2X& x, long n); // procedural versions: void LeftShift(GF2X& x, const GF2X& a, long n); GF2X LeftShift(const GF2X& a, long n); void RightShift(GF2X& x, const GF2X& a, long n); GF2X RightShift(const GF2X& a, long n); void MulByX(GF2X& x, const GF2X& a); GF2X MulByX(const GF2X& a); /**************************************************************************\ Division \**************************************************************************/ // operator notation: GF2X operator/(const GF2X& a, const GF2X& b); GF2X operator%(const GF2X& a, const GF2X& b); GF2X& operator/=(GF2X& x, const GF2X& a); GF2X& operator/=(GF2X& x, GF2 a); GF2X& operator/=(GF2X& x, long a); GF2X& operator%=(GF2X& x, const GF2X& b); // procedural versions: void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b); // q = a/b, r = a%b void div(GF2X& q, const GF2X& a, const GF2X& b); // q = a/b void rem(GF2X& r, const GF2X& a, const GF2X& b); // r = a%b long divide(GF2X& q, const GF2X& a, const GF2X& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const GF2X& a, const GF2X& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 // PROMOTIONS: operator / and procedure div promote {long, GF2} to GF2X // on (a, b). /**************************************************************************\ GCD's \**************************************************************************/ void GCD(GF2X& x, const GF2X& a, const GF2X& b); GF2X GCD(const GF2X& a, const GF2X& b); // x = GCD(a, b) (zero if a==b==0). void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b); // d = gcd(a,b), a s + b t = d /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be 0 or 1, and a_n not zero (the zero polynomial is [ ]). On input, the coefficients may be arbitrary integers which are reduced modulo 2, and leading zeros stripped. There is also a more compact hex I/O format. To output in this format, set GF2X::HexOutput to a nonzero value. On input, if the first non-blank character read is 'x' or 'X', then a hex format is assumed. \**************************************************************************/ istream& operator>>(istream& s, GF2X& x); ostream& operator<<(ostream& s, const GF2X& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(GF2X& x, const GF2X& a); GF2X diff(const GF2X& a); // x = derivative of a void reverse(GF2X& x, const GF2X& a, long hi); GF2X reverse(const GF2X& a, long hi); void reverse(GF2X& x, const GF2X& a); GF2X reverse(const GF2X& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_GF2& x, const GF2X& a, long n); vec_GF2 VectorCopy(const GF2X& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. // Note that there is also a conversion routine from GF2X to vec_GF2 // that makes the length of the vector match the number of coefficients // of the polynomial. long weight(const GF2X& a); // returns the # of nonzero coefficients in a void GF2XFromBytes(GF2X& x, const unsigned char *p, long n); GF2X GF2XFromBytes(const unsigned char *p, long n); // conversion from byte vector to polynomial. // x = sum(p[i]*X^(8*i), i = 0..n-1), where the bits of p[i] are interpretted // as a polynomial in the natural way (i.e., p[i] = 1 is interpretted as 1, // p[i] = 2 is interpretted as X, p[i] = 3 is interpretted as X+1, etc.). // In the unusual event that characters are wider than 8 bits, // only the low-order 8 bits of p[i] are used. void BytesFromGF2X(unsigned char *p, const GF2X& a, long n); // conversion from polynomial to byte vector. // p[0..n-1] are computed so that // a = sum(p[i]*X^(8*i), i = 0..n-1) mod X^(8*n), // where the values p[i] are interpretted as polynomials as in GF2XFromBytes // above. long NumBits(const GF2X& a); // returns number of bits of a, i.e., deg(a) + 1. long NumBytes(const GF2X& a); // returns number of bytes of a, i.e., floor((NumBits(a)+7)/8) /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(GF2X& x, long n); GF2X random_GF2X(long n); // x = random polynomial of degree < n /**************************************************************************\ Arithmetic mod X^n Required: n >= 0; otherwise, an error is raised. \**************************************************************************/ void trunc(GF2X& x, const GF2X& a, long n); // x = a % X^n GF2X trunc(const GF2X& a, long n); void MulTrunc(GF2X& x, const GF2X& a, const GF2X& b, long n); GF2X MulTrunc(const GF2X& a, const GF2X& b, long n); // x = a * b % X^n void SqrTrunc(GF2X& x, const GF2X& a, long n); GF2X SqrTrunc(const GF2X& a, long n); // x = a^2 % X^n void InvTrunc(GF2X& x, const GF2X& a, long n); GF2X InvTrunc(const GF2X& a, long n); // computes x = a^{-1} % X^n. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the GF2XModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(GF2X& x, const GF2X& a, const GF2X& b, const GF2X& f); GF2X MulMod(const GF2X& a, const GF2X& b, const GF2X& f); // x = (a * b) % f void SqrMod(GF2X& x, const GF2X& a, const GF2X& f); GF2X SqrMod(const GF2X& a, const GF2X& f); // x = a^2 % f void MulByXMod(GF2X& x, const GF2X& a, const GF2X& f); GF2X MulByXMod(const GF2X& a, const GF2X& f); // x = (a * X) mod f void InvMod(GF2X& x, const GF2X& a, const GF2X& f); GF2X InvMod(const GF2X& a, const GF2X& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(GF2X& x, const GF2X& a, const GF2X& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) // for modular exponentiation, see below /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build GF2XModulus F for f. This pre-computes information about f that speeds up subsequent computations. As an example, the following routine computes the product modulo f of a vector of polynomials. #include void product(GF2X& x, const vec_GF2X& v, const GF2X& f) { GF2XModulus F(f); GF2X res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } Note that automatic conversions are provided so that a GF2X can be used wherever a GF2XModulus is required, and a GF2XModulus can be used wherever a GF2X is required. The GF2XModulus routines optimize several important special cases: - f = X^n + X^k + 1, where k <= min((n+1)/2, n-NTL_BITS_PER_LONG) - f = X^n + X^{k_3} + X^{k_2} + X^{k_1} + 1, where k_3 <= min((n+1)/2, n-NTL_BITS_PER_LONG) - f = X^n + g, where deg(g) is small \**************************************************************************/ class GF2XModulus { public: GF2XModulus(); // initially in an unusable state ~GF2XModulus(); GF2XModulus(const GF2XModulus&); // copy GF2XModulus& operator=(const GF2XModulus&); // assignment GF2XModulus(const GF2X& f); // initialize with f, deg(f) > 0 operator const GF2X& () const; // read-only access to f, implicit conversion operator const GF2X& val() const; // read-only access to f, explicit notation long WordLength() const; // returns word-length of resisues }; void build(GF2XModulus& F, const GF2X& f); // pre-computes information about f and stores it in F; deg(f) > 0. // Note that the declaration GF2XModulus F(f) is equivalent to // GF2XModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const GF2XModulus& F); // return deg(f) void MulMod(GF2X& x, const GF2X& a, const GF2X& b, const GF2XModulus& F); GF2X MulMod(const GF2X& a, const GF2X& b, const GF2XModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(GF2X& x, const GF2X& a, const GF2XModulus& F); GF2X SqrMod(const GF2X& a, const GF2XModulus& F); // x = a^2 % f; deg(a) < n void MulByXMod(GF2X& x, const GF2X& a, const GF2XModulus& F); GF2X MulByXMod(const GF2X& a, const GF2XModulus& F); // x = (a * X) mod F void PowerMod(GF2X& x, const GF2X& a, const ZZ& e, const GF2XModulus& F); GF2X PowerMod(const GF2X& a, const ZZ& e, const GF2XModulus& F); void PowerMod(GF2X& x, const GF2X& a, long e, const GF2XModulus& F); GF2X PowerMod(const GF2X& a, long e, const GF2XModulus& F); // x = a^e % f; deg(a) < n (e may be negative) void PowerXMod(GF2X& x, const ZZ& e, const GF2XModulus& F); GF2X PowerXMod(const ZZ& e, const GF2XModulus& F); void PowerXMod(GF2X& x, long e, const GF2XModulus& F); GF2X PowerXMod(long e, const GF2XModulus& F); // x = X^e % f (e may be negative) void rem(GF2X& x, const GF2X& a, const GF2XModulus& F); // x = a % f void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F); // q = a/f, r = a%f void div(GF2X& q, const GF2X& a, const GF2XModulus& F); // q = a/f // operator notation: GF2X operator/(const GF2X& a, const GF2XModulus& F); GF2X operator%(const GF2X& a, const GF2XModulus& F); GF2X& operator/=(GF2X& x, const GF2XModulus& F); GF2X& operator%=(GF2X& x, const GF2XModulus& F); /**************************************************************************\ vectors of GF2X's \**************************************************************************/ typedef Vec vec_GF2X; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F); GF2X CompMod(const GF2X& g, const GF2X& h, const GF2XModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2, const GF2X& h, const GF2XModulus& F); // xi = gi(h) mod f (i=1,2), deg(h) < n. void CompMod3(GF2X& x1, GF2X& x2, GF2X& x3, const GF2X& g1, const GF2X& g2, const GF2X& g3, const GF2X& h, const GF2XModulus& F); // xi = gi(h) mod f (i=1..3), deg(h) < n /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a GF2XArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct GF2XArgument { vec_GF2X H; }; void build(GF2XArgument& H, const GF2X& h, const GF2XModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& H, const GF2XModulus& F); GF2X CompMod(const GF2X& g, const GF2XArgument& H, const GF2XModulus& F); extern long GF2XArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // GF2XArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in GF2XFactoring. /**************************************************************************\ Power Projection routines \**************************************************************************/ void project(GF2& x, const vec_GF2& a, const GF2X& b); GF2 project(const vec_GF2& a, const GF2X& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2X& h, const GF2XModulus& F); vec_GF2 ProjectPowers(const vec_GF2& a, long k, const GF2X& h, const GF2XModulus& F); // Computes the vector // (project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // Restriction: must have a.length <= deg(F) and deg(h) < deg(F). // This operation is really the "transpose" of the modular composition // operation. void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F); vec_GF2 ProjectPowers(const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F); // same as above, but uses a pre-computed GF2XArgument // lower-level routines for transposed modular multiplication: class GF2XTransMultiplier { /* ... */ }; void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F); // build a GF2XTransMultiplier to use in the following routine: void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F); vec_GF2 UpdateMap(const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Restriction: must have a.length() <= deg(F) and deg(b) < deg(F). // This is really the transpose of modular multiplication. // Input may have "high order" zeroes stripped. // Output always has high order zeroes stripped. /**************************************************************************\ Minimum Polynomials All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(GF2X& h, const vec_GF2& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m); GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F, long m); void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F); GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic; it always // returns a divisor of the minimal polynomial, possibly a proper divisor. void MinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m); GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F, long m); void MinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F); GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m); GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F, long m); void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F); GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F); // same as above, but assumes that F is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Traces \**************************************************************************/ void TraceMod(GF2& x, const GF2X& a, const GF2XModulus& F); GF2 TraceMod(const GF2X& a, const GF2XModulus& F); void TraceMod(GF2& x, const GF2X& a, const GF2X& f); GF2 TraceMod(const GF2X& a, const GF2X& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_GF2& S, const GF2X& f); vec_GF2 TraceVec(const GF2X& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(GF2X& x) // x = 0 void set(GF2X& x); // x = 1 void GF2X::kill(); // f.kill() sets f to 0 and frees all memory held by f. GF2X::GF2X(INIT_SIZE_TYPE, long n); // GF2X(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const GF2X& zero(); // GF2X::zero() is a read-only reference to 0 void swap(GF2X& x, GF2X& y); // swap x and y (via "pointer swapping") GF2X::GF2X(long i, GF2 c); GF2X::GF2X(long i, long c); // initialize to c*X^i, provided for backward compatibility // SIZE INVARIANT: for any f in GF2X, deg(f)+1 < 2^(NTL_BITS_PER_LONG-4). ntl-6.2.1/doc/GF2XFactoring.cpp.html000644 000765 000024 00000017624 12377144460 017417 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/GF2XFactoring.cpp.html

/**************************************************************************\

MODULE: GF2XFactoring

SUMMARY:

Routines are provided for factorization in F_2[X], as well as routines
for related problems such as testing irreducibility and constructing
irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/GF2X.h>
#include <NTL/pair_GF2X_long.h>

void SquareFreeDecomp(vec_pair_GF2X_long& u, const GF2X& f);
vec_pair_GF2X_long SquareFreeDecomp(const GF2X& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a list of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void DDF(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0);
vec_pair_GF2X_long DDF(const GF2X& f, long verbose=0);

// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.



void EDF(vec_GF2X& factors, const GF2X& f, long d, long verbose=0);
vec_GF2X EDF(const GF2X& f, long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  d = degree of
// irreducible factors of f

void SFCanZass(vec_GF2X& factors, const GF2X& f, long verbose=0);
vec_GF2X SFCanZass(const GF2X& f, long verbose=0);


// Assumes f is monic and square-free.  returns list of factors of f.


void CanZass(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0);
vec_pair_GF2X_long CanZass(const GF2X& f, long verbose=0);

// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.


void mul(GF2X& f, const vec_pair_GF2X_long& v);
GF2X mul(const vec_pair_GF2X_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long IterIrredTest(const GF2X& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildSparseIrred(GF2X& f, long n);
GF2X BuildSparseIrred_GF2X(long n);

// Builds a monic irreducible polynomial of degree n.
// If there is an irreducible trinomial X^n + X^k + 1,
// then the one with minimal k is chosen.
// Otherwise, if there is an irreducible pentanomial 
// X^n + X^k3 + X^k2 + x^k1 + 1, then the one with minimal
// k3 is chosen (minimizing first k2 and then k1).
// Otherwise, if there is niether an irreducible trinomial
// or pentanomial, the routine result from BuildIrred (see below)
// is chosen---this is probably only of academic interest,
// since it a reasonable, but unproved, conjecture that they
// exist for every n > 1.

// For n <= 2048, the polynomial is constructed
// by table lookup in a pre-computed table.

// The GF2XModulus data structure and routines (and indirectly GF2E) 
// are optimized to deal with the output from BuildSparseIrred.

void BuildIrred(GF2X& f, long n);
GF2X BuildIrred_GF2X(long n);

// Build a monic irreducible poly of degree n.  The polynomial
// constructed is "canonical" in the sense that it is of the form
// f=X^n + g, where the bits of g are the those of the smallest
// non-negative integer that make f irreducible.  

// The GF2XModulus data structure and routines (and indirectly GF2E) 
// are optimized to deal with the output from BuildIrred.

// Note that the output from BuildSparseIrred will generally yield
// a "better" representation (in terms of efficiency) for
// GF(2^n) than the output from BuildIrred.



void BuildRandomIrred(GF2X& f, const GF2X& g);
GF2X BuildRandomIrred(const GF2X& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.

ntl-6.2.1/doc/GF2XFactoring.txt000644 000765 000024 00000007756 12377144460 016516 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: GF2XFactoring SUMMARY: Routines are provided for factorization in F_2[X], as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_GF2X_long& u, const GF2X& f); vec_pair_GF2X_long SquareFreeDecomp(const GF2X& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a list of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void DDF(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0); vec_pair_GF2X_long DDF(const GF2X& f, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. void EDF(vec_GF2X& factors, const GF2X& f, long d, long verbose=0); vec_GF2X EDF(const GF2X& f, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. d = degree of // irreducible factors of f void SFCanZass(vec_GF2X& factors, const GF2X& f, long verbose=0); vec_GF2X SFCanZass(const GF2X& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. void CanZass(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0); vec_pair_GF2X_long CanZass(const GF2X& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. void mul(GF2X& f, const vec_pair_GF2X_long& v); GF2X mul(const vec_pair_GF2X_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long IterIrredTest(const GF2X& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildSparseIrred(GF2X& f, long n); GF2X BuildSparseIrred_GF2X(long n); // Builds a monic irreducible polynomial of degree n. // If there is an irreducible trinomial X^n + X^k + 1, // then the one with minimal k is chosen. // Otherwise, if there is an irreducible pentanomial // X^n + X^k3 + X^k2 + x^k1 + 1, then the one with minimal // k3 is chosen (minimizing first k2 and then k1). // Otherwise, if there is niether an irreducible trinomial // or pentanomial, the routine result from BuildIrred (see below) // is chosen---this is probably only of academic interest, // since it a reasonable, but unproved, conjecture that they // exist for every n > 1. // For n <= 2048, the polynomial is constructed // by table lookup in a pre-computed table. // The GF2XModulus data structure and routines (and indirectly GF2E) // are optimized to deal with the output from BuildSparseIrred. void BuildIrred(GF2X& f, long n); GF2X BuildIrred_GF2X(long n); // Build a monic irreducible poly of degree n. The polynomial // constructed is "canonical" in the sense that it is of the form // f=X^n + g, where the bits of g are the those of the smallest // non-negative integer that make f irreducible. // The GF2XModulus data structure and routines (and indirectly GF2E) // are optimized to deal with the output from BuildIrred. // Note that the output from BuildSparseIrred will generally yield // a "better" representation (in terms of efficiency) for // GF(2^n) than the output from BuildIrred. void BuildRandomIrred(GF2X& f, const GF2X& g); GF2X BuildRandomIrred(const GF2X& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. ntl-6.2.1/doc/GF2XVec.cpp.html000644 000765 000024 00000007636 12377144460 016222 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/GF2XVec.cpp.html

/**************************************************************************\

MODULE: GF2XVec

SUMMARY:

The class GF2XVec implements vectors of fixed-length GF2X's.  You can
allocate a vector of GF2X's of a specified length, where the maximum
size of each GF2X is also specified.  These parameters can be specified
either with a constructor, or with SetSize.  It is an error to
try to re-size a vector of non-xero , or store a GF2X that doesn't fit.  
The space can be released with "kill", and then you are free to call SetSize
again.  If you want more flexible---but less efficient---vectors, use
vec_GF2X.

\**************************************************************************/

#include <NTL/GF2X.h>


class GF2XVec {
public:
   GF2XVec();

   GF2XVec& operator=(const GF2XVec&);
   // first kill()'s destination (unless source and destination are
   // identical)

   GF2XVec(const GF2XVec&);
   ~GF2XVec();

   GF2XVec(long n, long d);
   // sets length to n and max size of each element to d,
   // where the size d measures the number of words 

   void SetSize(long n, long d);
   // sets length to n and max size of each element to d,
   // where the size d measures the number of words 

   long length() const;
   // length of vector

   long BaseSize() const;
   // max size of each element

   void kill();
   // release space


   GF2X* elts();
   const GF2X* elts() const;
   // pointer to first element

   GF2X& operator[](long i);
   const GF2X& operator[](long i) const;
   // indexing operator; starts at 0; no range checking
};


void swap(GF2XVec& x, GF2XVec& y);
// swaps x and y by swapping pointers

ntl-6.2.1/doc/GF2XVec.txt000644 000765 000024 00000003144 12377144460 015302 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: GF2XVec SUMMARY: The class GF2XVec implements vectors of fixed-length GF2X's. You can allocate a vector of GF2X's of a specified length, where the maximum size of each GF2X is also specified. These parameters can be specified either with a constructor, or with SetSize. It is an error to try to re-size a vector of non-xero , or store a GF2X that doesn't fit. The space can be released with "kill", and then you are free to call SetSize again. If you want more flexible---but less efficient---vectors, use vec_GF2X. \**************************************************************************/ #include class GF2XVec { public: GF2XVec(); GF2XVec& operator=(const GF2XVec&); // first kill()'s destination (unless source and destination are // identical) GF2XVec(const GF2XVec&); ~GF2XVec(); GF2XVec(long n, long d); // sets length to n and max size of each element to d, // where the size d measures the number of words void SetSize(long n, long d); // sets length to n and max size of each element to d, // where the size d measures the number of words long length() const; // length of vector long BaseSize() const; // max size of each element void kill(); // release space GF2X* elts(); const GF2X* elts() const; // pointer to first element GF2X& operator[](long i); const GF2X& operator[](long i) const; // indexing operator; starts at 0; no range checking }; void swap(GF2XVec& x, GF2XVec& y); // swaps x and y by swapping pointers ntl-6.2.1/doc/HNF.cpp.html000644 000765 000024 00000004476 12377144460 015470 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/HNF.cpp.html

/**************************************************************************\

MODULE: HNF

SUMMARY:

A routine for computing Hermite Normal Forms

\**************************************************************************/


#include <NTL/mat_ZZ.h>

void HNF(mat_ZZ& W, const mat_ZZ& A, const ZZ& D);

// The input matrix A is an n x m matrix of rank m (so n >= m), and D
// is a multiple of the determinant of the lattice L spanned by the
// rows of A.  W is computed as the Hermite Normal Form of A; that is,
// W is the unique m x m matrix whose rows span L, such that

//   - W is lower triangular,
//   - the diagonal entries are positive,
//   - any entry below the diagonal is a non-negative number
//     strictly less than the diagonal entry in its column.

// Currently, this is implemented using the algorithm of [P. Domich,
// R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987].

ntl-6.2.1/doc/HNF.txt000644 000765 000024 00000001612 12377144460 014547 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: HNF SUMMARY: A routine for computing Hermite Normal Forms \**************************************************************************/ #include void HNF(mat_ZZ& W, const mat_ZZ& A, const ZZ& D); // The input matrix A is an n x m matrix of rank m (so n >= m), and D // is a multiple of the determinant of the lattice L spanned by the // rows of A. W is computed as the Hermite Normal Form of A; that is, // W is the unique m x m matrix whose rows span L, such that // - W is lower triangular, // - the diagonal entries are positive, // - any entry below the diagonal is a non-negative number // strictly less than the diagonal entry in its column. // Currently, this is implemented using the algorithm of [P. Domich, // R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987]. ntl-6.2.1/doc/LLL.cpp.html000644 000765 000024 00000070154 12377144460 015474 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/LLL.cpp.html

/**************************************************************************\

MODULE: LLL

SUMMARY:

Routines are provided for lattice basis reduction, including both
exact-aritmetic variants (slow but sure) and floating-point variants
(fast but only approximate).

For an introduction to the basics of LLL reduction, see
[H. Cohen, A Course in Computational Algebraic Number Theory, Springer, 1993].

The LLL algorithm was introduced in [A. K. Lenstra, H. W. Lenstra, and
L. Lovasz, Math. Ann. 261 (1982), 515-534].

\**************************************************************************/




#include <NTL/mat_ZZ.h>



/**************************************************************************\

                         Exact Arithmetic Variants

\**************************************************************************/




long LLL(ZZ& det2, mat_ZZ& B, long verbose = 0);
long LLL(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long verbose = 0);

long LLL(ZZ& det2, mat_ZZ& B, long a, long b, long verbose = 0);
long LLL(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose = 0);


// performs LLL reduction.

// B is an m x n matrix, viewed as m rows of n-vectors.  m may be less
// than, equal to, or greater than n, and the rows need not be
// linearly independent.  B is transformed into an LLL-reduced basis,
// and the return value is the rank r of B.  The first m-r rows of B
// are zero.  

// More specifically, elementary row transformations are performed on
// B so that the non-zero rows of new-B form an LLL-reduced basis
// for the lattice spanned by the rows of old-B.
// The default reduction parameter is delta=3/4, which means
// that the squared length of the first non-zero basis vector
// is no more than 2^{r-1} times that of the shortest vector in
// the lattice.

// det2 is calculated as the *square* of the determinant
// of the lattice---note that sqrt(det2) is in general an integer
// only when r = n.

// In the second version, U is set to the transformation matrix, so
// that U is a unimodular m x m matrix with U * old-B = new-B.
// Note that the first m-r rows of U form a basis (as a lattice)
// for the kernel of old-B. 

// The third and fourth versions allow an arbitrary reduction
// parameter delta=a/b, where 1/4 < a/b <= 1, where a and b are positive
// integers.
// For a basis reduced with parameter delta, the squared length
// of the first non-zero basis vector is no more than 
// 1/(delta-1/4)^{r-1} times that of the shortest vector in the
// lattice (see, e.g., the article by Schnorr and Euchner mentioned below).

// The algorithm employed here is essentially the one in Cohen's book.


// Some variations:

long LLL_plus(vec_ZZ& D, mat_ZZ& B, long verbose = 0);
long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long verbose = 0);

long LLL_plus(vec_ZZ& D, mat_ZZ& B, long a, long b, long verbose = 0);
long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long a, long b,
              long verbose = 0);

// These are variations that return a bit more information about the
// reduced basis.  If r is the rank of B, then D is a vector of length
// r+1, such that D[0] = 1, and for i = 1..r, D[i]/D[i-1] is equal to
// the square of the length of the i-th vector of the Gram-Schmidt basis
// corresponding to the (non-zero) rows of the LLL reduced basis B.
// In particular, D[r] is equal to the value det2 computed by the
// plain LLL routines.

/**************************************************************************\

                      Computing Images and Kernels

\**************************************************************************/


long image(ZZ& det2, mat_ZZ& B, long verbose = 0);
long image(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long verbose = 0);

// This computes the image of B using a "cheap" version of the LLL:
// it performs the usual "size reduction", but it only swaps
// vectors when linear dependencies are found.
// I haven't seen this described in the literature, but it works 
// fairly well in practice, and can also easily be shown
// to run in a reasonable amount of time with reasonably bounded
// numbers.

// As in the above LLL routines, the return value is the rank r of B, and the
// first m-r rows will be zero.  U is a unimodular m x m matrix with 
// U * old-B = new-B.  det2 has the same meaning as above.

// Note that the first m-r rows of U form a basis (as a lattice)
// for the kernel of old-B. 
// This is a reasonably practical algorithm for computing kernels.
// One can also apply image() to the kernel to get somewhat
// shorter basis vectors for the kernels (there are no linear
// dependencies, but the size reduction may anyway help).
// For even shorter kernel basis vectors, on can apply
// LLL(). 


/**************************************************************************\

                    Finding a vector in a lattice 

\**************************************************************************/

long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce=0);

// This tests if for given A and y, there exists x such that x*A = y;
// if so, x is set to a solution, and the value 1 is returned;
// otherwise, x is left unchanged, and the value 0 is returned.

// The optional parameter reduce controls the 'quality' of the
// solution vector;  if the rows of A are linearly dependent, 
// there are many solutions, if there are any at all.
// The value of reduce controls the amount of effort that goes
// into finding a 'short' solution vector x.

//    reduce = 0: No particular effort is made to find a short solution.

//    reduce = 1: A simple 'size reduction' algorithm is run on kernel(A);
//                this is fast, and may yield somewhat shorter
//                solutions than the default, but not necessarily
//                very close at all to optimal.

//    reduce = 2: the LLL algorithm is run on kernel(A);
//                this may be significantly slower than the other options,
//                but yields solutions that are provably close to optimal.
//                More precisely, if kernel(A) has rank k,
//                then the squared length of the obtained solution
//                is no more than max(1, 2^(k-2)) times that of 
//                the optimal solution.  This makes use of slight
//                variation of Babai's approximately nearest vector algorithm.

// Of course, if the the rows of A are linearly independent, then
// the value of reduce is irrelevant: the solution, if it exists,
// is unique.

// Note that regardless of the value of reduce, the algorithm
// runs in polynomial time, and hence the bit-length of the solution
// vector is bounded by a polynomial in the bit-length of the inputs.




/**************************************************************************\

                   Floating Point Variants

There are a number of floating point LLL variants available:
you can choose the precision, the orthogonalization strategy,
and the reduction condition.

The wide variety of choices may seem a bit bewildering.
See below the discussion "How to choose?".

*** Precision:

  FP -- double
  QP -- quad_float (quasi quadruple precision)
        this is useful when roundoff errors can cause problems
  XD -- xdouble (extended exponent doubles)
        this is useful when numbers get too big
  RR -- RR (arbitrary precision floating point)
        this is useful for large precision and magnitudes

  Generally speaking, the choice FP will be the fastest,
  but may be prone to roundoff errors and/or overflow.
  

*** Orthogonalization Strategy: 

  -- Classical Gramm-Schmidt Orthogonalization.
     This choice uses classical methods for computing
     the Gramm-Schmidt othogonalization.
     It is fast but prone to stability problems.
     This strategy was first proposed by Schnorr and Euchner
     [C. P. Schnorr and M. Euchner, Proc. Fundamentals of Computation Theory, 
     LNCS 529, pp. 68-85, 1991].  
     The version implemented here is substantially different, improving
     both stability and performance.

  -- Givens Orthogonalization.
     This is a bit slower, but generally much more stable,
     and is really the preferred orthogonalization strategy.
     For a nice description of this, see Chapter 5 of  
     [G. Golub and C. van Loan, Matrix Computations, 3rd edition,
     Johns Hopkins Univ. Press, 1996].


*** Reduction Condition:

  -- LLL: the classical LLL reduction condition.

  -- BKZ: Block Korkin-Zolotarev reduction.
     This is slower, but yields a higher-quality basis,
     i.e., one with shorter vectors.
     See the Schnorr-Euchner paper for a description of this.
     This basically generalizes the LLL reduction condition
     from blocks of size 2 to blocks of larger size.


************* Calling Syntax for LLL routines ***************

long 
[G_]LLL_{FP,QP,XD,RR} (mat_ZZ& B, [ mat_ZZ& U, ] double delta = 0.99, 
                       long deep = 0, LLLCheckFct check = 0, long verbose = 0);

* The [ ... ] notation indicates something optional,
  and the { ... } indicates something that is chosen from
  among several alternatives.

* The return value is the rank of B (but see below if check != 0).

* The optional prefix G_ indicates that Givens rotations are to be used;
  otherwise, classical Gramm-Schmidt is used.

* The choice FP, QP, XD, RR determines the precision used.

* If the optional parameter U is given, then U is computed
  as the transition matrix:

     U * old_B = new_B

* The optional argument "delta" is the reduction parameter, and may
  be set so that 0.50 <= delta < 1.  Setting it close to 1 yields
  shorter vectors, and also improves the stability, but increases the
  running time.  Recommended value: delta = 0.99.

* The optional parameter "deep" can be set to any positive integer,
  which allows "deep insertions" of row k into row i, provided i <=
  deep or k-i <= deep.  Larger values of deep will usually yield
  shorter vectors, but the running increases exponentially.  

  NOTE: use of "deep" is obsolete, and has been "deprecated".
  It is recommended to use BKZ_FP to achieve higher-quality reductions.
  Moreover, the Givens versions do not support "deep", and setting
  deep != 0 will raise an error in this case.

* The optional parameter "check" is a function that is invoked after
  each size reduction with the current row as an argument.  If this
  function returns a non-zero value, the LLL procedure is immediately
  terminated.  Note that it is possible that some linear dependencies
  remain undiscovered, so that the calculated rank value is in fact
  too large.  In any case, zero rows discovered by the algorithm
  will be placed at the beginning, as usual.

  The check argument (if not zero) should be a routine taking
  a const vec_ZZ& as an argument and return value of type long.
  LLLCheckFct is defined via a typedef as:

     typedef long (*LLLCheckFct)(const vec_ZZ&);

  See the file subset.c for an example of the use of this feature.

* The optional parameter "verbose" can be set to see all kinds of fun
  things printed while the routine is executing.  A status report is
  printed every once in a while, and the current basis is optionally
  dumped to a file.  The behavior can be controlled with these global
  variables:

     extern char *LLLDumpFile;  // file to dump basis, 0 => no dump; 
                                // initially 0

     extern double LLLStatusInterval; // seconds between status reports 
                                      // initially 900s = 15min



 
************* Calling Syntax for BKZ routines ***************

long 
[G_]BKZ_{FP,QP,QP1,XD,RR} (mat_ZZ& B, [ mat_ZZ& U, ] double delta=0.99,
                          long BlockSize=10, long prune=0, 
                          LLLCheckFct check = 0, long verbose = 0);

These functions are equivalent to the LLL routines above,
except that Block Korkin-Zolotarev reduction is applied.
We describe here only the differences in the calling syntax.

* The optional parameter "BlockSize" specifies the size of the blocks
  in the reduction.  High values yield shorter vectors, but the
  running time increases exponentially with BlockSize.
  BlockSize should be between 2 and the number of rows of B.

* The optional parameter "prune" can be set to any positive number to
  invoke the Volume Heuristic from [Schnorr and Horner, Eurocrypt
  '95].  This can significantly reduce the running time, and hence
  allow much bigger block size, but the quality of the reduction is
  of course not as good in general.  Higher values of prune mean
  better quality, and slower running time.  
  When prune == 0, pruning is disabled.
  Recommended usage: for BlockSize >= 30, set 10 <= prune <= 15.

* The QP1 variant uses quad_float precision to compute Gramm-Schmidt,
  but uses double precision in the search phase of the block reduction
  algorithm.  This seems adequate for most purposes, and is faster
  than QP, which uses quad_float precision uniformly throughout.


******************** How to choose? *********************

I think it is safe to say that nobody really understands
how the LLL algorithm works.  The theoretical analyses are a long way
from describing what "really" happens in practice.  Choosing the best
variant for a certain application ultimately is a matter of trial
and error.

The first thing to try is LLL_FP.
It is the fastest of the routines, and is adequate for many applications.

If there are precision problems, you will most likely get
a warning message, something like "warning--relaxing reduction".
If there are overflow problems, you should get an error message
saying that the numbers are too big.

If either of these happens, the next thing to try is G_LLL_FP,
which uses the somewhat slower, but more stable, Givens rotations.
This approach also has the nice property that the numbers remain
smaller, so there is less chance of an overflow.

If you are still having precision problems with G_LLL_FP,
try LLL_QP or G_LLL_QP, which uses quadratic precision.

If you are still having overflow problems, try LLL_XD or G_LLL_XD.

I haven't yet come across a case where one *really* needs the
extra precision available in the RR variants.

All of the above discussion applies to the BKZ variants as well.
In addition, if you have a matrix with really big entries, you might try 
using G_LLL_FP or LLL_XD first to reduce the sizes of the numbers,
before running one of the BKZ variants.

Also, one shouldn't rule out using the "all integer" LLL routines.
For some highly structured matrices, this is not necessarily
much worse than some of the floating point versions, and can
under certain circumstances even be better.


******************** Implementation notes *********************

For all the floating point variants, I use a "relaxed" size reduction
condition.  Normally in LLL one makes all |\mu_{i,j}| <= 1/2.
However, this can easily lead to infinite loops in floating point arithemetic.
So I use the condition |\mu_{i,j}| <= 1/2 + fudge, where fudge is 
a very small number.  Even with this, one can fall into an infinite loop.
To handle this situation, I added some logic that detects, at quite low cost,
when an infinite loop has been entered.  When that happens, fudge
is replaced by fudge*2, and a warning message "relaxing reduction condition"
is printed.   We may do this relaxation several times.
If fudge gets too big, we give up and abort, except that 
LLL_FP and BKZ_FP make one last attempt to recover:  they try to compute the
Gramm-Schmidt coefficients using RR and continue.  As described above,
if you run into these problems, which you'll see in the error/warning
messages, it is more effective to use the QP and/or Givens variants.

For the Gramm-Schmidt orthogonalization, lots of "bookeeping" is done
to avoid computing the same thing twice.

For the Givens orthogonalization, we cannot do so many bookeeping tricks.
Instead, we "cache" a certain amount of information, which
allows us to avoid computing certain things over and over again.

There are many other hacks and tricks to speed things up even further.
For example, if the matrix elements are small enough to fit in
double precision floating point, the algorithms avoid almost
all big integer arithmetic.  This is done in a dynamic, on-line
fashion, so even if the numbers start out big, whenever they
get small, we automatically switch to floating point arithmetic.

\**************************************************************************/




/**************************************************************************\

                         Other Stuff

\**************************************************************************/



void ComputeGS(const mat_ZZ& B, mat_RR& mu, vec_RR& c);

// Computes Gramm-Schmidt data for B.  Assumes B is an m x n matrix of
// rank m.  Let if { B^*(i) } is the othogonal basis, then c(i) =
// |B^*(i)|^2, and B^*(i) = B(i) - \sum_{j=1}^{i-1} mu(i,j) B^*(j).

void NearVector(vec_ZZ& w, const mat_ZZ& B, const vec_ZZ& a);

// Computes a vector w that is an approximation to the closest vector
// in the lattice spanned by B to a, using the "closest plane"
// algorithm from [Babai, Combinatorica 6:1-13, 1986].  B must be a
// square matrix, and it is assumed that B is already LLL or BKZ
// reduced (the better the reduction the better the approximation).
// Note that arithmetic in RR is used with the current value of
// RR::precision().

// NOTE: Both of these routines use classical Gramm-Schmidt
// orthogonalization.


ntl-6.2.1/doc/LLL.txt000644 000765 000024 00000042201 12377144460 014556 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: LLL SUMMARY: Routines are provided for lattice basis reduction, including both exact-aritmetic variants (slow but sure) and floating-point variants (fast but only approximate). For an introduction to the basics of LLL reduction, see [H. Cohen, A Course in Computational Algebraic Number Theory, Springer, 1993]. The LLL algorithm was introduced in [A. K. Lenstra, H. W. Lenstra, and L. Lovasz, Math. Ann. 261 (1982), 515-534]. \**************************************************************************/ #include /**************************************************************************\ Exact Arithmetic Variants \**************************************************************************/ long LLL(ZZ& det2, mat_ZZ& B, long verbose = 0); long LLL(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long verbose = 0); long LLL(ZZ& det2, mat_ZZ& B, long a, long b, long verbose = 0); long LLL(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose = 0); // performs LLL reduction. // B is an m x n matrix, viewed as m rows of n-vectors. m may be less // than, equal to, or greater than n, and the rows need not be // linearly independent. B is transformed into an LLL-reduced basis, // and the return value is the rank r of B. The first m-r rows of B // are zero. // More specifically, elementary row transformations are performed on // B so that the non-zero rows of new-B form an LLL-reduced basis // for the lattice spanned by the rows of old-B. // The default reduction parameter is delta=3/4, which means // that the squared length of the first non-zero basis vector // is no more than 2^{r-1} times that of the shortest vector in // the lattice. // det2 is calculated as the *square* of the determinant // of the lattice---note that sqrt(det2) is in general an integer // only when r = n. // In the second version, U is set to the transformation matrix, so // that U is a unimodular m x m matrix with U * old-B = new-B. // Note that the first m-r rows of U form a basis (as a lattice) // for the kernel of old-B. // The third and fourth versions allow an arbitrary reduction // parameter delta=a/b, where 1/4 < a/b <= 1, where a and b are positive // integers. // For a basis reduced with parameter delta, the squared length // of the first non-zero basis vector is no more than // 1/(delta-1/4)^{r-1} times that of the shortest vector in the // lattice (see, e.g., the article by Schnorr and Euchner mentioned below). // The algorithm employed here is essentially the one in Cohen's book. // Some variations: long LLL_plus(vec_ZZ& D, mat_ZZ& B, long verbose = 0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long verbose = 0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, long a, long b, long verbose = 0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose = 0); // These are variations that return a bit more information about the // reduced basis. If r is the rank of B, then D is a vector of length // r+1, such that D[0] = 1, and for i = 1..r, D[i]/D[i-1] is equal to // the square of the length of the i-th vector of the Gram-Schmidt basis // corresponding to the (non-zero) rows of the LLL reduced basis B. // In particular, D[r] is equal to the value det2 computed by the // plain LLL routines. /**************************************************************************\ Computing Images and Kernels \**************************************************************************/ long image(ZZ& det2, mat_ZZ& B, long verbose = 0); long image(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long verbose = 0); // This computes the image of B using a "cheap" version of the LLL: // it performs the usual "size reduction", but it only swaps // vectors when linear dependencies are found. // I haven't seen this described in the literature, but it works // fairly well in practice, and can also easily be shown // to run in a reasonable amount of time with reasonably bounded // numbers. // As in the above LLL routines, the return value is the rank r of B, and the // first m-r rows will be zero. U is a unimodular m x m matrix with // U * old-B = new-B. det2 has the same meaning as above. // Note that the first m-r rows of U form a basis (as a lattice) // for the kernel of old-B. // This is a reasonably practical algorithm for computing kernels. // One can also apply image() to the kernel to get somewhat // shorter basis vectors for the kernels (there are no linear // dependencies, but the size reduction may anyway help). // For even shorter kernel basis vectors, on can apply // LLL(). /**************************************************************************\ Finding a vector in a lattice \**************************************************************************/ long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce=0); // This tests if for given A and y, there exists x such that x*A = y; // if so, x is set to a solution, and the value 1 is returned; // otherwise, x is left unchanged, and the value 0 is returned. // The optional parameter reduce controls the 'quality' of the // solution vector; if the rows of A are linearly dependent, // there are many solutions, if there are any at all. // The value of reduce controls the amount of effort that goes // into finding a 'short' solution vector x. // reduce = 0: No particular effort is made to find a short solution. // reduce = 1: A simple 'size reduction' algorithm is run on kernel(A); // this is fast, and may yield somewhat shorter // solutions than the default, but not necessarily // very close at all to optimal. // reduce = 2: the LLL algorithm is run on kernel(A); // this may be significantly slower than the other options, // but yields solutions that are provably close to optimal. // More precisely, if kernel(A) has rank k, // then the squared length of the obtained solution // is no more than max(1, 2^(k-2)) times that of // the optimal solution. This makes use of slight // variation of Babai's approximately nearest vector algorithm. // Of course, if the the rows of A are linearly independent, then // the value of reduce is irrelevant: the solution, if it exists, // is unique. // Note that regardless of the value of reduce, the algorithm // runs in polynomial time, and hence the bit-length of the solution // vector is bounded by a polynomial in the bit-length of the inputs. /**************************************************************************\ Floating Point Variants There are a number of floating point LLL variants available: you can choose the precision, the orthogonalization strategy, and the reduction condition. The wide variety of choices may seem a bit bewildering. See below the discussion "How to choose?". *** Precision: FP -- double QP -- quad_float (quasi quadruple precision) this is useful when roundoff errors can cause problems XD -- xdouble (extended exponent doubles) this is useful when numbers get too big RR -- RR (arbitrary precision floating point) this is useful for large precision and magnitudes Generally speaking, the choice FP will be the fastest, but may be prone to roundoff errors and/or overflow. *** Orthogonalization Strategy: -- Classical Gramm-Schmidt Orthogonalization. This choice uses classical methods for computing the Gramm-Schmidt othogonalization. It is fast but prone to stability problems. This strategy was first proposed by Schnorr and Euchner [C. P. Schnorr and M. Euchner, Proc. Fundamentals of Computation Theory, LNCS 529, pp. 68-85, 1991]. The version implemented here is substantially different, improving both stability and performance. -- Givens Orthogonalization. This is a bit slower, but generally much more stable, and is really the preferred orthogonalization strategy. For a nice description of this, see Chapter 5 of [G. Golub and C. van Loan, Matrix Computations, 3rd edition, Johns Hopkins Univ. Press, 1996]. *** Reduction Condition: -- LLL: the classical LLL reduction condition. -- BKZ: Block Korkin-Zolotarev reduction. This is slower, but yields a higher-quality basis, i.e., one with shorter vectors. See the Schnorr-Euchner paper for a description of this. This basically generalizes the LLL reduction condition from blocks of size 2 to blocks of larger size. ************* Calling Syntax for LLL routines *************** long [G_]LLL_{FP,QP,XD,RR} (mat_ZZ& B, [ mat_ZZ& U, ] double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); * The [ ... ] notation indicates something optional, and the { ... } indicates something that is chosen from among several alternatives. * The return value is the rank of B (but see below if check != 0). * The optional prefix G_ indicates that Givens rotations are to be used; otherwise, classical Gramm-Schmidt is used. * The choice FP, QP, XD, RR determines the precision used. * If the optional parameter U is given, then U is computed as the transition matrix: U * old_B = new_B * The optional argument "delta" is the reduction parameter, and may be set so that 0.50 <= delta < 1. Setting it close to 1 yields shorter vectors, and also improves the stability, but increases the running time. Recommended value: delta = 0.99. * The optional parameter "deep" can be set to any positive integer, which allows "deep insertions" of row k into row i, provided i <= deep or k-i <= deep. Larger values of deep will usually yield shorter vectors, but the running increases exponentially. NOTE: use of "deep" is obsolete, and has been "deprecated". It is recommended to use BKZ_FP to achieve higher-quality reductions. Moreover, the Givens versions do not support "deep", and setting deep != 0 will raise an error in this case. * The optional parameter "check" is a function that is invoked after each size reduction with the current row as an argument. If this function returns a non-zero value, the LLL procedure is immediately terminated. Note that it is possible that some linear dependencies remain undiscovered, so that the calculated rank value is in fact too large. In any case, zero rows discovered by the algorithm will be placed at the beginning, as usual. The check argument (if not zero) should be a routine taking a const vec_ZZ& as an argument and return value of type long. LLLCheckFct is defined via a typedef as: typedef long (*LLLCheckFct)(const vec_ZZ&); See the file subset.c for an example of the use of this feature. * The optional parameter "verbose" can be set to see all kinds of fun things printed while the routine is executing. A status report is printed every once in a while, and the current basis is optionally dumped to a file. The behavior can be controlled with these global variables: extern char *LLLDumpFile; // file to dump basis, 0 => no dump; // initially 0 extern double LLLStatusInterval; // seconds between status reports // initially 900s = 15min ************* Calling Syntax for BKZ routines *************** long [G_]BKZ_{FP,QP,QP1,XD,RR} (mat_ZZ& B, [ mat_ZZ& U, ] double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); These functions are equivalent to the LLL routines above, except that Block Korkin-Zolotarev reduction is applied. We describe here only the differences in the calling syntax. * The optional parameter "BlockSize" specifies the size of the blocks in the reduction. High values yield shorter vectors, but the running time increases exponentially with BlockSize. BlockSize should be between 2 and the number of rows of B. * The optional parameter "prune" can be set to any positive number to invoke the Volume Heuristic from [Schnorr and Horner, Eurocrypt '95]. This can significantly reduce the running time, and hence allow much bigger block size, but the quality of the reduction is of course not as good in general. Higher values of prune mean better quality, and slower running time. When prune == 0, pruning is disabled. Recommended usage: for BlockSize >= 30, set 10 <= prune <= 15. * The QP1 variant uses quad_float precision to compute Gramm-Schmidt, but uses double precision in the search phase of the block reduction algorithm. This seems adequate for most purposes, and is faster than QP, which uses quad_float precision uniformly throughout. ******************** How to choose? ********************* I think it is safe to say that nobody really understands how the LLL algorithm works. The theoretical analyses are a long way from describing what "really" happens in practice. Choosing the best variant for a certain application ultimately is a matter of trial and error. The first thing to try is LLL_FP. It is the fastest of the routines, and is adequate for many applications. If there are precision problems, you will most likely get a warning message, something like "warning--relaxing reduction". If there are overflow problems, you should get an error message saying that the numbers are too big. If either of these happens, the next thing to try is G_LLL_FP, which uses the somewhat slower, but more stable, Givens rotations. This approach also has the nice property that the numbers remain smaller, so there is less chance of an overflow. If you are still having precision problems with G_LLL_FP, try LLL_QP or G_LLL_QP, which uses quadratic precision. If you are still having overflow problems, try LLL_XD or G_LLL_XD. I haven't yet come across a case where one *really* needs the extra precision available in the RR variants. All of the above discussion applies to the BKZ variants as well. In addition, if you have a matrix with really big entries, you might try using G_LLL_FP or LLL_XD first to reduce the sizes of the numbers, before running one of the BKZ variants. Also, one shouldn't rule out using the "all integer" LLL routines. For some highly structured matrices, this is not necessarily much worse than some of the floating point versions, and can under certain circumstances even be better. ******************** Implementation notes ********************* For all the floating point variants, I use a "relaxed" size reduction condition. Normally in LLL one makes all |\mu_{i,j}| <= 1/2. However, this can easily lead to infinite loops in floating point arithemetic. So I use the condition |\mu_{i,j}| <= 1/2 + fudge, where fudge is a very small number. Even with this, one can fall into an infinite loop. To handle this situation, I added some logic that detects, at quite low cost, when an infinite loop has been entered. When that happens, fudge is replaced by fudge*2, and a warning message "relaxing reduction condition" is printed. We may do this relaxation several times. If fudge gets too big, we give up and abort, except that LLL_FP and BKZ_FP make one last attempt to recover: they try to compute the Gramm-Schmidt coefficients using RR and continue. As described above, if you run into these problems, which you'll see in the error/warning messages, it is more effective to use the QP and/or Givens variants. For the Gramm-Schmidt orthogonalization, lots of "bookeeping" is done to avoid computing the same thing twice. For the Givens orthogonalization, we cannot do so many bookeeping tricks. Instead, we "cache" a certain amount of information, which allows us to avoid computing certain things over and over again. There are many other hacks and tricks to speed things up even further. For example, if the matrix elements are small enough to fit in double precision floating point, the algorithms avoid almost all big integer arithmetic. This is done in a dynamic, on-line fashion, so even if the numbers start out big, whenever they get small, we automatically switch to floating point arithmetic. \**************************************************************************/ /**************************************************************************\ Other Stuff \**************************************************************************/ void ComputeGS(const mat_ZZ& B, mat_RR& mu, vec_RR& c); // Computes Gramm-Schmidt data for B. Assumes B is an m x n matrix of // rank m. Let if { B^*(i) } is the othogonal basis, then c(i) = // |B^*(i)|^2, and B^*(i) = B(i) - \sum_{j=1}^{i-1} mu(i,j) B^*(j). void NearVector(vec_ZZ& w, const mat_ZZ& B, const vec_ZZ& a); // Computes a vector w that is an approximation to the closest vector // in the lattice spanned by B to a, using the "closest plane" // algorithm from [Babai, Combinatorica 6:1-13, 1986]. B must be a // square matrix, and it is assumed that B is already LLL or BKZ // reduced (the better the reduction the better the approximation). // Note that arithmetic in RR is used with the current value of // RR::precision(). // NOTE: Both of these routines use classical Gramm-Schmidt // orthogonalization. ntl-6.2.1/doc/RR.cpp.html000644 000765 000024 00000104764 12377144460 015401 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/RR.cpp.html

/**************************************************************************\

MODULE: RR

SUMMARY:

The class RR is used to represent arbitrary-precision floating point
numbers.

The functions in this module guarantee very strong accuracy conditions
which make it easy to reason about the behavior of programs using
these functions.

The arithmetic operations always round their results to p bits, where
p is the current precision.  The current precision can be changed
using RR::SetPrecision(), and can be read using RR::precision().  

The minimum precision that can be set is 53 bits.
The maximum precision is limited only by the word size of the machine.

All arithmetic operations are implemented so that the effect is as if the
result was computed exactly, and then rounded to p bits.  If a number
lies exactly half-way between two p-bit numbers, the "round to even"
rule is used.  So in particular, the computed result will have a relative error
of at most 2^{-p}.


The above rounding rules apply to all arithmetic operations in this
module, except for the following routines:

* The transcendental functions: 
     log, exp, log10, expm1, log1p, pow, sin, cos, ComputePi

* The power function

* The input and ascii to RR conversion functions when using "e"-notation 

For these functions, a very strong accuracy condition is still 
guaranteed: the computed result has a relative error of less than 2^{-p + 1}
(and actually much closer to 2^{-p}).
That is, it is as if the resulted were computed exactly, and then
rounded to one of the two neighboring p-bit numbers (but not necessarily
the closest).

The behavior of all functions in this module is completely platform 
independent: you should get *exactly* the same results on any platform
(the only exception to this rule is the random number generator).

Note that because precision is variable, a number may be computed with
to a high precision p', and then be used as input to an arithmetic operation
when the current precision is p < p'.  
The above accuracy guarantees still apply; in particular, 
no rounding is done until *after* the operation is performed.  

EXAMPLE: If x and y are computed to 200 bits of precision,
and then the precision is set to 100 bits, then x-y will
be computed correctly to 100 bits, even if, say, x and y agree
in their high-order 50 bits.  If x and y had been rounded to
100 bits before the subtraction, then the difference would
only be accurate to 50 bits of precision.

Note that the assignment operator and the copy constructor 
produce *exact* copies of their inputs---they are *never* rounded. 
This is a change in semantics from versions 2.0 and earlier
in which assignment and copy rounded their outputs.
This was deemed a design error and has been changed.

If you want to force rounding to current precision, the easiest
way to do this is with the RR to RR conversion routines:
   conv(x, a);
or
   x = to_RR(a); 
This will round a to current precision and store the result in x.
Note that writing
   x = a + 0;
or
   x = a*1;
also has the same effect.

Unlike IEEE standard floating point, there are no "special values",
like "infinity" or "not a number", nor are there any "denormalized
numbers".  Overflow, underflow, or taking a square root of a negative
number all result in an error being raised.

An RR is represented as a mantissa/exponent pair (x, e), where x is a
ZZ and e is a long.  The real number represented by (x, e) is x * 2^e.
Zero is always represented as (0, 0).  For all other numbers, x is
always odd.


CONVERSIONS AND PROMOTIONS:
The complete set of conversion routines between RR and other types is
documented in the file "conversions.txt". Conversion from any type
to RR always rounds the result to the current precision.

The basic operations also support the notion of "promotions", 
so that they promote a double to an RR.  For example, one can write 
   x = y + 1.5;
where x and y are RR's. One should be aware that these promotions are 
always implemented using the double to RR conversion routine.


SIZE INVARIANT: max(NumBits(x), |e|) < 2^(NTL_BITS_PER_LONG-4)

\**************************************************************************/




#include <NTL/ZZ.h>
#include <NTL/xdouble.h>
#include <NTL/quad_float.h>

class RR {

public:

RR(); // = 0

RR(const RR& a); // copy constructor


explicit RR(double a);  // promotion constructor

RR& operator=(const RR& a); // assignment operator

// NOTE: the copy constructor and assignment operator
// produce exact copies of their inputs, and do not round
// to current precision.  

RR& operator=(double a); // convert and assign

~RR(); // destructor

const ZZ& mantissa() const;  // read the mantissa
long exponent() const;  // read the exponent

static void SetPrecision(long p);
// set current precision to max(p, 53) bits.
// The default is 150

static long precision();  // read current value of precision

static void SetOutputPrecision(long p);
// set the number of output decimal digits to max(p, 1).
// The default is 10

static long OutputPrecision();
// read the current number of output decimal digits


};



/**************************************************************************\

                                  Comparison

\**************************************************************************/



// standard comparison operators:

long operator==(const RR& a, const RR& b);
long operator!=(const RR& a, const RR& b);
long operator<=(const RR& a, const RR& b);
long operator>=(const RR& a, const RR& b);
long operator <(const RR& a, const RR& b);
long operator >(const RR& a, const RR& b);


long IsZero(const RR& a); // test if 0
long IsOne(const RR& a); // test if 1

long sign(const RR& a);  // returns sign of a (+1, -1, 0)
long compare(const RR& a, const RR& b); // returns sign(a-b);

// PROMOTIONS: operators ==, ..., > and function compare
// promote double to RR on (a, b).



/**************************************************************************\

                                  Addition

\**************************************************************************/

// operator notation:

RR operator+(const RR& a, const RR& b);
RR operator-(const RR& a, const RR& b);
RR operator-(const RR& a); // unary -

RR& operator+=(RR& x, const RR& a);
RR& operator+=(RR& x, double a);

RR& operator-=(RR& x, const RR& a);
RR& operator-=(RR& x, double a);

RR& operator++(RR& x);  // prefix
void operator++(RR& x, int);  // postfix

RR& operator--(RR& x);  // prefix
void operator--(RR& x, int);  // postfix


// procedural versions:

void add(RR& z, const RR& a, const RR& b); // z = a+b
void sub(RR& z, const RR& a, const RR& b); // z = a-b
void negate(RR& z, const RR& a); // z = -a

// PROMOTIONS: operators +, -, and procedures add, sub promote double
// to RR on (a, b).

void abs(RR& z, const RR& a); // z = |a|
RR fabs(const RR& a);
RR abs(const RR& a);


/**************************************************************************\

                                  Multiplication

\**************************************************************************/


// operator notation:

RR operator*(const RR& a, const RR& b);

RR& operator*=(RR& x, const RR& a);
RR& operator*=(RR& x, double a);

// procedural versions:


void mul(RR& z, const RR& a, const RR& b); // z = a*b

void sqr(RR& z, const RR& a); // z = a * a
RR sqr(const RR& a);

// PROMOTIONS: operator * and procedure mul promote double to RR on (a, b).


/**************************************************************************\

                               Division

\**************************************************************************/


// operator notation:

RR operator/(const RR& a, const RR& b);

RR& operator/=(RR& x, const RR& a);
RR& operator/=(RR& x, double a);


// procedural versions:


void div(RR& z, const RR& a, const RR& b); z = a/b

void inv(RR& z, const RR& a); // z = 1 / a
RR inv(const RR& a);

// PROMOTIONS: operator / and procedure div promote double to RR on (a, b).



/**************************************************************************\

                       Transcendental functions 

\**************************************************************************/


void exp(RR& res, const RR& x);  // e^x
RR exp(const RR& x);

void log(RR& res, const RR& x); // log(x) (natural log)
RR log(const RR& x);

void log10(RR& res, const RR& x); // log(x)/log(10)
RR log10(const RR& x);

void expm1(RR& res, const RR&  x);
RR expm1(const RR& x);
// e^(x)-1; more accurate than exp(x)-1 when |x| is small

void log1p(RR& res, const RR& x);
RR log1p(const RR& x);
// log(1 + x); more accurate than log(1 + x) when |x| is small

void pow(RR& res, const RR& x, const RR& y);  // x^y
RR pow(const RR& x, const RR& y);

void sin(RR& res, const RR& x);  // sin(x); restriction: |x| < 2^1000
RR sin(const RR& x);

void cos(RR& res, const RR& x);  // cos(x); restriction: |x| < 2^1000
RR cos(const RR& x);

void ComputePi(RR& pi); // approximate pi to current precision
RR ComputePi_RR();


/**************************************************************************\

                         Rounding to integer values        

\**************************************************************************/


/*** RR output ***/

void trunc(RR& z, const RR& a);  // z = a, truncated to 0
RR trunc(const RR& a);

void floor(RR& z, const RR& a);  // z = a, truncated to -infinity
RR floor(const RR& a);

void ceil(RR& z, const RR& a);   // z = a, truncated to +infinity
RR ceil(const RR& a);

void round(RR& z, const RR& a);   // z = a, truncated to nearest integer
RR round(const RR& a);            // ties are rounded to an even integer



/*** ZZ output ***/

void TruncToZZ(ZZ& z, const RR& a);  // z = a, truncated to 0
ZZ TruncToZZ(const RR& a);

void FloorToZZ(ZZ& z, const RR& a);  // z = a, truncated to -infinity
ZZ FloorToZZ(const RR& a);           // same as RR to ZZ conversion

void CeilToZZ(ZZ& z, const RR& a);   // z = a, truncated to +infinity
ZZ CeilToZZ(const ZZ& a);

void RoundToZZ(ZZ& z, const RR& a);   // z = a, truncated to nearest integer
ZZ RoundToZZ(const RR& a);            // ties are rounded to an even integer


/**************************************************************************\

                                 Miscelaneous

\**************************************************************************/


void MakeRR(RR& z, const ZZ& a,  long e);
RR MakeRR(const ZZ& a,  long e);
// z = a*2^e, rounded to current precision

void random(RR& z);
RR random_RR();
// z = pseudo-random number in the range [0,1).
// Note that the behaviour of this function is somewhat platform
// dependent, because the underlying pseudo-ramdom generator is.


void SqrRoot(RR& z, const RR& a); // z = sqrt(a);
RR SqrRoot(const RR& a);
RR sqrt(const RR& a);

void power(RR& z, const RR& a, long e); // z = a^e, e may be negative
RR power(const RR& a, long e);

void power2(RR& z, long e); // z = 2^e, e may be negative
RR power2_RR(long e);


void clear(RR& z);  // z = 0
void set(RR& z);  // z = 1

void swap(RR& a, RR& b);  // swaps a and b (by swapping pointers)



/**************************************************************************\

                               Input/Output
Input Syntax:

<number>: [ "-" ] <unsigned-number>
<unsigned-number>: <dotted-number> [ <e-part> ] | <e-part>
<dotted-number>: <digits> | <digits> "." <digits> | "." <digits> | <digits> "."
<digits>: <digit> <digits> | <digit>
<digit>: "0" | ... | "9"
<e-part>: ( "E" | "e" ) [ "+" | "-" ] <digits>

Examples of valid input:

17 1.5 0.5 .5 5.  -.5  e10 e-10 e+10 1.5e10 .5e10 .5E10

Note that the number of decimal digits of precision that are used
for output can be set to any number p >= 1 by calling
the routine RR::SetOutputPrecision(p).  The default value of p is 10.
The current value of p is returned by a call to RR::OutputPrecision().


\**************************************************************************/



ostream& operator<<(ostream& s, const RR& a);
istream& operator>>(istream& s, RR& x);

/**************************************************************************\


            Specialized routines with explicit precision parameter

These routines take an explicit precision parameter p.  The value of p may be
any positive integer.  All results are computed to *precisely* p bits of
precision, regardless of the current precision (as set by RR::SetPrecision).

These routines are provided both for convenience and for situations where the
computation must be done with a precision that may be less than 53.


\**************************************************************************/




void AddPrec(RR& z, const RR& a, const RR& b, long p); // z = a + b
RR AddPrec(const RR& a, const RR& b, long p);

void SubPrec(RR& z, const RR& a, const RR& b, long p); // z = a - b
RR SubPrec(const RR& a, const RR& b, long p);

void NegatePrec(RR& z, const RR& a, long p); // z = -a
RR NegatePrec(const RR& a, long p);

void AbsPrec(RR& z, const RR& a, long p); // z = |a|
RR AbsPrec(const RR& a, long p);

void MulPrec(RR& z, const RR& a, const RR& b, long p); // z = a*b
RR MulPrec(const RR& a, const RR& b, long p);

void SqrPrec(RR& z, const RR& a, long p); // z = a*a
RR SqrPrec(const RR& a, long p);

void DivPrec(RR& z, const RR& a, const RR& b, long p);  // z = a/b
RR DivPrec(const RR& a, const RR& b, long p);

void InvPrec(RR& z, const RR& a, long p);  // z = 1/a
RR DivPrec(const RR& a, long p);

void SqrRootPrec(RR& z, const RR& a, long p); // z = sqrt(a)
RR SqrRootPrec(const RR& a, long p);

void TruncPrec(RR& z, const RR& a, long p); // z = a, truncated to 0
RR TruncPrec(const RR& a, long p);

void FloorPrec(RR& z, const RR& a, long p); // z = a, truncated to -infinity
RR FloorPrec(const RR& a, long p);

void CeilPrec(RR& z, const RR& a, long p);  // z = a, truncated to +infinity
RR CeilPrec(const RR& a, long p);

void RoundPrec(RR& z, const RR& a, long p); // z = a, 
                                            // truncated to nearest integer,
                                            // ties are roundec to an even 
                                            // integer
RR RoundPrec(const RR& a, long p);

void ConvPrec(RR& z, const RR& a, long p); // z = a
RR ConvPrec(const RR& a, long p);

void ConvPrec(RR& z, const ZZ& a, long p); // z = a
RR ConvPrec(const ZZ& a, long p);

void ConvPrec(RR& z, long a, long p); // z = a
RR ConvPrec(long a, long p);

void ConvPrec(RR& z, int a, long p); // z = a
RR ConvPrec(int a, long p);

void ConvPrec(RR& z, unsigned long a, long p); // z = a
RR ConvPrec(unsigned long a, long p);

void ConvPrec(RR& z, unsigned int a, long p); // z = a 
RR ConvPrec(unsigned int a, long p);

void ConvPrec(RR& z, double a, long p); // z = a
RR ConvPrec(double a, long p);

void ConvPrec(RR& z, const xdouble& a, long p); // z = a
RR ConvPrec(const xdouble& a, long p);

void ConvPrec(RR& z, const quad_float& a, long p); // z = a
RR ConvPrec(const quad_float& a, long p);

void ConvPrec(RR& z, const char *s, long p); // read z from s
RR ConvPrec(const char *s, long p);

void InputPrec(RR& z, istream& s, long p); // read z from s
RR InputPrec(istream& s, long p);

void MakeRRPrec(RR& z, const ZZ& a, long e, long p); // z = a*2^e
RR MakeRRPrec(const ZZ& a, long e, long p);


/**************************************************************************\

COMPATABILITY NOTES: 

 (1)  Prior to version 5.3, the documentation indicated that under certain
      circumstances, the value of the current precision could be directly set
      by setting the variable RR::prec.  Such usage is now considered
      obsolete.  To perform computations using a precision of less than 53
      bits, users should use the specialized routines AddPrec, SubPrec, etc.,
      documented above.

 (2)  The routine RoundToPrecision is obsolete, although for backward
      compatability, it is still declared (in both procedural and function
      forms), and is equivalent to ConvPrec.

 (3)  In versions 2.0 and earlier, the assignment operator and copy
      constructor for the class RR rounded their outputs to the current
      precision.  This is no longer the case:  their outputs are now exact
      copies of their inputs, regardless of the current precision.

\**************************************************************************/


ntl-6.2.1/doc/RR.txt000644 000765 000024 00000040007 12377144460 014460 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: RR SUMMARY: The class RR is used to represent arbitrary-precision floating point numbers. The functions in this module guarantee very strong accuracy conditions which make it easy to reason about the behavior of programs using these functions. The arithmetic operations always round their results to p bits, where p is the current precision. The current precision can be changed using RR::SetPrecision(), and can be read using RR::precision(). The minimum precision that can be set is 53 bits. The maximum precision is limited only by the word size of the machine. All arithmetic operations are implemented so that the effect is as if the result was computed exactly, and then rounded to p bits. If a number lies exactly half-way between two p-bit numbers, the "round to even" rule is used. So in particular, the computed result will have a relative error of at most 2^{-p}. The above rounding rules apply to all arithmetic operations in this module, except for the following routines: * The transcendental functions: log, exp, log10, expm1, log1p, pow, sin, cos, ComputePi * The power function * The input and ascii to RR conversion functions when using "e"-notation For these functions, a very strong accuracy condition is still guaranteed: the computed result has a relative error of less than 2^{-p + 1} (and actually much closer to 2^{-p}). That is, it is as if the resulted were computed exactly, and then rounded to one of the two neighboring p-bit numbers (but not necessarily the closest). The behavior of all functions in this module is completely platform independent: you should get *exactly* the same results on any platform (the only exception to this rule is the random number generator). Note that because precision is variable, a number may be computed with to a high precision p', and then be used as input to an arithmetic operation when the current precision is p < p'. The above accuracy guarantees still apply; in particular, no rounding is done until *after* the operation is performed. EXAMPLE: If x and y are computed to 200 bits of precision, and then the precision is set to 100 bits, then x-y will be computed correctly to 100 bits, even if, say, x and y agree in their high-order 50 bits. If x and y had been rounded to 100 bits before the subtraction, then the difference would only be accurate to 50 bits of precision. Note that the assignment operator and the copy constructor produce *exact* copies of their inputs---they are *never* rounded. This is a change in semantics from versions 2.0 and earlier in which assignment and copy rounded their outputs. This was deemed a design error and has been changed. If you want to force rounding to current precision, the easiest way to do this is with the RR to RR conversion routines: conv(x, a); or x = to_RR(a); This will round a to current precision and store the result in x. Note that writing x = a + 0; or x = a*1; also has the same effect. Unlike IEEE standard floating point, there are no "special values", like "infinity" or "not a number", nor are there any "denormalized numbers". Overflow, underflow, or taking a square root of a negative number all result in an error being raised. An RR is represented as a mantissa/exponent pair (x, e), where x is a ZZ and e is a long. The real number represented by (x, e) is x * 2^e. Zero is always represented as (0, 0). For all other numbers, x is always odd. CONVERSIONS AND PROMOTIONS: The complete set of conversion routines between RR and other types is documented in the file "conversions.txt". Conversion from any type to RR always rounds the result to the current precision. The basic operations also support the notion of "promotions", so that they promote a double to an RR. For example, one can write x = y + 1.5; where x and y are RR's. One should be aware that these promotions are always implemented using the double to RR conversion routine. SIZE INVARIANT: max(NumBits(x), |e|) < 2^(NTL_BITS_PER_LONG-4) \**************************************************************************/ #include #include #include class RR { public: RR(); // = 0 RR(const RR& a); // copy constructor explicit RR(double a); // promotion constructor RR& operator=(const RR& a); // assignment operator // NOTE: the copy constructor and assignment operator // produce exact copies of their inputs, and do not round // to current precision. RR& operator=(double a); // convert and assign ~RR(); // destructor const ZZ& mantissa() const; // read the mantissa long exponent() const; // read the exponent static void SetPrecision(long p); // set current precision to max(p, 53) bits. // The default is 150 static long precision(); // read current value of precision static void SetOutputPrecision(long p); // set the number of output decimal digits to max(p, 1). // The default is 10 static long OutputPrecision(); // read the current number of output decimal digits }; /**************************************************************************\ Comparison \**************************************************************************/ // standard comparison operators: long operator==(const RR& a, const RR& b); long operator!=(const RR& a, const RR& b); long operator<=(const RR& a, const RR& b); long operator>=(const RR& a, const RR& b); long operator <(const RR& a, const RR& b); long operator >(const RR& a, const RR& b); long IsZero(const RR& a); // test if 0 long IsOne(const RR& a); // test if 1 long sign(const RR& a); // returns sign of a (+1, -1, 0) long compare(const RR& a, const RR& b); // returns sign(a-b); // PROMOTIONS: operators ==, ..., > and function compare // promote double to RR on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: RR operator+(const RR& a, const RR& b); RR operator-(const RR& a, const RR& b); RR operator-(const RR& a); // unary - RR& operator+=(RR& x, const RR& a); RR& operator+=(RR& x, double a); RR& operator-=(RR& x, const RR& a); RR& operator-=(RR& x, double a); RR& operator++(RR& x); // prefix void operator++(RR& x, int); // postfix RR& operator--(RR& x); // prefix void operator--(RR& x, int); // postfix // procedural versions: void add(RR& z, const RR& a, const RR& b); // z = a+b void sub(RR& z, const RR& a, const RR& b); // z = a-b void negate(RR& z, const RR& a); // z = -a // PROMOTIONS: operators +, -, and procedures add, sub promote double // to RR on (a, b). void abs(RR& z, const RR& a); // z = |a| RR fabs(const RR& a); RR abs(const RR& a); /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: RR operator*(const RR& a, const RR& b); RR& operator*=(RR& x, const RR& a); RR& operator*=(RR& x, double a); // procedural versions: void mul(RR& z, const RR& a, const RR& b); // z = a*b void sqr(RR& z, const RR& a); // z = a * a RR sqr(const RR& a); // PROMOTIONS: operator * and procedure mul promote double to RR on (a, b). /**************************************************************************\ Division \**************************************************************************/ // operator notation: RR operator/(const RR& a, const RR& b); RR& operator/=(RR& x, const RR& a); RR& operator/=(RR& x, double a); // procedural versions: void div(RR& z, const RR& a, const RR& b); z = a/b void inv(RR& z, const RR& a); // z = 1 / a RR inv(const RR& a); // PROMOTIONS: operator / and procedure div promote double to RR on (a, b). /**************************************************************************\ Transcendental functions \**************************************************************************/ void exp(RR& res, const RR& x); // e^x RR exp(const RR& x); void log(RR& res, const RR& x); // log(x) (natural log) RR log(const RR& x); void log10(RR& res, const RR& x); // log(x)/log(10) RR log10(const RR& x); void expm1(RR& res, const RR& x); RR expm1(const RR& x); // e^(x)-1; more accurate than exp(x)-1 when |x| is small void log1p(RR& res, const RR& x); RR log1p(const RR& x); // log(1 + x); more accurate than log(1 + x) when |x| is small void pow(RR& res, const RR& x, const RR& y); // x^y RR pow(const RR& x, const RR& y); void sin(RR& res, const RR& x); // sin(x); restriction: |x| < 2^1000 RR sin(const RR& x); void cos(RR& res, const RR& x); // cos(x); restriction: |x| < 2^1000 RR cos(const RR& x); void ComputePi(RR& pi); // approximate pi to current precision RR ComputePi_RR(); /**************************************************************************\ Rounding to integer values \**************************************************************************/ /*** RR output ***/ void trunc(RR& z, const RR& a); // z = a, truncated to 0 RR trunc(const RR& a); void floor(RR& z, const RR& a); // z = a, truncated to -infinity RR floor(const RR& a); void ceil(RR& z, const RR& a); // z = a, truncated to +infinity RR ceil(const RR& a); void round(RR& z, const RR& a); // z = a, truncated to nearest integer RR round(const RR& a); // ties are rounded to an even integer /*** ZZ output ***/ void TruncToZZ(ZZ& z, const RR& a); // z = a, truncated to 0 ZZ TruncToZZ(const RR& a); void FloorToZZ(ZZ& z, const RR& a); // z = a, truncated to -infinity ZZ FloorToZZ(const RR& a); // same as RR to ZZ conversion void CeilToZZ(ZZ& z, const RR& a); // z = a, truncated to +infinity ZZ CeilToZZ(const ZZ& a); void RoundToZZ(ZZ& z, const RR& a); // z = a, truncated to nearest integer ZZ RoundToZZ(const RR& a); // ties are rounded to an even integer /**************************************************************************\ Miscelaneous \**************************************************************************/ void MakeRR(RR& z, const ZZ& a, long e); RR MakeRR(const ZZ& a, long e); // z = a*2^e, rounded to current precision void random(RR& z); RR random_RR(); // z = pseudo-random number in the range [0,1). // Note that the behaviour of this function is somewhat platform // dependent, because the underlying pseudo-ramdom generator is. void SqrRoot(RR& z, const RR& a); // z = sqrt(a); RR SqrRoot(const RR& a); RR sqrt(const RR& a); void power(RR& z, const RR& a, long e); // z = a^e, e may be negative RR power(const RR& a, long e); void power2(RR& z, long e); // z = 2^e, e may be negative RR power2_RR(long e); void clear(RR& z); // z = 0 void set(RR& z); // z = 1 void swap(RR& a, RR& b); // swaps a and b (by swapping pointers) /**************************************************************************\ Input/Output Input Syntax: : [ "-" ] : [ ] | : | "." | "." | "." : | : "0" | ... | "9" : ( "E" | "e" ) [ "+" | "-" ] Examples of valid input: 17 1.5 0.5 .5 5. -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10 Note that the number of decimal digits of precision that are used for output can be set to any number p >= 1 by calling the routine RR::SetOutputPrecision(p). The default value of p is 10. The current value of p is returned by a call to RR::OutputPrecision(). \**************************************************************************/ ostream& operator<<(ostream& s, const RR& a); istream& operator>>(istream& s, RR& x); /**************************************************************************\ Specialized routines with explicit precision parameter These routines take an explicit precision parameter p. The value of p may be any positive integer. All results are computed to *precisely* p bits of precision, regardless of the current precision (as set by RR::SetPrecision). These routines are provided both for convenience and for situations where the computation must be done with a precision that may be less than 53. \**************************************************************************/ void AddPrec(RR& z, const RR& a, const RR& b, long p); // z = a + b RR AddPrec(const RR& a, const RR& b, long p); void SubPrec(RR& z, const RR& a, const RR& b, long p); // z = a - b RR SubPrec(const RR& a, const RR& b, long p); void NegatePrec(RR& z, const RR& a, long p); // z = -a RR NegatePrec(const RR& a, long p); void AbsPrec(RR& z, const RR& a, long p); // z = |a| RR AbsPrec(const RR& a, long p); void MulPrec(RR& z, const RR& a, const RR& b, long p); // z = a*b RR MulPrec(const RR& a, const RR& b, long p); void SqrPrec(RR& z, const RR& a, long p); // z = a*a RR SqrPrec(const RR& a, long p); void DivPrec(RR& z, const RR& a, const RR& b, long p); // z = a/b RR DivPrec(const RR& a, const RR& b, long p); void InvPrec(RR& z, const RR& a, long p); // z = 1/a RR DivPrec(const RR& a, long p); void SqrRootPrec(RR& z, const RR& a, long p); // z = sqrt(a) RR SqrRootPrec(const RR& a, long p); void TruncPrec(RR& z, const RR& a, long p); // z = a, truncated to 0 RR TruncPrec(const RR& a, long p); void FloorPrec(RR& z, const RR& a, long p); // z = a, truncated to -infinity RR FloorPrec(const RR& a, long p); void CeilPrec(RR& z, const RR& a, long p); // z = a, truncated to +infinity RR CeilPrec(const RR& a, long p); void RoundPrec(RR& z, const RR& a, long p); // z = a, // truncated to nearest integer, // ties are roundec to an even // integer RR RoundPrec(const RR& a, long p); void ConvPrec(RR& z, const RR& a, long p); // z = a RR ConvPrec(const RR& a, long p); void ConvPrec(RR& z, const ZZ& a, long p); // z = a RR ConvPrec(const ZZ& a, long p); void ConvPrec(RR& z, long a, long p); // z = a RR ConvPrec(long a, long p); void ConvPrec(RR& z, int a, long p); // z = a RR ConvPrec(int a, long p); void ConvPrec(RR& z, unsigned long a, long p); // z = a RR ConvPrec(unsigned long a, long p); void ConvPrec(RR& z, unsigned int a, long p); // z = a RR ConvPrec(unsigned int a, long p); void ConvPrec(RR& z, double a, long p); // z = a RR ConvPrec(double a, long p); void ConvPrec(RR& z, const xdouble& a, long p); // z = a RR ConvPrec(const xdouble& a, long p); void ConvPrec(RR& z, const quad_float& a, long p); // z = a RR ConvPrec(const quad_float& a, long p); void ConvPrec(RR& z, const char *s, long p); // read z from s RR ConvPrec(const char *s, long p); void InputPrec(RR& z, istream& s, long p); // read z from s RR InputPrec(istream& s, long p); void MakeRRPrec(RR& z, const ZZ& a, long e, long p); // z = a*2^e RR MakeRRPrec(const ZZ& a, long e, long p); /**************************************************************************\ COMPATABILITY NOTES: (1) Prior to version 5.3, the documentation indicated that under certain circumstances, the value of the current precision could be directly set by setting the variable RR::prec. Such usage is now considered obsolete. To perform computations using a precision of less than 53 bits, users should use the specialized routines AddPrec, SubPrec, etc., documented above. (2) The routine RoundToPrecision is obsolete, although for backward compatability, it is still declared (in both procedural and function forms), and is equivalent to ConvPrec. (3) In versions 2.0 and earlier, the assignment operator and copy constructor for the class RR rounded their outputs to the current precision. This is no longer the case: their outputs are now exact copies of their inputs, regardless of the current precision. \**************************************************************************/ ntl-6.2.1/doc/ZZ.cpp.html000644 000765 000024 00000156727 12377144460 015427 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZ.cpp.html

/**************************************************************************\

MODULE: ZZ

SUMMARY:

The class ZZ is used to represent signed, arbitrary length integers.

Routines are provided for all of the basic arithmetic operations, as
well as for some more advanced operations such as primality testing.
Space is automatically managed by the constructors and destructors.

This module also provides routines for generating small primes, and
fast routines for performing modular arithmetic on single-precision
numbers.


\**************************************************************************/

#include <NTL/tools.h>


class ZZ {
public:


   ZZ(); // initial value is 0

   ZZ(const ZZ& a);  // copy constructor
   explicit ZZ(long a);  // promotion constructor

   ~ZZ(); // destructor

   ZZ& operator=(const ZZ& a);  // assignment operator
   ZZ& operator=(long a);

   // typedefs to aid in generic programming
   typedef ZZ_p residue_type;
   typedef ZZX poly_type;


   // ...

};


// NOTE: A ZZ is represented as a sequence of "zzigits",
// where each zzigit is between 0 and 2^{NTL_ZZ_NBITS-1}.

// NTL_ZZ_NBITS is  macros defined in <NTL/ZZ.h>.

// SIZE INVARIANT: the number of bits in a ZZ is always less than
// 2^(NTL_BITS_PER_LONG-4).



/**************************************************************************\

                                 Comparison

\**************************************************************************/



// The usual comparison operators: 

long operator==(const ZZ& a, const ZZ& b);
long operator!=(const ZZ& a, const ZZ& b);
long operator<(const ZZ& a, const ZZ& b);
long operator>(const ZZ& a, const ZZ& b);
long operator<=(const ZZ& a, const ZZ& b);
long operator>=(const ZZ& a, const ZZ& b);

// other stuff:

long sign(const ZZ& a); // returns sign of a (-1, 0, +1)
long IsZero(const ZZ& a); // test for 0
long IsOne(const ZZ& a); // test for 1

long compare(const ZZ& a, const ZZ& b); // returns sign of a-b (-1, 0, or 1).

// PROMOTIONS: the comparison operators and the function compare
// support promotion from long to ZZ on (a, b).


/**************************************************************************\

                                 Addition

\**************************************************************************/


// operator notation:

ZZ operator+(const ZZ& a, const ZZ& b);
ZZ operator-(const ZZ& a, const ZZ& b);
ZZ operator-(const ZZ& a); // unary -

ZZ& operator+=(ZZ& x, const ZZ& a);
ZZ& operator+=(ZZ& x, long a);

ZZ& operator-=(ZZ& x, const ZZ& a);
ZZ& operator-=(ZZ& x, long a);

ZZ& operator++(ZZ& x);  // prefix
void operator++(ZZ& x, int);  // postfix

ZZ& operator--(ZZ& x);  // prefix
void operator--(ZZ& x, int);  // postfix



// procedural versions:

void add(ZZ& x, const ZZ& a, const ZZ& b); // x = a + b
void sub(ZZ& x, const ZZ& a, const ZZ& b); // x = a - b
void SubPos(ZZ& x, const ZZ& a, const ZZ& b); // x = a-b; assumes a >= b >= 0.
void negate(ZZ& x, const ZZ& a); // x = -a

void abs(ZZ& x, const ZZ& a); // x = |a|
ZZ abs(const ZZ& a);

// PROMOTIONS: binary +, -, as well as the procedural versions add, sub
// support promotions from long to ZZ on (a, b).


/**************************************************************************\

                             Multiplication

\**************************************************************************/

// operator notation:

ZZ operator*(const ZZ& a, const ZZ& b);

ZZ& operator*=(ZZ& x, const ZZ& a);
ZZ& operator*=(ZZ& x, long a);

// procedural versions:

void mul(ZZ& x, const ZZ& a, const ZZ& b); // x = a * b

void sqr(ZZ& x, const ZZ& a); // x = a*a
ZZ sqr(const ZZ& a);

// PROMOTIONS: operator * and procedure mul support promotion
// from long to ZZ on (a, b).

/**************************************************************************\

                            Combined Multiply and Add 

\**************************************************************************/


void MulAddTo(ZZ& x, const ZZ& a, const ZZ& b); // x += a*b
void MulAddTo(ZZ& x, const ZZ& a, long b);      // x += a*b


void MulSubFrom(ZZ& x, const ZZ& a, const ZZ& b); // x -= a*b
void MulSubFrom(ZZ& x, const ZZ& a, long b);      // x -= a*b

// NOTE: these are provided for both convenience and efficiency.
// The single-precision versions may be significantly
// faster than the code sequence 
//   mul(tmp, a, b); add(x, x, tmp);



/**************************************************************************\

                                 Division

\**************************************************************************/


// operator notation:

ZZ operator/(const ZZ& a, const ZZ& b);
ZZ operator/(const ZZ& a, long  b);

ZZ operator%(const ZZ& a, const ZZ& b);
long operator%(const ZZ& a, long b);

ZZ& operator/=(ZZ& x, const ZZ& b);
ZZ& operator/=(ZZ& x, long b);

ZZ& operator%=(ZZ& x, const ZZ& b);


// procedural versions:

void DivRem(ZZ& q, ZZ& r, const ZZ& a, const ZZ& b);
// q = floor(a/b), r = a - b*q.
// This implies that:
//    |r| < |b|, and if r != 0, sign(r) = sign(b)

void div(ZZ& q, const ZZ& a, const ZZ& b);
// q = floor(a/b)

void rem(ZZ& r, const ZZ& a, const ZZ& b);
// q = floor(a/b), r = a - b*q


// single-precision variants:

long DivRem(ZZ& q, const ZZ& a, long b);
// q = floor(a/b), r = a - b*q, return value is r.

long rem(const ZZ& a, long b);
// q = floor(a/b), r = a - b*q, return value is r.


// divisibility testing:

long divide(ZZ& q, const ZZ& a, const ZZ& b);
long divide(ZZ& q, const ZZ& a, long b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0.

long divide(const ZZ& a, const ZZ& b);
long divide(const ZZ& a, long b);
// if b | a, returns 1; otherwise returns 0.


/**************************************************************************\

                                    GCD's

\**************************************************************************/


void GCD(ZZ& d, const ZZ& a, const ZZ& b);
ZZ GCD(const ZZ& a, const ZZ& b);

// d = gcd(a, b) (which is always non-negative).  Uses a binary GCD
// algorithm.



void XGCD(ZZ& d, ZZ& s, ZZ& t, const ZZ& a, const ZZ& b);

//  d = gcd(a, b) = a*s + b*t.

// The coefficients s and t are defined according to the standard
// Euclidean algorithm applied to |a| and |b|, with the signs then
// adjusted according to the signs of a and b.

// The implementation may or may not Euclid's algorithm,
// but the coefficients a and t are always computed as if 
// it did.


// special-purpose single-precision variants:

long GCD(long a, long b);
// return value is gcd(a, b) (which is always non-negative)

void XGCD(long& d, long& s, long& t, long a, long b);
//  d = gcd(a, b) = a*s + b*t.

//  The coefficients s and t are defined according to the standard
//  Euclidean algorithm applied to |a| and |b|, with the signs then
//  adjusted according to the signs of a and b.



/**************************************************************************\

                             Modular Arithmetic

The following routines perform arithmetic mod n, where n > 1.

All arguments (other than exponents) are assumed to be in the range
0..n-1.  Some routines may check this and raise an error if this
does not hold.  Others may not, and the behaviour is unpredictable
in this case.

\**************************************************************************/



void AddMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a+b)%n
ZZ AddMod(const ZZ& a, const ZZ& b, const ZZ& n);

void SubMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a-b)%n
ZZ SubMod(const ZZ& a, const ZZ& b, const ZZ& n);

void NegateMod(ZZ& x, const ZZ& a, const ZZ& n); // x = -a % n
ZZ NegateMod(const ZZ& a, const ZZ& n);

void MulMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a*b)%n
ZZ MulMod(const ZZ& a, const ZZ& b, const ZZ& n);

void SqrMod(ZZ& x, const ZZ& a, const ZZ& n); // x = a^2 % n
ZZ SqrMod(const ZZ& a, const ZZ& n);

void InvMod(ZZ& x, const ZZ& a, const ZZ& n);
ZZ InvMod(const ZZ& a, const ZZ& n);
// x = a^{-1} mod n (0 <= x < n); error is raised occurs if inverse
// not defined

long InvModStatus(ZZ& x, const ZZ& a, const ZZ& n);
// if gcd(a,b) = 1, then return-value = 0, x = a^{-1} mod n;
// otherwise, return-value = 1, x = gcd(a, n)

void PowerMod(ZZ& x, const ZZ& a, const ZZ& e, const ZZ& n);
ZZ PowerMod(const ZZ& a, const ZZ& e, const ZZ& n);

void PowerMod(ZZ& x, const ZZ& a, long e, const ZZ& n);
ZZ PowerMod(const ZZ& a, long e, const ZZ& n);

// x = a^e % n (e may be negative)


// PROMOTIONS: AddMod, SubMod, and MulMod (both procedural and functional
// forms) support promotions from long to ZZ on (a, b).


/**************************************************************************\

                        Single-precision modular arithmetic

These routines implement single-precision modular arithmetic.  If n is
the modulus, all inputs should be in the range 0..n-1.  The number n
itself should be in the range 2..NTL_SP_BOUND-1.

Most of these routines are, of course, implemented as fast inline
functions.  No checking is done that inputs are in range.

\**************************************************************************/




long AddMod(long a, long b, long n); // return (a+b)%n

long SubMod(long a, long b, long n); // return (a-b)%n

long NegateMod(long a, long n); // return (-a)%n

long MulMod(long a, long b, long n); // return (a*b)%n

long MulMod(long a, long b, long n, double ninv);
// return (a*b)%n.  ninv = 1/((double) n).  This is faster if n is
// fixed for many multiplications.


long MulMod2(long a, long b, long n, double bninv);
// return (a*b)%n.  bninv = ((double) b)/((double) n).  This is faster
// if both n and b are fixed for many multiplications.
// Note: This is OBSOLETE -- use MulModPrecon (see below) for 
// better performance.


long MulDivRem(long& q, long a, long b, long n, double bninv);
// return (a*b)%n, set q = (a*b)/n.  bninv = ((double) b)/((double) n)

long InvMod(long a, long n);
// computes a^{-1} mod n.  Error is raised if undefined.

long PowerMod(long a, long e, long n);
// computes a^e mod n (e may be negative)



// The following are variants of MulMod2 above that may be significantly 
// faster on certain machines.  The implmentation varies depending
// on the settings of the flags NTL_SPMM_ULL and NTL_SPMM_UL.
// By default (no flags), the implementation is the same as MulMod2 above.
// It is best to let the Wizard script select the optimal flag.

typedef mulmod_precon_t  /*  depends on implementation */ ;

mulmod_precon_t PrepMulModPrecon(long b, long n, double ninv);
// Prepares preconditioning. ninv = 1/((double) n)

long MulModPrecon(long a, long b, long n, mulmod_precon_t bninv);
// return (a*b)%n.  bninv = MulModPrecon(b, n, ninv).

// Example of use:
//    long a, b, n, c;
//      ...
//    double ninv = 1/((double) n);
//    mulmod_precon_t bninv = PrepMulModPrecon(b, n, ninv);
//     ...
//    c = MulModPrecon(a, b, n, bninv);  // c = (a*b) % n



// The following are vector versions of the MulMod routines
// They each compute x[i] = (a[i] * b[i])% n   i = 0..k-1 

void VectorMulMod(long k, long *x, const long *a, long b, long n);

void VectorMulMod(long k, long *x, const long *a, long b, long n,
                  double ninv);
// ninv == 1/((double) n)

void VectorMulModPrecon(long k, long *x, const long *a, long b, long n,
                        mulmod_precon_t bninv);
// bninv == MulModPrecon(b, n, ninv)





/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by 2^n
RightShift by n means division by 2^n, with truncation toward zero
  (so the sign is preserved).

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

ZZ operator<<(const ZZ& a, long n);
ZZ operator>>(const ZZ& a, long n);

ZZ& operator<<=(ZZ& x, long n);
ZZ& operator>>=(ZZ& x, long n);

// procedural versions:

void LeftShift(ZZ& x, const ZZ& a, long n);
ZZ LeftShift(const ZZ& a, long n);

void RightShift(ZZ& x, const ZZ& a, long n);
ZZ RightShift(const ZZ& a, long n);



/**************************************************************************\

                              Bits and Bytes

\**************************************************************************/



long MakeOdd(ZZ& x);
// removes factors of 2 from x, returns the number of 2's removed
// returns 0 if x == 0

long NumTwos(const ZZ& x);
// returns max e such that 2^e divides x if x != 0, and returns 0 if x == 0.

long IsOdd(const ZZ& a); // test if a is odd

long NumBits(const ZZ& a);
long NumBits(long a);
// returns the number of bits in binary represenation of |a|; 
// NumBits(0) = 0


long bit(const ZZ& a, long k);
long bit(long a, long k);
// returns bit k of |a|, position 0 being the low-order bit.
// If  k < 0 or k >= NumBits(a), returns 0.


void trunc(ZZ& x, const ZZ& a, long k);
// x = low order k bits of |a|. 
// If k <= 0, x = 0.

// two functional variants:
ZZ trunc_ZZ(const ZZ& a, long k);
long trunc_long(const ZZ& a, long k);

long SetBit(ZZ& x, long p);
// returns original value of p-th bit of |a|, and replaces p-th bit of
// a by 1 if it was zero; low order bit is bit 0; error if p < 0;
// the sign of x is maintained

long SwitchBit(ZZ& x, long p);
// returns original value of p-th bit of |a|, and switches the value
// of p-th bit of a; low order bit is bit 0; error if p < 0
// the sign of x is maintained

long weight(const ZZ& a); // returns Hamming weight of |a|
long weight(long a);

// bit-wise Boolean operations, procedural form:

void bit_and(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| AND |b|
void bit_or(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| OR |b|
void bit_xor(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| XOR |b|

// bit-wise Boolean operations, operator notation:

ZZ operator&(const ZZ& a, const ZZ& b);
ZZ operator|(const ZZ& a, const ZZ& b);
ZZ operator^(const ZZ& a, const ZZ& b);

// PROMOTIONS: the above bit-wise operations (both procedural 
// and operator forms) provide promotions from long to ZZ on (a, b).

ZZ& operator&=(ZZ& x, const ZZ& b);
ZZ& operator&=(ZZ& x, long b);

ZZ& operator|=(ZZ& x, const ZZ& b);
ZZ& operator|=(ZZ& x, long b);

ZZ& operator^=(ZZ& x, const ZZ& b);
ZZ& operator^=(ZZ& x, long b);



// conversions between byte sequences and ZZ's

void ZZFromBytes(ZZ& x, const unsigned char *p, long n);
ZZ ZZFromBytes(const unsigned char *p, long n);
// x = sum(p[i]*256^i, i=0..n-1). 
// NOTE: in the unusual event that a char is more than 8 bits, 
//       only the low order 8 bits of p[i] are used

void BytesFromZZ(unsigned char *p, const ZZ& a, long n);
// Computes p[0..n-1] such that abs(a) == sum(p[i]*256^i, i=0..n-1) mod 256^n.

long NumBytes(const ZZ& a);
long NumBytes(long a);
// returns # of base 256 digits needed to represent abs(a).
// NumBytes(0) == 0.



/**************************************************************************\

                            Pseudo-Random Numbers

\**************************************************************************/


// Routines for generating pseudo-random numbers.

// These routines generate high qualtity, cryptographically strong
// pseudo-random numbers.  They are implemented so that their behaviour
// is completely independent of the underlying hardware and long 
// integer implementation.  Note, however, that other routines 
// throughout NTL use pseudo-random numbers, and because of this,
// the word size of the machine can impact the sequence of numbers
// seen by a client program.


void SetSeed(const ZZ& s);
// Initializes generator with a "seed" s.
// s is first hashed to generate the initial state, so it is
// not necessary that s itself looks random, just that 
// it has a lot of "entropy".
// If SetSeed is not called before using the routines below,
// a default initial state is used.
// Calling SetSeed with s == 0, e.g. SetSeed(ZZ::zero()), 
// has the effect of re-setting the state to the default initial state.
// Routine ZZFromBytes (above) may be useful.


void RandomBnd(ZZ& x, const ZZ& n);
ZZ RandomBnd(const ZZ& n);
long RandomBnd(long n);
// x = pseudo-random number in the range 0..n-1, or 0 if n <= 0

void RandomBits(ZZ& x, long l);
ZZ RandomBits_ZZ(long l);
long RandomBits_long(long l);
// x = pseudo-random number in the range 0..2^l-1.

void RandomLen(ZZ& x, long l);
ZZ RandomLen_ZZ(long l);
long RandomLen_long(long l);
// x = psuedo-random number with precisely l bits,
// or 0 of l <= 0.

unsigned long RandomBits_ulong(long l);
// returns a pseudo-random number in the range 0..2^l-1

unsigned long RandomWord();
// returns a word filled with pseudo-random bits.
// Equivalent to RandomBits_ulong(NTL_BITS_PER_LONG).


/**************************************************************************\

             Incremental Chinese Remaindering

\**************************************************************************/

long CRT(ZZ& a, ZZ& p, const ZZ& A, const ZZ& P);
long CRT(ZZ& a, ZZ& p, long A, long P);

// 0 <= A < P, (p, P) = 1; computes a' such that a' = a mod p, 
// a' = A mod P, and -p*P/2 < a' <= p*P/2; sets a := a', p := p*P, and
// returns 1 if a's value has changed, otherwise 0


/**************************************************************************\

                  Rational Reconstruction

\**************************************************************************/

long ReconstructRational(ZZ& a, ZZ& b, const ZZ& x, const ZZ& m,
                         const ZZ& a_bound, const ZZ& b_bound);

// 0 <= x < m, m > 2 * a_bound * b_bound,
// a_bound >= 0, b_bound > 0

// This routine either returns 0, leaving a and b unchanged, 
// or returns 1 and sets a and b so that
//   (1) a = b x (mod m),
//   (2) |a| <= a_bound, 0 < b <= b_bound, and
//   (3) gcd(m, b) = gcd(a, b).

// If there exist a, b satisfying (1), (2), and 
//   (3') gcd(m, b) = 1,
// then a, b are uniquely determined if we impose the additional
// condition that gcd(a, b) = 1;  moreover, if such a, b exist,
// then these values are returned by the routine.

// Unless the calling routine can *a priori* guarantee the existence
// of a, b satisfying (1), (2), and (3'),
// then to ensure correctness, the calling routine should check
// that gcd(m, b) = 1, or equivalently, gcd(a, b) = 1.

// This is implemented using a variant of Lehmer's extended
// Euclidean algorithm.

// Literature:  see G. Collins and M. Encarnacion, J. Symb. Comp. 20:287-297, 
// 1995; P. Wang, M. Guy, and J. Davenport, SIGSAM Bulletin 16:2-3, 1982. 


/**************************************************************************\

                                Primality Testing 
                           and Prime Number Generation

\**************************************************************************/

void GenPrime(ZZ& n, long l, long err = 80);
ZZ GenPrime_ZZ(long l, long err = 80);
long GenPrime_long(long l, long err = 80);

// GenPrime generates a random prime n of length l so that the
// probability that the resulting n is composite is bounded by 2^(-err).
// This calls the routine RandomPrime below, and uses results of 
// Damgard, Landrock, Pomerance to "optimize" 
// the number of Miller-Rabin trials at the end.

void GenGermainPrime(ZZ& n, long l, long err = 80);
ZZ GenGermainPrime_ZZ(long l, long err = 80);
long GenGermainPrime_long(long l, long err = 80);

// A (Sophie) Germain prime is a prime p such that p' = 2*p+1 is also a prime.
// Such primes are useful for cryptographic applications...cryptographers
// sometimes call p' a "strong" or "safe" prime.
// GenGermainPrime generates a random Germain prime n of length l
// so that the probability that either n or 2*n+1 is not a prime
// is bounded by 2^(-err).


long ProbPrime(const ZZ& n, long NumTrials = 10);
long ProbPrime(long n, long NumTrials = 10);
// performs up to NumTrials Miller-witness tests (after some trial division).

void RandomPrime(ZZ& n, long l, long NumTrials=10);
ZZ RandomPrime_ZZ(long l, long NumTrials=10);
long RandomPrime_long(long l, long NumTrials=10);
// n = random l-bit prime.  Uses ProbPrime with NumTrials.

void NextPrime(ZZ& n, const ZZ& m, long NumTrials=10);
ZZ NextPrime(const ZZ& m, long NumTrials=10);
// n = smallest prime >= m.  Uses ProbPrime with NumTrials.

long NextPrime(long m, long NumTrials=10);
// Single precision version of the above.
// Result will always be bounded by NTL_ZZ_SP_BOUND, and an
// error is raised if this cannot be satisfied.

long MillerWitness(const ZZ& n, const ZZ& w);
// Tests if w is a witness to compositeness a la Miller.  Assumption: n is
// odd and positive, 0 <= w < n.
// Return value of 1 implies n is composite.
// Return value of 0 indicates n might be prime.


/**************************************************************************\

                               Exponentiation

\**************************************************************************/


void power(ZZ& x, const ZZ& a, long e); // x = a^e (e >= 0)
ZZ power(const ZZ& a, long e);

void power(ZZ& x, long a, long e);

// two functional variants:
ZZ power_ZZ(long a, long e);
long power_long(long a, long e);

void power2(ZZ& x, long e); // x = 2^e (e >= 0)
ZZ power2_ZZ(long e);


/**************************************************************************\

                               Square Roots

\**************************************************************************/


void SqrRoot(ZZ& x, const ZZ& a); // x = floor(a^{1/2}) (a >= 0)
ZZ SqrRoot(const ZZ& a);

long SqrRoot(long a);




/**************************************************************************\

                    Jacobi symbol and modular square roots

\**************************************************************************/


long Jacobi(const ZZ& a, const ZZ& n);
//  compute Jacobi symbol of a and n; assumes 0 <= a < n, n odd

void SqrRootMod(ZZ& x, const ZZ& a, const ZZ& n);
ZZ SqrRootMod(const ZZ& a, const ZZ& n);
//  computes square root of a mod n; assumes n is an odd prime, and
//  that a is a square mod n, with 0 <= a < n.




/**************************************************************************\

                             Input/Output

I/O Format:

Numbers are written in base 10, with an optional minus sign.

\**************************************************************************/

istream& operator>>(istream& s, ZZ& x);
ostream& operator<<(ostream& s, const ZZ& a);



/**************************************************************************\

                            Miscellany

\**************************************************************************/


// The following macros are defined:

#define NTL_ZZ_NBITS (...)  // number of bits in a zzigit;
                            // a ZZ is represented as a sequence of zzigits.

#define NTL_SP_NBITS (...)  // max number of bits in a "single-precision" number

#define NTL_WSP_NBITS (...)  // max number of bits in a "wide single-precision"
                             // number

// The following relations hold:
//    NTL_SP_NBITS <= NTL_WSP_NBITS <= NTL_ZZ_NBITS
//    26 <= NTL_SP_NBITS <= min(NTL_BITS_PER_LONG-2, NTL_DOUBLE_PRECISION-3)
//    NTL_WSP_NBITS <= NTL_BITS_PER_LONG-2
//
// Note that NTL_ZZ_NBITS may be less than, equal to, or greater than
// NTL_BITS_PER_LONG  -- no particular relationship should be assumed to hold.
// In particular, expressions like (1L << NTL_ZZ_BITS) might overflow.
//
// "single-precision" numbers are meant to be used in conjunction with the
//  single-precision modular arithmetic routines.
//
// "wide single-precision" numbers are meant to be used in conjunction
//  with the ZZ arithmetic routines for optimal efficiency.

// The following auxilliary macros are also defined

#define NTL_FRADIX (...) // double-precision value of 2^NTL_ZZ_NBITS

#define NTL_SP_BOUND (1L << NTL_SP_NBITS)
#define NTL_WSP_BOUND (1L << NTL_WSP_NBITS)


// Backward compatability note:
// Prior to version 5.0, the macro NTL_NBITS was defined,
// along with the macro NTL_RADIX defined to be (1L << NTL_NBITS).
// While these macros are still available when using NTL's traditional 
// long integer package (i.e., when NTL_GMP_LIP is not set), 
// they are not available when using the GMP as the primary long integer 
// package (i.e., when NTL_GMP_LIP is set).
// Furthermore, when writing portable programs, one should avoid these macros.
// Note that when using traditional long integer arithmetic, we have
//    NTL_ZZ_NBITS = NTL_SP_NBITS = NTL_WSP_NBITS = NTL_NBITS.


// Here are some additional functions.

void clear(ZZ& x); // x = 0
void set(ZZ& x);   // x = 1

void swap(ZZ& x, ZZ& y);
// swap x and y (done by "pointer swapping", if possible).

double log(const ZZ& a);
// returns double precision approximation to log(a)

long NextPowerOfTwo(long m);
// returns least nonnegative k such that 2^k >= m

long ZZ::size() const;
// a.size() returns the number of zzigits of |a|; the
// size of 0 is 0.

void ZZ::SetSize(long k)
// a.SetSize(k) does not change the value of a, but simply pre-allocates
// space for k zzigits.

long ZZ::SinglePrecision() const;
// a.SinglePrecision() is a predicate that tests if abs(a) < NTL_SP_BOUND

long ZZ::WideSinglePrecision() const;
// a.WideSinglePrecision() is a predicate that tests if abs(a) < NTL_WSP_BOUND

long digit(const ZZ& a, long k);
// returns k-th zzigit of |a|, position 0 being the low-order
// zzigit.
// NOTE: this routine is only available when using NTL's traditional
// long integer arithmetic, and should not be used in programs
// that are meant to be portable.

void ZZ::kill();
// a.kill() sets a to zero and frees the space held by a.

ZZ::ZZ(INIT_SIZE_TYPE, long k);
// ZZ(INIT_SIZE, k) initializes to 0, but space is pre-allocated so
// that numbers x with x.size() <= k can be stored without
// re-allocation.

static const ZZ& ZZ::zero();
// ZZ::zero() yields a read-only reference to zero, if you need it.




/**************************************************************************\

                    Small Prime Generation

primes are generated in sequence, starting at 2, and up to a maximum
that is no more than min(NTL_SP_BOUND, 2^30).

Example: print the primes up to 1000

#include <NTL/ZZ.h>

main()
{
   PrimeSeq s;
   long p;

   p = s.next();
   while (p <= 1000) {
      cout << p << "\n";
      p = s.next();
   }
}

\**************************************************************************/



class PrimeSeq {
public:
   PrimeSeq();
   ~PrimeSeq();

   long next();
   // returns next prime in the sequence.  returns 0 if list of small
   // primes is exhausted.

   void reset(long b);
   // resets generator so that the next prime in the sequence is the
   // smallest prime >= b.

private:
   PrimeSeq(const PrimeSeq&);        // disabled
   void operator=(const PrimeSeq&);  // disabled

};


ntl-6.2.1/doc/ZZ.txt000644 000765 000024 00000064634 12377144460 014514 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZ SUMMARY: The class ZZ is used to represent signed, arbitrary length integers. Routines are provided for all of the basic arithmetic operations, as well as for some more advanced operations such as primality testing. Space is automatically managed by the constructors and destructors. This module also provides routines for generating small primes, and fast routines for performing modular arithmetic on single-precision numbers. \**************************************************************************/ #include class ZZ { public: ZZ(); // initial value is 0 ZZ(const ZZ& a); // copy constructor explicit ZZ(long a); // promotion constructor ~ZZ(); // destructor ZZ& operator=(const ZZ& a); // assignment operator ZZ& operator=(long a); // typedefs to aid in generic programming typedef ZZ_p residue_type; typedef ZZX poly_type; // ... }; // NOTE: A ZZ is represented as a sequence of "zzigits", // where each zzigit is between 0 and 2^{NTL_ZZ_NBITS-1}. // NTL_ZZ_NBITS is macros defined in . // SIZE INVARIANT: the number of bits in a ZZ is always less than // 2^(NTL_BITS_PER_LONG-4). /**************************************************************************\ Comparison \**************************************************************************/ // The usual comparison operators: long operator==(const ZZ& a, const ZZ& b); long operator!=(const ZZ& a, const ZZ& b); long operator<(const ZZ& a, const ZZ& b); long operator>(const ZZ& a, const ZZ& b); long operator<=(const ZZ& a, const ZZ& b); long operator>=(const ZZ& a, const ZZ& b); // other stuff: long sign(const ZZ& a); // returns sign of a (-1, 0, +1) long IsZero(const ZZ& a); // test for 0 long IsOne(const ZZ& a); // test for 1 long compare(const ZZ& a, const ZZ& b); // returns sign of a-b (-1, 0, or 1). // PROMOTIONS: the comparison operators and the function compare // support promotion from long to ZZ on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ operator+(const ZZ& a, const ZZ& b); ZZ operator-(const ZZ& a, const ZZ& b); ZZ operator-(const ZZ& a); // unary - ZZ& operator+=(ZZ& x, const ZZ& a); ZZ& operator+=(ZZ& x, long a); ZZ& operator-=(ZZ& x, const ZZ& a); ZZ& operator-=(ZZ& x, long a); ZZ& operator++(ZZ& x); // prefix void operator++(ZZ& x, int); // postfix ZZ& operator--(ZZ& x); // prefix void operator--(ZZ& x, int); // postfix // procedural versions: void add(ZZ& x, const ZZ& a, const ZZ& b); // x = a + b void sub(ZZ& x, const ZZ& a, const ZZ& b); // x = a - b void SubPos(ZZ& x, const ZZ& a, const ZZ& b); // x = a-b; assumes a >= b >= 0. void negate(ZZ& x, const ZZ& a); // x = -a void abs(ZZ& x, const ZZ& a); // x = |a| ZZ abs(const ZZ& a); // PROMOTIONS: binary +, -, as well as the procedural versions add, sub // support promotions from long to ZZ on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ operator*(const ZZ& a, const ZZ& b); ZZ& operator*=(ZZ& x, const ZZ& a); ZZ& operator*=(ZZ& x, long a); // procedural versions: void mul(ZZ& x, const ZZ& a, const ZZ& b); // x = a * b void sqr(ZZ& x, const ZZ& a); // x = a*a ZZ sqr(const ZZ& a); // PROMOTIONS: operator * and procedure mul support promotion // from long to ZZ on (a, b). /**************************************************************************\ Combined Multiply and Add \**************************************************************************/ void MulAddTo(ZZ& x, const ZZ& a, const ZZ& b); // x += a*b void MulAddTo(ZZ& x, const ZZ& a, long b); // x += a*b void MulSubFrom(ZZ& x, const ZZ& a, const ZZ& b); // x -= a*b void MulSubFrom(ZZ& x, const ZZ& a, long b); // x -= a*b // NOTE: these are provided for both convenience and efficiency. // The single-precision versions may be significantly // faster than the code sequence // mul(tmp, a, b); add(x, x, tmp); /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ operator/(const ZZ& a, const ZZ& b); ZZ operator/(const ZZ& a, long b); ZZ operator%(const ZZ& a, const ZZ& b); long operator%(const ZZ& a, long b); ZZ& operator/=(ZZ& x, const ZZ& b); ZZ& operator/=(ZZ& x, long b); ZZ& operator%=(ZZ& x, const ZZ& b); // procedural versions: void DivRem(ZZ& q, ZZ& r, const ZZ& a, const ZZ& b); // q = floor(a/b), r = a - b*q. // This implies that: // |r| < |b|, and if r != 0, sign(r) = sign(b) void div(ZZ& q, const ZZ& a, const ZZ& b); // q = floor(a/b) void rem(ZZ& r, const ZZ& a, const ZZ& b); // q = floor(a/b), r = a - b*q // single-precision variants: long DivRem(ZZ& q, const ZZ& a, long b); // q = floor(a/b), r = a - b*q, return value is r. long rem(const ZZ& a, long b); // q = floor(a/b), r = a - b*q, return value is r. // divisibility testing: long divide(ZZ& q, const ZZ& a, const ZZ& b); long divide(ZZ& q, const ZZ& a, long b); // if b | a, sets q = a/b and returns 1; otherwise returns 0. long divide(const ZZ& a, const ZZ& b); long divide(const ZZ& a, long b); // if b | a, returns 1; otherwise returns 0. /**************************************************************************\ GCD's \**************************************************************************/ void GCD(ZZ& d, const ZZ& a, const ZZ& b); ZZ GCD(const ZZ& a, const ZZ& b); // d = gcd(a, b) (which is always non-negative). Uses a binary GCD // algorithm. void XGCD(ZZ& d, ZZ& s, ZZ& t, const ZZ& a, const ZZ& b); // d = gcd(a, b) = a*s + b*t. // The coefficients s and t are defined according to the standard // Euclidean algorithm applied to |a| and |b|, with the signs then // adjusted according to the signs of a and b. // The implementation may or may not Euclid's algorithm, // but the coefficients a and t are always computed as if // it did. // special-purpose single-precision variants: long GCD(long a, long b); // return value is gcd(a, b) (which is always non-negative) void XGCD(long& d, long& s, long& t, long a, long b); // d = gcd(a, b) = a*s + b*t. // The coefficients s and t are defined according to the standard // Euclidean algorithm applied to |a| and |b|, with the signs then // adjusted according to the signs of a and b. /**************************************************************************\ Modular Arithmetic The following routines perform arithmetic mod n, where n > 1. All arguments (other than exponents) are assumed to be in the range 0..n-1. Some routines may check this and raise an error if this does not hold. Others may not, and the behaviour is unpredictable in this case. \**************************************************************************/ void AddMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a+b)%n ZZ AddMod(const ZZ& a, const ZZ& b, const ZZ& n); void SubMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a-b)%n ZZ SubMod(const ZZ& a, const ZZ& b, const ZZ& n); void NegateMod(ZZ& x, const ZZ& a, const ZZ& n); // x = -a % n ZZ NegateMod(const ZZ& a, const ZZ& n); void MulMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a*b)%n ZZ MulMod(const ZZ& a, const ZZ& b, const ZZ& n); void SqrMod(ZZ& x, const ZZ& a, const ZZ& n); // x = a^2 % n ZZ SqrMod(const ZZ& a, const ZZ& n); void InvMod(ZZ& x, const ZZ& a, const ZZ& n); ZZ InvMod(const ZZ& a, const ZZ& n); // x = a^{-1} mod n (0 <= x < n); error is raised occurs if inverse // not defined long InvModStatus(ZZ& x, const ZZ& a, const ZZ& n); // if gcd(a,b) = 1, then return-value = 0, x = a^{-1} mod n; // otherwise, return-value = 1, x = gcd(a, n) void PowerMod(ZZ& x, const ZZ& a, const ZZ& e, const ZZ& n); ZZ PowerMod(const ZZ& a, const ZZ& e, const ZZ& n); void PowerMod(ZZ& x, const ZZ& a, long e, const ZZ& n); ZZ PowerMod(const ZZ& a, long e, const ZZ& n); // x = a^e % n (e may be negative) // PROMOTIONS: AddMod, SubMod, and MulMod (both procedural and functional // forms) support promotions from long to ZZ on (a, b). /**************************************************************************\ Single-precision modular arithmetic These routines implement single-precision modular arithmetic. If n is the modulus, all inputs should be in the range 0..n-1. The number n itself should be in the range 2..NTL_SP_BOUND-1. Most of these routines are, of course, implemented as fast inline functions. No checking is done that inputs are in range. \**************************************************************************/ long AddMod(long a, long b, long n); // return (a+b)%n long SubMod(long a, long b, long n); // return (a-b)%n long NegateMod(long a, long n); // return (-a)%n long MulMod(long a, long b, long n); // return (a*b)%n long MulMod(long a, long b, long n, double ninv); // return (a*b)%n. ninv = 1/((double) n). This is faster if n is // fixed for many multiplications. long MulMod2(long a, long b, long n, double bninv); // return (a*b)%n. bninv = ((double) b)/((double) n). This is faster // if both n and b are fixed for many multiplications. // Note: This is OBSOLETE -- use MulModPrecon (see below) for // better performance. long MulDivRem(long& q, long a, long b, long n, double bninv); // return (a*b)%n, set q = (a*b)/n. bninv = ((double) b)/((double) n) long InvMod(long a, long n); // computes a^{-1} mod n. Error is raised if undefined. long PowerMod(long a, long e, long n); // computes a^e mod n (e may be negative) // The following are variants of MulMod2 above that may be significantly // faster on certain machines. The implmentation varies depending // on the settings of the flags NTL_SPMM_ULL and NTL_SPMM_UL. // By default (no flags), the implementation is the same as MulMod2 above. // It is best to let the Wizard script select the optimal flag. typedef mulmod_precon_t /* depends on implementation */ ; mulmod_precon_t PrepMulModPrecon(long b, long n, double ninv); // Prepares preconditioning. ninv = 1/((double) n) long MulModPrecon(long a, long b, long n, mulmod_precon_t bninv); // return (a*b)%n. bninv = MulModPrecon(b, n, ninv). // Example of use: // long a, b, n, c; // ... // double ninv = 1/((double) n); // mulmod_precon_t bninv = PrepMulModPrecon(b, n, ninv); // ... // c = MulModPrecon(a, b, n, bninv); // c = (a*b) % n // The following are vector versions of the MulMod routines // They each compute x[i] = (a[i] * b[i])% n i = 0..k-1 void VectorMulMod(long k, long *x, const long *a, long b, long n); void VectorMulMod(long k, long *x, const long *a, long b, long n, double ninv); // ninv == 1/((double) n) void VectorMulModPrecon(long k, long *x, const long *a, long b, long n, mulmod_precon_t bninv); // bninv == MulModPrecon(b, n, ninv) /**************************************************************************\ Shift Operations LeftShift by n means multiplication by 2^n RightShift by n means division by 2^n, with truncation toward zero (so the sign is preserved). A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: ZZ operator<<(const ZZ& a, long n); ZZ operator>>(const ZZ& a, long n); ZZ& operator<<=(ZZ& x, long n); ZZ& operator>>=(ZZ& x, long n); // procedural versions: void LeftShift(ZZ& x, const ZZ& a, long n); ZZ LeftShift(const ZZ& a, long n); void RightShift(ZZ& x, const ZZ& a, long n); ZZ RightShift(const ZZ& a, long n); /**************************************************************************\ Bits and Bytes \**************************************************************************/ long MakeOdd(ZZ& x); // removes factors of 2 from x, returns the number of 2's removed // returns 0 if x == 0 long NumTwos(const ZZ& x); // returns max e such that 2^e divides x if x != 0, and returns 0 if x == 0. long IsOdd(const ZZ& a); // test if a is odd long NumBits(const ZZ& a); long NumBits(long a); // returns the number of bits in binary represenation of |a|; // NumBits(0) = 0 long bit(const ZZ& a, long k); long bit(long a, long k); // returns bit k of |a|, position 0 being the low-order bit. // If k < 0 or k >= NumBits(a), returns 0. void trunc(ZZ& x, const ZZ& a, long k); // x = low order k bits of |a|. // If k <= 0, x = 0. // two functional variants: ZZ trunc_ZZ(const ZZ& a, long k); long trunc_long(const ZZ& a, long k); long SetBit(ZZ& x, long p); // returns original value of p-th bit of |a|, and replaces p-th bit of // a by 1 if it was zero; low order bit is bit 0; error if p < 0; // the sign of x is maintained long SwitchBit(ZZ& x, long p); // returns original value of p-th bit of |a|, and switches the value // of p-th bit of a; low order bit is bit 0; error if p < 0 // the sign of x is maintained long weight(const ZZ& a); // returns Hamming weight of |a| long weight(long a); // bit-wise Boolean operations, procedural form: void bit_and(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| AND |b| void bit_or(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| OR |b| void bit_xor(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| XOR |b| // bit-wise Boolean operations, operator notation: ZZ operator&(const ZZ& a, const ZZ& b); ZZ operator|(const ZZ& a, const ZZ& b); ZZ operator^(const ZZ& a, const ZZ& b); // PROMOTIONS: the above bit-wise operations (both procedural // and operator forms) provide promotions from long to ZZ on (a, b). ZZ& operator&=(ZZ& x, const ZZ& b); ZZ& operator&=(ZZ& x, long b); ZZ& operator|=(ZZ& x, const ZZ& b); ZZ& operator|=(ZZ& x, long b); ZZ& operator^=(ZZ& x, const ZZ& b); ZZ& operator^=(ZZ& x, long b); // conversions between byte sequences and ZZ's void ZZFromBytes(ZZ& x, const unsigned char *p, long n); ZZ ZZFromBytes(const unsigned char *p, long n); // x = sum(p[i]*256^i, i=0..n-1). // NOTE: in the unusual event that a char is more than 8 bits, // only the low order 8 bits of p[i] are used void BytesFromZZ(unsigned char *p, const ZZ& a, long n); // Computes p[0..n-1] such that abs(a) == sum(p[i]*256^i, i=0..n-1) mod 256^n. long NumBytes(const ZZ& a); long NumBytes(long a); // returns # of base 256 digits needed to represent abs(a). // NumBytes(0) == 0. /**************************************************************************\ Pseudo-Random Numbers \**************************************************************************/ // Routines for generating pseudo-random numbers. // These routines generate high qualtity, cryptographically strong // pseudo-random numbers. They are implemented so that their behaviour // is completely independent of the underlying hardware and long // integer implementation. Note, however, that other routines // throughout NTL use pseudo-random numbers, and because of this, // the word size of the machine can impact the sequence of numbers // seen by a client program. void SetSeed(const ZZ& s); // Initializes generator with a "seed" s. // s is first hashed to generate the initial state, so it is // not necessary that s itself looks random, just that // it has a lot of "entropy". // If SetSeed is not called before using the routines below, // a default initial state is used. // Calling SetSeed with s == 0, e.g. SetSeed(ZZ::zero()), // has the effect of re-setting the state to the default initial state. // Routine ZZFromBytes (above) may be useful. void RandomBnd(ZZ& x, const ZZ& n); ZZ RandomBnd(const ZZ& n); long RandomBnd(long n); // x = pseudo-random number in the range 0..n-1, or 0 if n <= 0 void RandomBits(ZZ& x, long l); ZZ RandomBits_ZZ(long l); long RandomBits_long(long l); // x = pseudo-random number in the range 0..2^l-1. void RandomLen(ZZ& x, long l); ZZ RandomLen_ZZ(long l); long RandomLen_long(long l); // x = psuedo-random number with precisely l bits, // or 0 of l <= 0. unsigned long RandomBits_ulong(long l); // returns a pseudo-random number in the range 0..2^l-1 unsigned long RandomWord(); // returns a word filled with pseudo-random bits. // Equivalent to RandomBits_ulong(NTL_BITS_PER_LONG). /**************************************************************************\ Incremental Chinese Remaindering \**************************************************************************/ long CRT(ZZ& a, ZZ& p, const ZZ& A, const ZZ& P); long CRT(ZZ& a, ZZ& p, long A, long P); // 0 <= A < P, (p, P) = 1; computes a' such that a' = a mod p, // a' = A mod P, and -p*P/2 < a' <= p*P/2; sets a := a', p := p*P, and // returns 1 if a's value has changed, otherwise 0 /**************************************************************************\ Rational Reconstruction \**************************************************************************/ long ReconstructRational(ZZ& a, ZZ& b, const ZZ& x, const ZZ& m, const ZZ& a_bound, const ZZ& b_bound); // 0 <= x < m, m > 2 * a_bound * b_bound, // a_bound >= 0, b_bound > 0 // This routine either returns 0, leaving a and b unchanged, // or returns 1 and sets a and b so that // (1) a = b x (mod m), // (2) |a| <= a_bound, 0 < b <= b_bound, and // (3) gcd(m, b) = gcd(a, b). // If there exist a, b satisfying (1), (2), and // (3') gcd(m, b) = 1, // then a, b are uniquely determined if we impose the additional // condition that gcd(a, b) = 1; moreover, if such a, b exist, // then these values are returned by the routine. // Unless the calling routine can *a priori* guarantee the existence // of a, b satisfying (1), (2), and (3'), // then to ensure correctness, the calling routine should check // that gcd(m, b) = 1, or equivalently, gcd(a, b) = 1. // This is implemented using a variant of Lehmer's extended // Euclidean algorithm. // Literature: see G. Collins and M. Encarnacion, J. Symb. Comp. 20:287-297, // 1995; P. Wang, M. Guy, and J. Davenport, SIGSAM Bulletin 16:2-3, 1982. /**************************************************************************\ Primality Testing and Prime Number Generation \**************************************************************************/ void GenPrime(ZZ& n, long l, long err = 80); ZZ GenPrime_ZZ(long l, long err = 80); long GenPrime_long(long l, long err = 80); // GenPrime generates a random prime n of length l so that the // probability that the resulting n is composite is bounded by 2^(-err). // This calls the routine RandomPrime below, and uses results of // Damgard, Landrock, Pomerance to "optimize" // the number of Miller-Rabin trials at the end. void GenGermainPrime(ZZ& n, long l, long err = 80); ZZ GenGermainPrime_ZZ(long l, long err = 80); long GenGermainPrime_long(long l, long err = 80); // A (Sophie) Germain prime is a prime p such that p' = 2*p+1 is also a prime. // Such primes are useful for cryptographic applications...cryptographers // sometimes call p' a "strong" or "safe" prime. // GenGermainPrime generates a random Germain prime n of length l // so that the probability that either n or 2*n+1 is not a prime // is bounded by 2^(-err). long ProbPrime(const ZZ& n, long NumTrials = 10); long ProbPrime(long n, long NumTrials = 10); // performs up to NumTrials Miller-witness tests (after some trial division). void RandomPrime(ZZ& n, long l, long NumTrials=10); ZZ RandomPrime_ZZ(long l, long NumTrials=10); long RandomPrime_long(long l, long NumTrials=10); // n = random l-bit prime. Uses ProbPrime with NumTrials. void NextPrime(ZZ& n, const ZZ& m, long NumTrials=10); ZZ NextPrime(const ZZ& m, long NumTrials=10); // n = smallest prime >= m. Uses ProbPrime with NumTrials. long NextPrime(long m, long NumTrials=10); // Single precision version of the above. // Result will always be bounded by NTL_ZZ_SP_BOUND, and an // error is raised if this cannot be satisfied. long MillerWitness(const ZZ& n, const ZZ& w); // Tests if w is a witness to compositeness a la Miller. Assumption: n is // odd and positive, 0 <= w < n. // Return value of 1 implies n is composite. // Return value of 0 indicates n might be prime. /**************************************************************************\ Exponentiation \**************************************************************************/ void power(ZZ& x, const ZZ& a, long e); // x = a^e (e >= 0) ZZ power(const ZZ& a, long e); void power(ZZ& x, long a, long e); // two functional variants: ZZ power_ZZ(long a, long e); long power_long(long a, long e); void power2(ZZ& x, long e); // x = 2^e (e >= 0) ZZ power2_ZZ(long e); /**************************************************************************\ Square Roots \**************************************************************************/ void SqrRoot(ZZ& x, const ZZ& a); // x = floor(a^{1/2}) (a >= 0) ZZ SqrRoot(const ZZ& a); long SqrRoot(long a); /**************************************************************************\ Jacobi symbol and modular square roots \**************************************************************************/ long Jacobi(const ZZ& a, const ZZ& n); // compute Jacobi symbol of a and n; assumes 0 <= a < n, n odd void SqrRootMod(ZZ& x, const ZZ& a, const ZZ& n); ZZ SqrRootMod(const ZZ& a, const ZZ& n); // computes square root of a mod n; assumes n is an odd prime, and // that a is a square mod n, with 0 <= a < n. /**************************************************************************\ Input/Output I/O Format: Numbers are written in base 10, with an optional minus sign. \**************************************************************************/ istream& operator>>(istream& s, ZZ& x); ostream& operator<<(ostream& s, const ZZ& a); /**************************************************************************\ Miscellany \**************************************************************************/ // The following macros are defined: #define NTL_ZZ_NBITS (...) // number of bits in a zzigit; // a ZZ is represented as a sequence of zzigits. #define NTL_SP_NBITS (...) // max number of bits in a "single-precision" number #define NTL_WSP_NBITS (...) // max number of bits in a "wide single-precision" // number // The following relations hold: // NTL_SP_NBITS <= NTL_WSP_NBITS <= NTL_ZZ_NBITS // 26 <= NTL_SP_NBITS <= min(NTL_BITS_PER_LONG-2, NTL_DOUBLE_PRECISION-3) // NTL_WSP_NBITS <= NTL_BITS_PER_LONG-2 // // Note that NTL_ZZ_NBITS may be less than, equal to, or greater than // NTL_BITS_PER_LONG -- no particular relationship should be assumed to hold. // In particular, expressions like (1L << NTL_ZZ_BITS) might overflow. // // "single-precision" numbers are meant to be used in conjunction with the // single-precision modular arithmetic routines. // // "wide single-precision" numbers are meant to be used in conjunction // with the ZZ arithmetic routines for optimal efficiency. // The following auxilliary macros are also defined #define NTL_FRADIX (...) // double-precision value of 2^NTL_ZZ_NBITS #define NTL_SP_BOUND (1L << NTL_SP_NBITS) #define NTL_WSP_BOUND (1L << NTL_WSP_NBITS) // Backward compatability note: // Prior to version 5.0, the macro NTL_NBITS was defined, // along with the macro NTL_RADIX defined to be (1L << NTL_NBITS). // While these macros are still available when using NTL's traditional // long integer package (i.e., when NTL_GMP_LIP is not set), // they are not available when using the GMP as the primary long integer // package (i.e., when NTL_GMP_LIP is set). // Furthermore, when writing portable programs, one should avoid these macros. // Note that when using traditional long integer arithmetic, we have // NTL_ZZ_NBITS = NTL_SP_NBITS = NTL_WSP_NBITS = NTL_NBITS. // Here are some additional functions. void clear(ZZ& x); // x = 0 void set(ZZ& x); // x = 1 void swap(ZZ& x, ZZ& y); // swap x and y (done by "pointer swapping", if possible). double log(const ZZ& a); // returns double precision approximation to log(a) long NextPowerOfTwo(long m); // returns least nonnegative k such that 2^k >= m long ZZ::size() const; // a.size() returns the number of zzigits of |a|; the // size of 0 is 0. void ZZ::SetSize(long k) // a.SetSize(k) does not change the value of a, but simply pre-allocates // space for k zzigits. long ZZ::SinglePrecision() const; // a.SinglePrecision() is a predicate that tests if abs(a) < NTL_SP_BOUND long ZZ::WideSinglePrecision() const; // a.WideSinglePrecision() is a predicate that tests if abs(a) < NTL_WSP_BOUND long digit(const ZZ& a, long k); // returns k-th zzigit of |a|, position 0 being the low-order // zzigit. // NOTE: this routine is only available when using NTL's traditional // long integer arithmetic, and should not be used in programs // that are meant to be portable. void ZZ::kill(); // a.kill() sets a to zero and frees the space held by a. ZZ::ZZ(INIT_SIZE_TYPE, long k); // ZZ(INIT_SIZE, k) initializes to 0, but space is pre-allocated so // that numbers x with x.size() <= k can be stored without // re-allocation. static const ZZ& ZZ::zero(); // ZZ::zero() yields a read-only reference to zero, if you need it. /**************************************************************************\ Small Prime Generation primes are generated in sequence, starting at 2, and up to a maximum that is no more than min(NTL_SP_BOUND, 2^30). Example: print the primes up to 1000 #include main() { PrimeSeq s; long p; p = s.next(); while (p <= 1000) { cout << p << "\n"; p = s.next(); } } \**************************************************************************/ class PrimeSeq { public: PrimeSeq(); ~PrimeSeq(); long next(); // returns next prime in the sequence. returns 0 if list of small // primes is exhausted. void reset(long b); // resets generator so that the next prime in the sequence is the // smallest prime >= b. private: PrimeSeq(const PrimeSeq&); // disabled void operator=(const PrimeSeq&); // disabled }; ntl-6.2.1/doc/ZZVec.cpp.html000644 000765 000024 00000007451 12377144460 016052 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZVec.cpp.html

/**************************************************************************\

MODULE: ZZVec

SUMMARY:

The class ZZVec implements vectors of fixed-length ZZ's.  You can
allocate a vector of ZZ's of a specified length, where the maximum
size of each ZZ is also specified.  The size is measured in terms
of the number of zzigits.

These parameters can be specified either with a constructor 
or with SetSize.  It is an error to try to re-size a vector of non-zero length,
or store a ZZ that doesn't fit.  The space can be released with "kill", 
and then you are free to call SetSize again.  

If you want more flexible---but less efficient---vectors, use vec_ZZ.

\**************************************************************************/

#include <NTL/ZZ.h>


class ZZVec {
public:
   ZZVec();

   ZZVec& operator=(const ZZVec&);
   // first kill()'s destination (unless source and destination are
   // identical)

   ZZVec(const ZZVec&);

   ~ZZVec();

   ZZVec(long n, long d);
   // sets length to n and max size of each element to d

   void SetSize(long n, long d);
   // sets length to n and max size of each element to d

   long length() const;
   // length of vector

   long BaseSize() const;
   // max size of each element

   void kill();
   // release space


   ZZ* elts();
   const ZZ* elts() const;
   // pointer to first element

   ZZ& operator[](long i);
   const ZZ& operator[](long i) const;
   // indexing operator; starts at 0; no range checking
};


void swap(ZZVec& x, ZZVec& y);
// swaps x and y by swapping pointers

ntl-6.2.1/doc/ZZVec.txt000644 000765 000024 00000003016 12377144460 015135 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZVec SUMMARY: The class ZZVec implements vectors of fixed-length ZZ's. You can allocate a vector of ZZ's of a specified length, where the maximum size of each ZZ is also specified. The size is measured in terms of the number of zzigits. These parameters can be specified either with a constructor or with SetSize. It is an error to try to re-size a vector of non-zero length, or store a ZZ that doesn't fit. The space can be released with "kill", and then you are free to call SetSize again. If you want more flexible---but less efficient---vectors, use vec_ZZ. \**************************************************************************/ #include class ZZVec { public: ZZVec(); ZZVec& operator=(const ZZVec&); // first kill()'s destination (unless source and destination are // identical) ZZVec(const ZZVec&); ~ZZVec(); ZZVec(long n, long d); // sets length to n and max size of each element to d void SetSize(long n, long d); // sets length to n and max size of each element to d long length() const; // length of vector long BaseSize() const; // max size of each element void kill(); // release space ZZ* elts(); const ZZ* elts() const; // pointer to first element ZZ& operator[](long i); const ZZ& operator[](long i) const; // indexing operator; starts at 0; no range checking }; void swap(ZZVec& x, ZZVec& y); // swaps x and y by swapping pointers ntl-6.2.1/doc/ZZX.cpp.html000644 000765 000024 00000106166 12377144460 015547 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZX.cpp.html


/**************************************************************************\

MODULE: ZZX

SUMMARY:

The class ZZX implements polynomials in ZZ[X], i.e., univariate
polynomials with integer coefficients.

Polynomial multiplication is implemented using one of 4 different
algorithms:

1) classical 

2) Karatsuba

3) Schoenhage & Strassen --- performs an FFT by working
     modulo a "Fermat number" of appropriate size...
     good for polynomials with huge coefficients
     and moderate degree

4) CRT/FFT --- performs an FFT by working modulo several
     small primes...good for polynomials with moderate coefficients
     and huge degree.

The choice of algorithm is somewhat heuristic, and may not always be
perfect.

Many thanks to Juergen Gerhard <jngerhar@plato.uni-paderborn.de> for
pointing out the deficiency in the NTL-1.0 ZZX arithmetic, and for
contributing the Schoenhage/Strassen code.

Extensive use is made of modular algorithms to enhance performance
(e.g., the GCD algorithm and amny others).

\**************************************************************************/

#include <NTL/vec_ZZ.h>
#include "zz_pX.h"
#include <NTL/ZZ_pX.h>


class ZZX {
public:


   ZZX(); // initial value 0

   ZZX(const ZZX& a); // copy
   explicit ZZX(const ZZ& a); // promotion
   explicit ZZX(long a); // promotion

   ~ZZX();

   ZZX(INIT_MONO_TYPE, long i, const ZZ& c);
   ZZX(INIT_MONO_TYPE, long i, long c);
   // initial value c*X^i, invoke as ZZX(INIT_MONO, i, c)

   ZZX(INIT_MONO_TYPE, long i);
   // initial value X^i, invoke as ZZX(INIT_MONO, i)

   ZZX& operator=(const ZZX& a); // assignment
   ZZX& operator=(const ZZ& a);
   ZZX& operator=(long a);

   typedef ZZ coeff_type;

   // ...

};




/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const ZZX& a);  // return deg(a); deg(0) == -1.

const ZZ& coeff(const ZZX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const ZZ& LeadCoeff(const ZZX& a);
// returns leading term of a, or zero if a == 0

const ZZ& ConstTerm(const ZZX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(ZZX& x, long i, const ZZ& a);
void SetCoeff(ZZX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(ZZX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(ZZX& x); // x is set to the monomial X

long IsX(const ZZX& a); // test if x = X




ZZ& ZZX::operator[](long i);
const ZZ& ZZX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void ZZX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void ZZX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void ZZX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.







/**************************************************************************\

                                  Comparison

\**************************************************************************/

long operator==(const ZZX& a, const ZZX& b);
long operator!=(const ZZX& a, const ZZX& b);

long IsZero(const ZZX& a);  // test for 0
long IsOne(const ZZX& a);  // test for 1

// PROMOTIONS: operators ==, != promote {long, ZZ} to ZZX on (a, b).


/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

ZZX operator+(const ZZX& a, const ZZX& b);
ZZX operator-(const ZZX& a, const ZZX& b);
ZZX operator-(const ZZX& a); // unary -

ZZX& operator+=(ZZX& x, const ZZX& a);
ZZX& operator-=(ZZX& x, const ZZX& a);

ZZX& operator++(ZZX& x);  // prefix
void operator++(ZZX& x, int);  // postfix

ZZX& operator--(ZZX& x);  // prefix
void operator--(ZZX& x, int);  // postfix


// procedural versions:

void add(ZZX& x, const ZZX& a, const ZZX& b); // x = a + b
void sub(ZZX& x, const ZZX& a, const ZZX& b); // x = a - b
void negate(ZZX& x, const ZZX& a); // x = -a

// PROMOTIONS: binary +, - and procedures add, sub promote {long, ZZ} 
// to ZZX on (a, b).


/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

ZZX operator*(const ZZX& a, const ZZX& b);

ZZX& operator*=(ZZX& x, const ZZX& a);


// procedural versions:

void mul(ZZX& x, const ZZX& a, const ZZX& b); // x = a * b

void sqr(ZZX& x, const ZZX& a); // x = a^2
ZZX sqr(const ZZX& a);

// PROMOTIONS: operator * and procedure mul promote {long, ZZ} to ZZX 
// on (a, b).


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

ZZX operator<<(const ZZX& a, long n);
ZZX operator>>(const ZZX& a, long n);

ZZX& operator<<=(ZZX& x, long n);
ZZX& operator>>=(ZZX& x, long n);

// procedural versions:

void LeftShift(ZZX& x, const ZZX& a, long n);
ZZX LeftShift(const ZZX& a, long n);

void RightShift(ZZX& x, const ZZX& a, long n);
ZZX RightShift(const ZZX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/


// Given polynomials a, b in ZZ[X], there exist polynomials
// q, r in QQ[X] such that a = b*q + r, deg(r) < deg(b).
// These routines return q and/or r if q and/or r lie(s) in ZZ[X],
// and otherwise raise an error.  

// Note that if the leading coefficient of b is 1 or -1, 
// then q and r always lie in ZZ[X], and no error can occur.

// For example, you can write f/2 for a ZZX f.  If all coefficients
// of f are even, the result is f with a factor of two removed;
// otherwise, an error is raised.  More generally, f/g will be
// evaluate q in ZZ[X] such that f = q*g if such a q exists,
// and will otherwise raise an error.

// See also below the routines for pseudo-division and division
// predicates for routines that are perhaps more useful in
// some situations.


// operator notation: 

ZZX operator/(const ZZX& a, const ZZX& b);
ZZX operator/(const ZZX& a, const ZZ& b);
ZZX operator/(const ZZX& a, long b);

ZZX operator%(const ZZX& a, const ZZX& b);

ZZX& operator/=(ZZX& x, const ZZX& b);
ZZX& operator/=(ZZX& x, const ZZ& b);
ZZX& operator/=(ZZX& x, long b);

ZZX& operator%=(ZZX& x, const ZZX& b);


// procedural versions:

void DivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b);
// computes q, r such that a = b q + r and deg(r) < deg(b).
// requires LeadCoeff(b) is a unit (+1, -1); otherwise,
// an error is raised.

void div(ZZX& q, const ZZX& a, const ZZX& b);
void div(ZZX& q, const ZZX& a, const ZZ& b);
void div(ZZX& q, const ZZX& a, long b);
// same as DivRem, but only computes q

void rem(ZZX& r, const ZZX& a, const ZZX& b);
// same as DivRem, but only computes r



// divide predicates:

long divide(ZZX& q, const ZZX& a, const ZZX& b);
long divide(ZZX& q, const ZZX& a, const ZZ& b);
long divide(ZZX& q, const ZZX& a, long b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


long divide(const ZZX& a, const ZZX& b);
long divide(const ZZX& a, const ZZ& b);
long divide(const ZZX& a, long b);
// if b | a, returns 1; otherwise returns 0

// These algorithms employ a modular approach, performing the division
// modulo small primes (reconstructing q via the CRT).  It is
// usually much faster than the general division routines above
// (especially when b does not divide a).


void content(ZZ& d, const ZZX& f);
ZZ content(const ZZX& f);
// d = content of f, sign(d) == sign(LeadCoeff(f)); content(0) == 0

void PrimitivePart(ZZX& pp, const ZZX& f);
ZZX PrimitivePart(const ZZX& f);
// pp = primitive part of f, LeadCoeff(pp) >= 0; PrimitivePart(0) == 0



// pseudo-division:

void PseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b);
// performs pseudo-division: computes q and r with deg(r) < deg(b),
// and LeadCoeff(b)^(deg(a)-deg(b)+1) a = b q + r.  Only the classical
// algorithm is used.

void PseudoDiv(ZZX& q, const ZZX& a, const ZZX& b);
ZZX PseudoDiv(const ZZX& a, const ZZX& b);
// same as PseudoDivRem, but only computes q

void PseudoRem(ZZX& r, const ZZX& a, const ZZX& b);
ZZX PseudoRem(const ZZX& a, const ZZX& b);
// same as PseudoDivRem, but only computes r


/**************************************************************************\

                                  GCD's

\**************************************************************************/


void GCD(ZZX& d, const ZZX& a, const ZZX& b);
ZZX GCD(const ZZX& a, const ZZX& b);
// d = gcd(a, b), LeadCoeff(d) >= 0.  Uses a modular algorithm.


void XGCD(ZZ& r, ZZX& s, ZZX& t, const ZZX& a, const ZZX& b,
          long deterministic=0);
// r = resultant of a and b; if r != 0, then computes s and t such
// that: a*s + b*t = r; otherwise s and t not affected.  if
// !deterministic, then resultant computation may use a randomized
// strategy that errs with probability no more than 2^{-80}.



/**************************************************************************\

                               Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.


\**************************************************************************/


istream& operator>>(istream& s, ZZX& x);
ostream& operator<<(ostream& s, const ZZX& a);


/**************************************************************************\

                             Some utility routines

\**************************************************************************/


void diff(ZZX& x, const ZZX& a); // x = derivative of a
ZZX diff(const ZZX& a);

long MaxBits(const ZZX& f);
// returns max NumBits of coefficients of f

void reverse(ZZX& x, const ZZX& a, long hi);
ZZX reverse(const ZZX& a, long hi);

void reverse(ZZX& x, const ZZX& a);
ZZX reverse(const ZZX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version


void VectorCopy(vec_ZZ& x, const ZZX& a, long n);
vec_ZZ VectorCopy(const ZZX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.



/**************************************************************************\

                       Arithmetic mod X^n

All routines require n >= 0, otherwise an error is raised.

\**************************************************************************/


void trunc(ZZX& x, const ZZX& a, long m); // x = a % X^m
ZZX trunc(const ZZX& a, long m);

void MulTrunc(ZZX& x, const ZZX& a, const ZZX& b, long n);
ZZX MulTrunc(const ZZX& a, const ZZX& b, long n);
// x = a * b % X^n

void SqrTrunc(ZZX& x, const ZZX& a, long n);
ZZX SqrTrunc(const ZZX& a, long n);
// x = a^2 % X^n

void InvTrunc(ZZX& x, const ZZX& a, long n);
ZZX InvTrunc(const ZZX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.




/**************************************************************************\

                               Modular Arithmetic

The modulus f must be monic with deg(f) > 0, 
and other arguments must have smaller degree.

\**************************************************************************/

void MulMod(ZZX& x, const ZZX& a, const ZZX& b, const ZZX& f);
ZZX MulMod(const ZZX& a, const ZZX& b, const ZZX& f);
// x = a * b mod f

void SqrMod(ZZX& x, const ZZX& a, const ZZX& f);
ZZX SqrMod(const ZZX& a, const ZZX& f);
// x = a^2 mod f

void MulByXMod(ZZX& x, const ZZX& a, const ZZX& f);
ZZX MulByXMod(const ZZX& a, const ZZX& f);
// x = a*X mod f


/**************************************************************************\

                  traces, norms, resultants, discriminants,
                   minimal and characteristic polynomials

\**************************************************************************/


void TraceMod(ZZ& res, const ZZX& a, const ZZX& f);
ZZ TraceMod(const ZZX& a, const ZZX& f);
// res = trace of (a mod f).  f must be monic, 0 < deg(f), deg(a) <
// deg(f)

void TraceVec(vec_ZZ& S, const ZZX& f);
vec_ZZ TraceVec(const ZZX& f);
// S[i] = Trace(X^i mod f), for i = 0..deg(f)-1.
// f must be a monic polynomial.


// The following routines use a modular approach.

void resultant(ZZ& res, const ZZX& a, const ZZX& b, long deterministic=0);
ZZ resultant(const ZZX& a, const ZZX& b, long deterministic=0);
// res = resultant of a and b. If !deterministic, then it may use a
// randomized strategy that errs with probability no more than
// 2^{-80}.



void NormMod(ZZ& res, const ZZX& a, const ZZX& f, long deterministic=0);
ZZ NormMod(const ZZX& a, const ZZX& f, long deterministic=0);
// res = norm of (a mod f).  f must be monic, 0 < deg(f), deg(a) <
// deg(f). If !deterministic, then it may use a randomized strategy
// that errs with probability no more than 2^{-80}.



void discriminant(ZZ& d, const ZZX& a, long deterministic=0);
ZZ discriminant(const ZZX& a, long deterministic=0);
// d = discriminant of a = (-1)^{m(m-1)/2} resultant(a, a')/lc(a),
// where m = deg(a). If !deterministic, then it may use a randomized
// strategy that errs with probability no more than 2^{-80}.


void CharPolyMod(ZZX& g, const ZZX& a, const ZZX& f, long deterministic=0);
ZZX CharPolyMod(const ZZX& a, const ZZX& f, long deterministic=0);
// g = char poly of (a mod f).  f must be monic.  If !deterministic,
// then it may use a randomized strategy that errs with probability no
// more than 2^{-80}.


void MinPolyMod(ZZX& g, const ZZX& a, const ZZX& f);
ZZX MinPolyMod(const ZZX& a, const ZZX& f);
// g = min poly of (a mod f).  f must be monic, 0 < deg(f), deg(a) <
// deg(f).  May use a probabilistic strategy that errs with
// probability no more than 2^{-80}.




/**************************************************************************\

                  Incremental Chinese Remaindering

\**************************************************************************/

long CRT(ZZX& a, ZZ& prod, const zz_pX& A);
long CRT(ZZX& a, ZZ& prod, const ZZ_pX& A);
// Incremental Chinese Remaindering: If p is the current zz_p/ZZ_p modulus with
// (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p,
// with coefficients in the interval (-p*prod/2, p*prod/2]; 
// Sets a := a', prod := p*prod, and returns 1 if a's value changed.





/**************************************************************************\

                                vectors of ZZX's

\**************************************************************************/


typedef Vec<ZZX> vec_ZZX; // backward compatibility


/**************************************************************************\

                                Miscellany


\**************************************************************************/


void clear(ZZX& x); // x = 0
void set(ZZX& x); // x = 1

void ZZX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

ZZX::ZZX(INIT_SIZE_TYPE, long n);
// ZZX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const ZZX& zero();
// ZZX::zero() is a read-only reference to 0

void swap(ZZX& x, ZZX& y);
// swap x & y (by swapping pointers)


ZZX::ZZX(long i, const ZZ& c);
ZZX::ZZX(long i, long c);
// initial value c*X^i, provided for backward compatibility
ntl-6.2.1/doc/ZZX.txt000644 000765 000024 00000041663 12377144460 014641 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZX SUMMARY: The class ZZX implements polynomials in ZZ[X], i.e., univariate polynomials with integer coefficients. Polynomial multiplication is implemented using one of 4 different algorithms: 1) classical 2) Karatsuba 3) Schoenhage & Strassen --- performs an FFT by working modulo a "Fermat number" of appropriate size... good for polynomials with huge coefficients and moderate degree 4) CRT/FFT --- performs an FFT by working modulo several small primes...good for polynomials with moderate coefficients and huge degree. The choice of algorithm is somewhat heuristic, and may not always be perfect. Many thanks to Juergen Gerhard for pointing out the deficiency in the NTL-1.0 ZZX arithmetic, and for contributing the Schoenhage/Strassen code. Extensive use is made of modular algorithms to enhance performance (e.g., the GCD algorithm and amny others). \**************************************************************************/ #include #include "zz_pX.h" #include class ZZX { public: ZZX(); // initial value 0 ZZX(const ZZX& a); // copy explicit ZZX(const ZZ& a); // promotion explicit ZZX(long a); // promotion ~ZZX(); ZZX(INIT_MONO_TYPE, long i, const ZZ& c); ZZX(INIT_MONO_TYPE, long i, long c); // initial value c*X^i, invoke as ZZX(INIT_MONO, i, c) ZZX(INIT_MONO_TYPE, long i); // initial value X^i, invoke as ZZX(INIT_MONO, i) ZZX& operator=(const ZZX& a); // assignment ZZX& operator=(const ZZ& a); ZZX& operator=(long a); typedef ZZ coeff_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const ZZX& a); // return deg(a); deg(0) == -1. const ZZ& coeff(const ZZX& a, long i); // returns the coefficient of X^i, or zero if i not in range const ZZ& LeadCoeff(const ZZX& a); // returns leading term of a, or zero if a == 0 const ZZ& ConstTerm(const ZZX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(ZZX& x, long i, const ZZ& a); void SetCoeff(ZZX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(ZZX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(ZZX& x); // x is set to the monomial X long IsX(const ZZX& a); // test if x = X ZZ& ZZX::operator[](long i); const ZZ& ZZX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void ZZX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void ZZX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void ZZX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZX& a, const ZZX& b); long operator!=(const ZZX& a, const ZZX& b); long IsZero(const ZZX& a); // test for 0 long IsOne(const ZZX& a); // test for 1 // PROMOTIONS: operators ==, != promote {long, ZZ} to ZZX on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZX operator+(const ZZX& a, const ZZX& b); ZZX operator-(const ZZX& a, const ZZX& b); ZZX operator-(const ZZX& a); // unary - ZZX& operator+=(ZZX& x, const ZZX& a); ZZX& operator-=(ZZX& x, const ZZX& a); ZZX& operator++(ZZX& x); // prefix void operator++(ZZX& x, int); // postfix ZZX& operator--(ZZX& x); // prefix void operator--(ZZX& x, int); // postfix // procedural versions: void add(ZZX& x, const ZZX& a, const ZZX& b); // x = a + b void sub(ZZX& x, const ZZX& a, const ZZX& b); // x = a - b void negate(ZZX& x, const ZZX& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub promote {long, ZZ} // to ZZX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZX operator*(const ZZX& a, const ZZX& b); ZZX& operator*=(ZZX& x, const ZZX& a); // procedural versions: void mul(ZZX& x, const ZZX& a, const ZZX& b); // x = a * b void sqr(ZZX& x, const ZZX& a); // x = a^2 ZZX sqr(const ZZX& a); // PROMOTIONS: operator * and procedure mul promote {long, ZZ} to ZZX // on (a, b). /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: ZZX operator<<(const ZZX& a, long n); ZZX operator>>(const ZZX& a, long n); ZZX& operator<<=(ZZX& x, long n); ZZX& operator>>=(ZZX& x, long n); // procedural versions: void LeftShift(ZZX& x, const ZZX& a, long n); ZZX LeftShift(const ZZX& a, long n); void RightShift(ZZX& x, const ZZX& a, long n); ZZX RightShift(const ZZX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // Given polynomials a, b in ZZ[X], there exist polynomials // q, r in QQ[X] such that a = b*q + r, deg(r) < deg(b). // These routines return q and/or r if q and/or r lie(s) in ZZ[X], // and otherwise raise an error. // Note that if the leading coefficient of b is 1 or -1, // then q and r always lie in ZZ[X], and no error can occur. // For example, you can write f/2 for a ZZX f. If all coefficients // of f are even, the result is f with a factor of two removed; // otherwise, an error is raised. More generally, f/g will be // evaluate q in ZZ[X] such that f = q*g if such a q exists, // and will otherwise raise an error. // See also below the routines for pseudo-division and division // predicates for routines that are perhaps more useful in // some situations. // operator notation: ZZX operator/(const ZZX& a, const ZZX& b); ZZX operator/(const ZZX& a, const ZZ& b); ZZX operator/(const ZZX& a, long b); ZZX operator%(const ZZX& a, const ZZX& b); ZZX& operator/=(ZZX& x, const ZZX& b); ZZX& operator/=(ZZX& x, const ZZ& b); ZZX& operator/=(ZZX& x, long b); ZZX& operator%=(ZZX& x, const ZZX& b); // procedural versions: void DivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); // computes q, r such that a = b q + r and deg(r) < deg(b). // requires LeadCoeff(b) is a unit (+1, -1); otherwise, // an error is raised. void div(ZZX& q, const ZZX& a, const ZZX& b); void div(ZZX& q, const ZZX& a, const ZZ& b); void div(ZZX& q, const ZZX& a, long b); // same as DivRem, but only computes q void rem(ZZX& r, const ZZX& a, const ZZX& b); // same as DivRem, but only computes r // divide predicates: long divide(ZZX& q, const ZZX& a, const ZZX& b); long divide(ZZX& q, const ZZX& a, const ZZ& b); long divide(ZZX& q, const ZZX& a, long b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZX& a, const ZZX& b); long divide(const ZZX& a, const ZZ& b); long divide(const ZZX& a, long b); // if b | a, returns 1; otherwise returns 0 // These algorithms employ a modular approach, performing the division // modulo small primes (reconstructing q via the CRT). It is // usually much faster than the general division routines above // (especially when b does not divide a). void content(ZZ& d, const ZZX& f); ZZ content(const ZZX& f); // d = content of f, sign(d) == sign(LeadCoeff(f)); content(0) == 0 void PrimitivePart(ZZX& pp, const ZZX& f); ZZX PrimitivePart(const ZZX& f); // pp = primitive part of f, LeadCoeff(pp) >= 0; PrimitivePart(0) == 0 // pseudo-division: void PseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); // performs pseudo-division: computes q and r with deg(r) < deg(b), // and LeadCoeff(b)^(deg(a)-deg(b)+1) a = b q + r. Only the classical // algorithm is used. void PseudoDiv(ZZX& q, const ZZX& a, const ZZX& b); ZZX PseudoDiv(const ZZX& a, const ZZX& b); // same as PseudoDivRem, but only computes q void PseudoRem(ZZX& r, const ZZX& a, const ZZX& b); ZZX PseudoRem(const ZZX& a, const ZZX& b); // same as PseudoDivRem, but only computes r /**************************************************************************\ GCD's \**************************************************************************/ void GCD(ZZX& d, const ZZX& a, const ZZX& b); ZZX GCD(const ZZX& a, const ZZX& b); // d = gcd(a, b), LeadCoeff(d) >= 0. Uses a modular algorithm. void XGCD(ZZ& r, ZZX& s, ZZX& t, const ZZX& a, const ZZX& b, long deterministic=0); // r = resultant of a and b; if r != 0, then computes s and t such // that: a*s + b*t = r; otherwise s and t not affected. if // !deterministic, then resultant computation may use a randomized // strategy that errs with probability no more than 2^{-80}. /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. \**************************************************************************/ istream& operator>>(istream& s, ZZX& x); ostream& operator<<(ostream& s, const ZZX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(ZZX& x, const ZZX& a); // x = derivative of a ZZX diff(const ZZX& a); long MaxBits(const ZZX& f); // returns max NumBits of coefficients of f void reverse(ZZX& x, const ZZX& a, long hi); ZZX reverse(const ZZX& a, long hi); void reverse(ZZX& x, const ZZX& a); ZZX reverse(const ZZX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_ZZ& x, const ZZX& a, long n); vec_ZZ VectorCopy(const ZZX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Arithmetic mod X^n All routines require n >= 0, otherwise an error is raised. \**************************************************************************/ void trunc(ZZX& x, const ZZX& a, long m); // x = a % X^m ZZX trunc(const ZZX& a, long m); void MulTrunc(ZZX& x, const ZZX& a, const ZZX& b, long n); ZZX MulTrunc(const ZZX& a, const ZZX& b, long n); // x = a * b % X^n void SqrTrunc(ZZX& x, const ZZX& a, long n); ZZX SqrTrunc(const ZZX& a, long n); // x = a^2 % X^n void InvTrunc(ZZX& x, const ZZX& a, long n); ZZX InvTrunc(const ZZX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic The modulus f must be monic with deg(f) > 0, and other arguments must have smaller degree. \**************************************************************************/ void MulMod(ZZX& x, const ZZX& a, const ZZX& b, const ZZX& f); ZZX MulMod(const ZZX& a, const ZZX& b, const ZZX& f); // x = a * b mod f void SqrMod(ZZX& x, const ZZX& a, const ZZX& f); ZZX SqrMod(const ZZX& a, const ZZX& f); // x = a^2 mod f void MulByXMod(ZZX& x, const ZZX& a, const ZZX& f); ZZX MulByXMod(const ZZX& a, const ZZX& f); // x = a*X mod f /**************************************************************************\ traces, norms, resultants, discriminants, minimal and characteristic polynomials \**************************************************************************/ void TraceMod(ZZ& res, const ZZX& a, const ZZX& f); ZZ TraceMod(const ZZX& a, const ZZX& f); // res = trace of (a mod f). f must be monic, 0 < deg(f), deg(a) < // deg(f) void TraceVec(vec_ZZ& S, const ZZX& f); vec_ZZ TraceVec(const ZZX& f); // S[i] = Trace(X^i mod f), for i = 0..deg(f)-1. // f must be a monic polynomial. // The following routines use a modular approach. void resultant(ZZ& res, const ZZX& a, const ZZX& b, long deterministic=0); ZZ resultant(const ZZX& a, const ZZX& b, long deterministic=0); // res = resultant of a and b. If !deterministic, then it may use a // randomized strategy that errs with probability no more than // 2^{-80}. void NormMod(ZZ& res, const ZZX& a, const ZZX& f, long deterministic=0); ZZ NormMod(const ZZX& a, const ZZX& f, long deterministic=0); // res = norm of (a mod f). f must be monic, 0 < deg(f), deg(a) < // deg(f). If !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void discriminant(ZZ& d, const ZZX& a, long deterministic=0); ZZ discriminant(const ZZX& a, long deterministic=0); // d = discriminant of a = (-1)^{m(m-1)/2} resultant(a, a')/lc(a), // where m = deg(a). If !deterministic, then it may use a randomized // strategy that errs with probability no more than 2^{-80}. void CharPolyMod(ZZX& g, const ZZX& a, const ZZX& f, long deterministic=0); ZZX CharPolyMod(const ZZX& a, const ZZX& f, long deterministic=0); // g = char poly of (a mod f). f must be monic. If !deterministic, // then it may use a randomized strategy that errs with probability no // more than 2^{-80}. void MinPolyMod(ZZX& g, const ZZX& a, const ZZX& f); ZZX MinPolyMod(const ZZX& a, const ZZX& f); // g = min poly of (a mod f). f must be monic, 0 < deg(f), deg(a) < // deg(f). May use a probabilistic strategy that errs with // probability no more than 2^{-80}. /**************************************************************************\ Incremental Chinese Remaindering \**************************************************************************/ long CRT(ZZX& a, ZZ& prod, const zz_pX& A); long CRT(ZZX& a, ZZ& prod, const ZZ_pX& A); // Incremental Chinese Remaindering: If p is the current zz_p/ZZ_p modulus with // (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p, // with coefficients in the interval (-p*prod/2, p*prod/2]; // Sets a := a', prod := p*prod, and returns 1 if a's value changed. /**************************************************************************\ vectors of ZZX's \**************************************************************************/ typedef Vec vec_ZZX; // backward compatibility /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZX& x); // x = 0 void set(ZZX& x); // x = 1 void ZZX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). ZZX::ZZX(INIT_SIZE_TYPE, long n); // ZZX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const ZZX& zero(); // ZZX::zero() is a read-only reference to 0 void swap(ZZX& x, ZZX& y); // swap x & y (by swapping pointers) ZZX::ZZX(long i, const ZZ& c); ZZX::ZZX(long i, long c); // initial value c*X^i, provided for backward compatibility ntl-6.2.1/doc/ZZXFactoring.cpp.html000644 000765 000024 00000026645 12377144460 017407 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZXFactoring.cpp.html

/*****************************************************************************\

MODULE: ZZXFactoring

SUMMARY:

Routines are provided for factoring in ZZX.

See IMPLEMENTATION DETAILS below for a discussion of the algorithms used,
and of the flags available for selecting among these algorithms.

\*****************************************************************************/

#include <NTL/ZZX.h>
#include <NTL/pair_ZZX_long.h>

void SquareFreeDecomp(vec_pair_ZZX_long& u, const ZZX& f);
const vector(pair_ZZX_long SquareFreeDecomp(const ZZX& f);

// input is primitive, with positive leading coefficient.  Performs
// square-free decomposition.  If f = prod_i g_i^i, then u is set to a
// lest of pairs (g_i, i).  The list is is increasing order of i, with
// trivial terms (i.e., g_i = 1) deleted.


void MultiLift(vec_ZZX& A, const vec_zz_pX& a, const ZZX& f, long e,
               long verbose=0);

// Using current value p of zz_p::modulus(), this lifts the
// square-free factorization a mod p of f to a factorization A mod p^e
// of f.  It is required that f and all the polynomials in a are
// monic.



void SFFactor(vec_ZZX& factors, const ZZX& f, long verbose=0, long bnd=0);
vec_ZZX SFFactor(const ZZX& f, long verbose=0, long bnd=0);

// input f is primitive and square-free, with positive leading
// coefficient.  bnd, if not zero, indicates that f divides a
// polynomial h whose Euclidean norm is bounded by 2^{bnd} in absolute
// value.  This uses the routine SFCanZass in zz_pXFactoring and then
// performs a MultiLift, followed by a brute-force search for the
// factors.  

// A number of heuristics are used to speed up the factor-search step.
// See "implementation details" below.


void factor(ZZ& c,
            vec_pair_ZZX_long& factors,
            const ZZX& f,
            long verbose=0,
            long bnd=0);

// input f is is an arbitrary polynomial.  c is the content of f, and
// factors is the facrorization of its primitive part.  bnd is as in
// SFFactor.  The routine calls SquareFreeDecomp and SFFactor.

void mul(ZZX& x, const vec_pair_ZZX_long& a);
ZZX mul(const vec_pair_ZZX_long& a);
// multiplies polynomials, with multiplcities.




/*****************************************************************************\

IMPLEMENTATION DETAILS

To factor a polynomial, first its content is extracted, and it is
made squarefree.  This is typically very fast.

Second, a simple hack is performed: if the polynomial is of the
form g(x^l), then an attempt is made to factor g(k^m),
for divisors m of l, which can in some cases greatly simplify
the factorization task.
You can turn this "power hack" on/off by setting the following variable
to 1/0:

   extern long ZZXFac_PowerHack;  // initial value = 1


Third, the polynomial is factored modulo several
small primes, and one small prime p is selected as the "best".
You can choose the number of small primes that you want to use
by setting the following variable:

   extern long ZZXFac_InitNumPrimes;  // initial value = 7

Fourth, The factorization mod p is "lifted" to a factorization mod p^k
for a sufficiently large k.  This is done via quadratic Hensel
lifting.  Despite "folk wisdom" to the contrary, this is much
more efficient than linear Hensel lifting, especially since NTL
has very fast polynomial arithmetic.

After the "lifting phase" comes the "factor recombination phase".
The factorization mod p^k may be "finer" than the true factorization
over the integers, hence we have to "combine" subsets of modular factors
and test if these are factors over the integers.

There are two basic strategies:  the "Zassenhaus" method
and the "van Hoeij" method.

The van Hoeij method:

The van Hoeij method is fairly new, but it is so much better than
the older, Zassenhaus method, that it is now the default.
For a description of the method, go to Mark van Hoeij's home page:

   http://www.openmath.org/~hoeij/

The van Hoeij method is not really a specific algorithm, but a general
algorithmic approach: many parameters and strategies have to be selected
to obtain a specific algorithm, and it is a challenge to
make all of these choices so that the resulting algorithm works
fairly well on all input polynomials.

Set the following variable to 1 to enable the van Hoeij method,
and to 0 to revert to the Zassenhaus method:

   extern long ZZXFac_van_Hoeij; // initial value = 1

Note that the "power hack" is still on by default when using van Hoeij's
method, but we have arranged things so that the "power hack" strategy 
is abandoned if it appears to be too much a waste of time.
Unlike with the Zassenhaus method, using the "power hack" method with
van Hoeij can sometimes be a huge waste of time if one is not careful.



The Zassenhaus method:

The Zassenhaus method is essentially a brute-force search, but with
a lot of fancy "pruning" techniques, as described in the paper
[J. Abbott, V. Shoup, P. Zimmermann, "Factoring in Z[x]: the searching phase",
ISSAC 2000].

These heuristics are fairly effective, and allow one to easily deal
with up to around 30-40 modular factors, which is *much* more
than other Zassenhaus-based factorizers can deal with; however, after this, 
the exponential behavior of the algorithm really starts to dominate.

The behaviour of these heuristics can be fine tuned by
setting the following global variables:

   extern long ZZXFac_MaxNumPrimes;  // initial value = 50
   // During the factor recombination phase, if not much progress
   // is being made, occasionally more "local" information is 
   // collected by factoring f modulo another prime.
   // This "local" information is used to rule out degrees 
   // of potential factors during recombination.
   // This value bounds the total number of primes modulo which f 
   // is factored.

   extern long ZZXFac_MaxPrune;  // initial value = 10
   // A kind of "meet in the middle" strategy is used
   // to prune the search space during recombination.
   // For many (but not all) polynomials, this can greatly
   // reduce the running time.
   // When it does work, there is a time-space tradeoff:
   // If t = ZZXFac_MaxPrune, the running time will be reduced by a factor near
   // 2^t, but the table will take (at most) t*2^(t-1) bytes of storage.
   // Note that ZZXFac_MaxPrune is treated as an upper bound on t---the
   // factoring algorithm may decide to use a smaller value of t for
   // a number of reasons.



\*****************************************************************************/
ntl-6.2.1/doc/ZZXFactoring.txt000644 000765 000024 00000014546 12377144460 016476 0ustar00shoupstaff000000 000000 /*****************************************************************************\ MODULE: ZZXFactoring SUMMARY: Routines are provided for factoring in ZZX. See IMPLEMENTATION DETAILS below for a discussion of the algorithms used, and of the flags available for selecting among these algorithms. \*****************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_ZZX_long& u, const ZZX& f); const vector(pair_ZZX_long SquareFreeDecomp(const ZZX& f); // input is primitive, with positive leading coefficient. Performs // square-free decomposition. If f = prod_i g_i^i, then u is set to a // lest of pairs (g_i, i). The list is is increasing order of i, with // trivial terms (i.e., g_i = 1) deleted. void MultiLift(vec_ZZX& A, const vec_zz_pX& a, const ZZX& f, long e, long verbose=0); // Using current value p of zz_p::modulus(), this lifts the // square-free factorization a mod p of f to a factorization A mod p^e // of f. It is required that f and all the polynomials in a are // monic. void SFFactor(vec_ZZX& factors, const ZZX& f, long verbose=0, long bnd=0); vec_ZZX SFFactor(const ZZX& f, long verbose=0, long bnd=0); // input f is primitive and square-free, with positive leading // coefficient. bnd, if not zero, indicates that f divides a // polynomial h whose Euclidean norm is bounded by 2^{bnd} in absolute // value. This uses the routine SFCanZass in zz_pXFactoring and then // performs a MultiLift, followed by a brute-force search for the // factors. // A number of heuristics are used to speed up the factor-search step. // See "implementation details" below. void factor(ZZ& c, vec_pair_ZZX_long& factors, const ZZX& f, long verbose=0, long bnd=0); // input f is is an arbitrary polynomial. c is the content of f, and // factors is the facrorization of its primitive part. bnd is as in // SFFactor. The routine calls SquareFreeDecomp and SFFactor. void mul(ZZX& x, const vec_pair_ZZX_long& a); ZZX mul(const vec_pair_ZZX_long& a); // multiplies polynomials, with multiplcities. /*****************************************************************************\ IMPLEMENTATION DETAILS To factor a polynomial, first its content is extracted, and it is made squarefree. This is typically very fast. Second, a simple hack is performed: if the polynomial is of the form g(x^l), then an attempt is made to factor g(k^m), for divisors m of l, which can in some cases greatly simplify the factorization task. You can turn this "power hack" on/off by setting the following variable to 1/0: extern long ZZXFac_PowerHack; // initial value = 1 Third, the polynomial is factored modulo several small primes, and one small prime p is selected as the "best". You can choose the number of small primes that you want to use by setting the following variable: extern long ZZXFac_InitNumPrimes; // initial value = 7 Fourth, The factorization mod p is "lifted" to a factorization mod p^k for a sufficiently large k. This is done via quadratic Hensel lifting. Despite "folk wisdom" to the contrary, this is much more efficient than linear Hensel lifting, especially since NTL has very fast polynomial arithmetic. After the "lifting phase" comes the "factor recombination phase". The factorization mod p^k may be "finer" than the true factorization over the integers, hence we have to "combine" subsets of modular factors and test if these are factors over the integers. There are two basic strategies: the "Zassenhaus" method and the "van Hoeij" method. The van Hoeij method: The van Hoeij method is fairly new, but it is so much better than the older, Zassenhaus method, that it is now the default. For a description of the method, go to Mark van Hoeij's home page: http://www.openmath.org/~hoeij/ The van Hoeij method is not really a specific algorithm, but a general algorithmic approach: many parameters and strategies have to be selected to obtain a specific algorithm, and it is a challenge to make all of these choices so that the resulting algorithm works fairly well on all input polynomials. Set the following variable to 1 to enable the van Hoeij method, and to 0 to revert to the Zassenhaus method: extern long ZZXFac_van_Hoeij; // initial value = 1 Note that the "power hack" is still on by default when using van Hoeij's method, but we have arranged things so that the "power hack" strategy is abandoned if it appears to be too much a waste of time. Unlike with the Zassenhaus method, using the "power hack" method with van Hoeij can sometimes be a huge waste of time if one is not careful. The Zassenhaus method: The Zassenhaus method is essentially a brute-force search, but with a lot of fancy "pruning" techniques, as described in the paper [J. Abbott, V. Shoup, P. Zimmermann, "Factoring in Z[x]: the searching phase", ISSAC 2000]. These heuristics are fairly effective, and allow one to easily deal with up to around 30-40 modular factors, which is *much* more than other Zassenhaus-based factorizers can deal with; however, after this, the exponential behavior of the algorithm really starts to dominate. The behaviour of these heuristics can be fine tuned by setting the following global variables: extern long ZZXFac_MaxNumPrimes; // initial value = 50 // During the factor recombination phase, if not much progress // is being made, occasionally more "local" information is // collected by factoring f modulo another prime. // This "local" information is used to rule out degrees // of potential factors during recombination. // This value bounds the total number of primes modulo which f // is factored. extern long ZZXFac_MaxPrune; // initial value = 10 // A kind of "meet in the middle" strategy is used // to prune the search space during recombination. // For many (but not all) polynomials, this can greatly // reduce the running time. // When it does work, there is a time-space tradeoff: // If t = ZZXFac_MaxPrune, the running time will be reduced by a factor near // 2^t, but the table will take (at most) t*2^(t-1) bytes of storage. // Note that ZZXFac_MaxPrune is treated as an upper bound on t---the // factoring algorithm may decide to use a smaller value of t for // a number of reasons. \*****************************************************************************/ ntl-6.2.1/doc/ZZ_p.cpp.html000644 000765 000024 00000053121 12377144460 015726 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZ_p.cpp.html


/**************************************************************************\

MODULE: ZZ_p

SUMMARY:

The class ZZ_p is used to represent integers mod p.  The modulus p may
be any positive integer, not necessarily prime.  

Objects of the class ZZ_p are represented as a ZZ in the range 0..p-1.

An executing program maintains a "current modulus", which is set to p using
ZZ_p::init(p).  The current modulus *must* be initialized before any operations
on ZZ_p's are performed.  The modulus may be changed, and a mechanism is provided
for saving and restoring a modulus (see classes ZZ_pPush and ZZ_pContext below).


\**************************************************************************/

#include <NTL/ZZ.h>
#include <NTL/ZZVec.h>

class ZZ_p {
public:

   ZZ_p(); // initialize to 0

   ZZ_p(const ZZ_p& a); // copy constructor
   explicit ZZ_p(long a);  // promotion constructor

   ~ZZ_p(); // destructor

   ZZ_p& operator=(const ZZ_p& a); // assignment
   ZZ_p& operator=(long a); // assignment

   static void init(const ZZ& p);
   // ZZ_p::init(p) sets the modulus to p (p > 1)

   static const ZZ& modulus();
   // ZZ_p::modulus() yields read-only reference to the current
   // modulus

   // typedefs to aid in generic programming
   typedef ZZ rep_type;
   typedef ZZ_pContext context_type;
   typedef ZZ_pBak bak_type;
   typedef ZZ_pPush push_type;
   typedef ZZ_pX poly_type;
};


/**************************************************************************\

                      Access to representation

\**************************************************************************/


const ZZ& rep(const ZZ_p& a);
// read-only access to representation of a

/****** Example: ********  

   ZZ x;
   ZZ_p a;

   x = rep(a);

*************************/


/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const ZZ_p& a, const ZZ_p& b);
long operator!=(const ZZ_p& a, const ZZ_p& b);

// PROMOTIONS: the comparison operators provide promotions
// from long to ZZ_p on (a, b)

long IsZero(const ZZ_p& a);  // test for 0
long IsOne(const ZZ_p& a);  // test for 1


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

ZZ_p operator+(const ZZ_p& a, const ZZ_p& b);
ZZ_p operator-(const ZZ_p& a, const ZZ_p& b);
ZZ_p operator-(const ZZ_p& a); // unary -

ZZ_p& operator+=(ZZ_p& x, const ZZ_p& b);
ZZ_p& operator+=(ZZ_p& x, long b);

ZZ_p& operator-=(ZZ_p& x, const ZZ_p& b);
ZZ_p& operator-=(ZZ_p& x, long b);

ZZ_p& operator++(ZZ_p& x);  // prefix
void operator++(ZZ_p& x, int);  // postfix

ZZ_p& operator--(ZZ_p& x);  // prefix
void operator--(ZZ_p& x, int);  // postfix

// procedural versions:


void add(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a + b
void sub(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a - b 
void negate(ZZ_p& x, const ZZ_p& a); // x = -a

// PROMOTIONS: binary +, - and procedures add, sub provide promotions
// from long to ZZ_p on (a, b)


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/

// operator notation:

ZZ_p operator*(const ZZ_p& a, const ZZ_p& b);

ZZ_p& operator*=(ZZ_p& x, const ZZ_p& b);
ZZ_p& operator*=(ZZ_p& x, long b);

// procedural versions:


void mul(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a * b

void sqr(ZZ_p& x, const ZZ_p& a); // x = a^2
ZZ_p sqr(const ZZ_p& a); // x = a^2

// PROMOTIONS: operator * and procedure mul provide promotions 
// from long to ZZ_p on (a, b)



/**************************************************************************\

                              Division

\**************************************************************************/


// operator notation:

ZZ_p operator/(const ZZ_p& a, const ZZ_p& b);

ZZ_p& operator/=(ZZ_p& x, const ZZ_p& b);
ZZ_p& operator/=(ZZ_p& x, long b);


// procedural versions:


void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b);
// x = a/b.

// By default, if b is not invertible, an error is raised.  However,
// one can override this default behavior by defining an error handler
// void H(const ZZ_p& b), and setting ZZ_p::DivHandler = H.  Then if b
// != 0 and b is not invertible, the function H is invoked with b as
// its argument.  When this happens, p is of course not prime, and
// GCD(p, rep(b)) is a nontrivial factor.

void inv(ZZ_p& x, const ZZ_p& a); // x = 1/a
ZZ_p inv(const ZZ_p& a);

// Error handling is the same as above.

// PROMOTIONS: operator / and procedure div provide promotions
// from long to ZZ_p on (a, b)



/**************************************************************************\

                            Exponentiation

\**************************************************************************/



void power(ZZ_p& x, const ZZ_p& a, const ZZ& e); // x = a^e (e may be negative)
ZZ_p power(const ZZ_p& a, const ZZ& e); // functional variants

void power(ZZ_p& x, const ZZ_p& a, long e);
ZZ_p power(ZZ_p& x, const ZZ_p& a, long e);



/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(ZZ_p& x);
ZZ_p random_ZZ_p();
// x = random element in ZZ_p.  


/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, const ZZ_p& a);

istream& operator>>(istream& s, ZZ_p& x);
// a ZZ is read and reduced mod p

/**************************************************************************\

                       Modulus Switching 


A class ZZ_pPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to p, and automatically restore it:

   { 
      ZZ_pPush push(p); 

      ...

   }

The constructor for push will save the current modulus, and install p as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      ZZ_pPush push(); // just backup current modulus

        ...

      ZZ_p::init(p1); // install p1 

        ...

      ZZ_p::init(p2); // install p2

      // reinstall original modulus as close of scope
   }

      
The ZZ_pPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see ZZ_pContext below.  There is also an older ZZ_pBak class
that may also be useful.

..........................................................................

It is critical that ZZ_p objects created under one ZZ_p modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
ZZ_p modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any ZZ_p object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.


NOTE: the implementation of Vec<ZZ_p> is specialized to manage memory more
efficiently than in the default implementation of Vec<T>.  Specifically,
contiguous elements in a Vec<ZZ_p> are allocated in a contiguous region of
memory.  This reduces the number of calls to the memory allocator, and --- more
significantly --- leads to greater locality of reference.  A consequence of
this implementation is that any calls to SetLength on a Vec<ZZ_p> object will
need to use information about the current modulus, and so such calls should
only be done "in context".  That said, it is still safe to construct a
Vec<ZZ_p> using the default or copy contructor, and to assign or append one
Vec<ZZ_p> to another "out of context".

\**************************************************************************/



// A convenient interface for common cases:

class ZZ_pPush {

public:
ZZ_pPush();  // backup current modulus
explicit ZZ_pPush(const ZZ& p);
explicit ZZ_pPush(const ZZ_pContext& context);
  // backup current modulus and install the given one

private:
ZZ_pPush(const ZZ_pPush&); // disabled
void operator=(const ZZ_pPush&); // disabled

};



// more general context switching:
// A ZZ_pContext object has a modulus q (possibly "null")

class ZZ_pContext {


public:

ZZ_pContext(); // q = "null"

explicit ZZ_pContext(const ZZ& p);  // q = p

void save(); // q = CurrentModulus
void restore() const; // CurrentModulus = q

ZZ_pContext(const ZZ_pContext&);  // copy
ZZ_pContext& operator=(const ZZ_pContext&); // assignment
~ZZ_pContext(); // destructor


};


// An older interface:
// To describe this logic, think of a ZZ_pBak object
// of having two components: a modulus q (possibly "null") and 
// an "auto-restore bit" b.

class ZZ_pBak {
public:


   ZZ_pBak();  // q = "null", b = 0

   ~ZZ_pBak();  // if (b) CurrentModulus = q

   void save();  // q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = q, b = 0


private:
   ZZ_pBak(const ZZ_pBak&);  // copy disabled
   void operator=(const ZZ_pBak&);  // assignment disabled
};






/**************************************************************************\

                               Miscellany

\**************************************************************************/

void clear(ZZ_p& x); // x = 0
void set(ZZ_p& x); // x = 1

static long ZZ_p::ModulusSize();
//  ZZ_p::ModulusSize() returns ZZ_p::modulus().size()

static const ZZ_p& ZZ_p::zero();
// ZZ_p::zero() yields a read-only reference to zero

void swap(ZZ_p& x, ZZ_p& y);
// swap x and y (done by "pointer swapping", if possible).


ZZ_p::ZZ_p(INIT_NO_ALLOC_TYPE);
// special constructor: invoke as ZZ_p x(INIT_NO_ALLOC);
// initializes x to 0, but allocates no space (this is now the default)

ZZ_p::ZZ_p(INIT_ALLOC_TYPE);
// special constructor: invoke as ZZ_p x(INIT_ALLOC);
// initializes x to 0, but allocates space


ZZ_p::allocate();
// useful in conjunction with the INIT_NO_ALLLOC constructor:
// x.allocate() will pre-allocate space for x, using the
// current modulus

ntl-6.2.1/doc/ZZ_p.txt000644 000765 000024 00000025067 12377144460 015030 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZ_p SUMMARY: The class ZZ_p is used to represent integers mod p. The modulus p may be any positive integer, not necessarily prime. Objects of the class ZZ_p are represented as a ZZ in the range 0..p-1. An executing program maintains a "current modulus", which is set to p using ZZ_p::init(p). The current modulus *must* be initialized before any operations on ZZ_p's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes ZZ_pPush and ZZ_pContext below). \**************************************************************************/ #include #include class ZZ_p { public: ZZ_p(); // initialize to 0 ZZ_p(const ZZ_p& a); // copy constructor explicit ZZ_p(long a); // promotion constructor ~ZZ_p(); // destructor ZZ_p& operator=(const ZZ_p& a); // assignment ZZ_p& operator=(long a); // assignment static void init(const ZZ& p); // ZZ_p::init(p) sets the modulus to p (p > 1) static const ZZ& modulus(); // ZZ_p::modulus() yields read-only reference to the current // modulus // typedefs to aid in generic programming typedef ZZ rep_type; typedef ZZ_pContext context_type; typedef ZZ_pBak bak_type; typedef ZZ_pPush push_type; typedef ZZ_pX poly_type; }; /**************************************************************************\ Access to representation \**************************************************************************/ const ZZ& rep(const ZZ_p& a); // read-only access to representation of a /****** Example: ******** ZZ x; ZZ_p a; x = rep(a); *************************/ /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZ_p& a, const ZZ_p& b); long operator!=(const ZZ_p& a, const ZZ_p& b); // PROMOTIONS: the comparison operators provide promotions // from long to ZZ_p on (a, b) long IsZero(const ZZ_p& a); // test for 0 long IsOne(const ZZ_p& a); // test for 1 /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ_p operator+(const ZZ_p& a, const ZZ_p& b); ZZ_p operator-(const ZZ_p& a, const ZZ_p& b); ZZ_p operator-(const ZZ_p& a); // unary - ZZ_p& operator+=(ZZ_p& x, const ZZ_p& b); ZZ_p& operator+=(ZZ_p& x, long b); ZZ_p& operator-=(ZZ_p& x, const ZZ_p& b); ZZ_p& operator-=(ZZ_p& x, long b); ZZ_p& operator++(ZZ_p& x); // prefix void operator++(ZZ_p& x, int); // postfix ZZ_p& operator--(ZZ_p& x); // prefix void operator--(ZZ_p& x, int); // postfix // procedural versions: void add(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a + b void sub(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a - b void negate(ZZ_p& x, const ZZ_p& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub provide promotions // from long to ZZ_p on (a, b) /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ_p operator*(const ZZ_p& a, const ZZ_p& b); ZZ_p& operator*=(ZZ_p& x, const ZZ_p& b); ZZ_p& operator*=(ZZ_p& x, long b); // procedural versions: void mul(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a * b void sqr(ZZ_p& x, const ZZ_p& a); // x = a^2 ZZ_p sqr(const ZZ_p& a); // x = a^2 // PROMOTIONS: operator * and procedure mul provide promotions // from long to ZZ_p on (a, b) /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ_p operator/(const ZZ_p& a, const ZZ_p& b); ZZ_p& operator/=(ZZ_p& x, const ZZ_p& b); ZZ_p& operator/=(ZZ_p& x, long b); // procedural versions: void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a/b. // By default, if b is not invertible, an error is raised. However, // one can override this default behavior by defining an error handler // void H(const ZZ_p& b), and setting ZZ_p::DivHandler = H. Then if b // != 0 and b is not invertible, the function H is invoked with b as // its argument. When this happens, p is of course not prime, and // GCD(p, rep(b)) is a nontrivial factor. void inv(ZZ_p& x, const ZZ_p& a); // x = 1/a ZZ_p inv(const ZZ_p& a); // Error handling is the same as above. // PROMOTIONS: operator / and procedure div provide promotions // from long to ZZ_p on (a, b) /**************************************************************************\ Exponentiation \**************************************************************************/ void power(ZZ_p& x, const ZZ_p& a, const ZZ& e); // x = a^e (e may be negative) ZZ_p power(const ZZ_p& a, const ZZ& e); // functional variants void power(ZZ_p& x, const ZZ_p& a, long e); ZZ_p power(ZZ_p& x, const ZZ_p& a, long e); /**************************************************************************\ Random Elements \**************************************************************************/ void random(ZZ_p& x); ZZ_p random_ZZ_p(); // x = random element in ZZ_p. /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, const ZZ_p& a); istream& operator>>(istream& s, ZZ_p& x); // a ZZ is read and reduced mod p /**************************************************************************\ Modulus Switching A class ZZ_pPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to p, and automatically restore it: { ZZ_pPush push(p); ... } The constructor for push will save the current modulus, and install p as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { ZZ_pPush push(); // just backup current modulus ... ZZ_p::init(p1); // install p1 ... ZZ_p::init(p2); // install p2 // reinstall original modulus as close of scope } The ZZ_pPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see ZZ_pContext below. There is also an older ZZ_pBak class that may also be useful. .......................................................................... It is critical that ZZ_p objects created under one ZZ_p modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) ZZ_p modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any ZZ_p object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. NOTE: the implementation of Vec is specialized to manage memory more efficiently than in the default implementation of Vec. Specifically, contiguous elements in a Vec are allocated in a contiguous region of memory. This reduces the number of calls to the memory allocator, and --- more significantly --- leads to greater locality of reference. A consequence of this implementation is that any calls to SetLength on a Vec object will need to use information about the current modulus, and so such calls should only be done "in context". That said, it is still safe to construct a Vec using the default or copy contructor, and to assign or append one Vec to another "out of context". \**************************************************************************/ // A convenient interface for common cases: class ZZ_pPush { public: ZZ_pPush(); // backup current modulus explicit ZZ_pPush(const ZZ& p); explicit ZZ_pPush(const ZZ_pContext& context); // backup current modulus and install the given one private: ZZ_pPush(const ZZ_pPush&); // disabled void operator=(const ZZ_pPush&); // disabled }; // more general context switching: // A ZZ_pContext object has a modulus q (possibly "null") class ZZ_pContext { public: ZZ_pContext(); // q = "null" explicit ZZ_pContext(const ZZ& p); // q = p void save(); // q = CurrentModulus void restore() const; // CurrentModulus = q ZZ_pContext(const ZZ_pContext&); // copy ZZ_pContext& operator=(const ZZ_pContext&); // assignment ~ZZ_pContext(); // destructor }; // An older interface: // To describe this logic, think of a ZZ_pBak object // of having two components: a modulus q (possibly "null") and // an "auto-restore bit" b. class ZZ_pBak { public: ZZ_pBak(); // q = "null", b = 0 ~ZZ_pBak(); // if (b) CurrentModulus = q void save(); // q = CurrentModulus, b = 1 void restore(); // CurrentModulus = q, b = 0 private: ZZ_pBak(const ZZ_pBak&); // copy disabled void operator=(const ZZ_pBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZ_p& x); // x = 0 void set(ZZ_p& x); // x = 1 static long ZZ_p::ModulusSize(); // ZZ_p::ModulusSize() returns ZZ_p::modulus().size() static const ZZ_p& ZZ_p::zero(); // ZZ_p::zero() yields a read-only reference to zero void swap(ZZ_p& x, ZZ_p& y); // swap x and y (done by "pointer swapping", if possible). ZZ_p::ZZ_p(INIT_NO_ALLOC_TYPE); // special constructor: invoke as ZZ_p x(INIT_NO_ALLOC); // initializes x to 0, but allocates no space (this is now the default) ZZ_p::ZZ_p(INIT_ALLOC_TYPE); // special constructor: invoke as ZZ_p x(INIT_ALLOC); // initializes x to 0, but allocates space ZZ_p::allocate(); // useful in conjunction with the INIT_NO_ALLLOC constructor: // x.allocate() will pre-allocate space for x, using the // current modulus ntl-6.2.1/doc/ZZ_pE.cpp.html000644 000765 000024 00000051554 12377144460 016043 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZ_pE.cpp.html


/**************************************************************************\

MODULE: ZZ_pE

SUMMARY:

The class ZZ_pE is used to represent polynomials in Z_p[X] modulo a
polynomial P.  The modulus P may be any polynomial with deg(P) > 0,
not necessarily irreducible.  The modulus p defining Z_p need
not be prime either.

Objects of the class ZZ_pE are represented as a ZZ_pX of degree < deg(P).

An executing program maintains a "current modulus", which is set to P
using ZZ_pE::init(P).  The current modulus for ZZ_pE (as well as for ZZ_p)
*must* be initialized before an operations on ZZ_pE's are performed.

The modulus may be changed, and a mechanism is provided for saving and
restoring a modulus (see classes ZZ_pEPush and ZZ_pEContext below).


\**************************************************************************/

#include <NTL/ZZ_pX.h>

class ZZ_pE {
public:

   ZZ_pE(); // initial value 0

   ZZ_pE(const ZZ_pE& a); // copy constructor
   explicit ZZ_pE(const ZZ_p& a); // promotion
   explicit ZZ_pE(long a); // promotion

   ZZ_pE& operator=(const ZZ_pE& a); // assignment
   ZZ_pE& operator=(const ZZ_p& a); // assignment
   ZZ_pE& operator=(long a); // assignment

   ~ZZ_pE(); // destructor

   void init(const ZZ_pX& P);
   // ZZ_pE::init(P) initializes the current modulus to P;
   // required: deg(P) >= 1.

   static const ZZ_pXModulus& modulus();
   // ZZ_pE::modulus() yields read-only reference to the current modulus 

   static long degree();
   // ZZ_pE::degree() returns deg(P)


   // typedefs to aid generic programming
   typedef ZZ_pX rep_type;
   typedef ZZ_pEContext context_type;
   typedef ZZ_pEBak bak_type;
   typedef ZZ_pEPush push_type;
   typedef ZZ_pEX poly_type;

};


const ZZ_pX& rep(const ZZ_pE& a); // read-only access to representation of a



/**************************************************************************\

                                  Comparison

\**************************************************************************/

long operator==(const ZZ_pE& a, const ZZ_pE& b);
long operator!=(const ZZ_pE& a, const ZZ_pE& b);

long IsZero(const ZZ_pE& a);  // test for 0
long IsOne(const ZZ_pE& a);  // test for 1

// PROMOTIONS: ==, != promote {long, ZZ_p} to ZZ_pE on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

ZZ_pE operator+(const ZZ_pE& a, const ZZ_pE& b);

ZZ_pE operator-(const ZZ_pE& a, const ZZ_pE& b);
ZZ_pE operator-(const ZZ_pE& a);

ZZ_pE& operator+=(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE& operator+=(ZZ_pE& x, const ZZ_p& a);
ZZ_pE& operator+=(ZZ_pE& x, long a);

ZZ_pE& operator++(ZZ_pE& x); // prefix
void operator++(ZZ_pE& x, int); // postfix

ZZ_pE& operator-=(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE& operator-=(ZZ_pE& x, const ZZ_p& a);
ZZ_pE& operator-=(ZZ_pE& x, long a);

ZZ_pE& operator--(ZZ_pE& x); // prefix
void operator--(ZZ_pE& x, int); // postfix

// procedural versions:

void add(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a + b
void sub(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a - b 
void negate(ZZ_pE& x, const ZZ_pE& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long, ZZ_p} to ZZ_pE on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/


// operator notation:

ZZ_pE operator*(const ZZ_pE& a, const ZZ_pE& b);

ZZ_pE& operator*=(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE& operator*=(ZZ_pE& x, const ZZ_p& a);
ZZ_pE& operator*=(ZZ_pE& x, long a);

// procedural versions:


void mul(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a * b

void sqr(ZZ_pE& x, const ZZ_pE& a); // x = a^2
ZZ_pE sqr(const ZZ_pE& a);

// PROMOTIONS: *, mul promote {long, ZZ_p} to ZZ_pE on (a, b).



/**************************************************************************\

                                     Division

\**************************************************************************/


// operator notation:

ZZ_pE operator/(const ZZ_pE& a, const ZZ_pE& b);

ZZ_pE& operator/=(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE& operator/=(ZZ_pE& x, const ZZ_p& a);
ZZ_pE& operator/=(ZZ_pE& x, long a);


// procedural versions:

void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b);
// x = a/b.  If b is not invertible, an error is raised.

void inv(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE inv(const ZZ_pE& a);
// x = 1/a

PROMOTIONS: /, div promote {long, ZZ_p} to ZZ_pE on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/



void power(ZZ_pE& x, const ZZ_pE& a, const ZZ& e);
ZZ_pE power(const ZZ_pE& a, const ZZ& e);

void power(ZZ_pE& x, const ZZ_pE& a, long e);
ZZ_pE power(const ZZ_pE& a, long e);

// x = a^e (e may be negative)



/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(ZZ_pE& x);
ZZ_pE random_ZZ_pE();
// x = random element in ZZ_pE.

/**************************************************************************\

                               Norms and Traces

\**************************************************************************/



void trace(ZZ_p& x, const ZZ_pE& a);  // x = trace of a
ZZ_p trace(const ZZ_pE& a);

void norm(ZZ_p& x, const ZZ_pE& a);   // x = norm of a
ZZ_p norm(const ZZ_pE& a);



/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, const ZZ_pE& a);

istream& operator>>(istream& s, ZZ_pE& x);
// a ZZ_pX is read and reduced mod p


/**************************************************************************\

                       Modulus Switching 

A class ZZ_pEPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to P, and automatically restore it:

   { 
      ZZ_pEPush push(P); 

      ...

   }

The constructor for push will save the current modulus, and install P as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      ZZ_pEPush push(); // just backup current modulus

        ...

      ZZ_pE::init(P1); // install P1 

        ...

      ZZ_pE::init(P2); // install P2

      // reinstall original modulus as close of scope
   }

      
The ZZ_pEPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see ZZ_pEContext below.  There is also an older ZZ_pEBak class
that may also be useful.

..........................................................................

It is critical that ZZ_pE objects created under one ZZ_pE modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
ZZ_pE modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any ZZ_pE object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.


\**************************************************************************/


// A convenient interface for common cases

class ZZ_pEPush {

public:
ZZ_pEPush();  // backup current modulus
explicit ZZ_pEPush(const ZZ_pX& P);
explicit ZZ_pEPush(const ZZ_pEContext& context);
  // backup current modulus and install the given one

private:
ZZ_pEPush(const ZZ_pEPush&); // disabled
void operator=(const ZZ_pEPush&); // disabled

};



// more general context switching:
// A ZZ_pEContext object has a modulus Q (possibly "null"),

class ZZ_pEContext {


public:

ZZ_pEContext(); // Q = "null"
explicit ZZ_pEContext(const ZZ_pX& P); // Q = P

void save(); // Q = CurrentModulus
void restore() const; // CurrentModulus = Q

ZZ_pEContext(const ZZ_pEContext&);  // copy
ZZ_pEContext& operator=(const ZZ_pEContext&); // assignment
~ZZ_pEContext(); // destructor


};


// An older interface:
// To describe this logic, think of a ZZ_pEBak object
// of having two components: a modulus Q (possibly "null") and 
// an "auto-restore bit" b.


class ZZ_pEBak {
public:


   ZZ_pEBak();  // Q = "null", b = 0

   ~ZZ_pEBak();  // if (b) CurrentModulus = Q

   void save();  // Q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = Q, b = 0


private:
   ZZ_pEBak(const ZZ_pEBak&);  // copy disabled
   void operator=(const ZZ_pEBak&);  // assignment disabled
};






/**************************************************************************\

                               Miscellany

\**************************************************************************/

void clear(ZZ_pE& x); // x = 0
void set(ZZ_pE& x); // x = 1

static const ZZ_pE& ZZ_pE::zero();
// ZZ_pE::zero() yields a read-only reference to zero

void swap(ZZ_pE& x, ZZ_pE& y);
// swap x and y (done by "pointer swapping", if possible).

static ZZ& ZZ_pE::cardinality();
// yields the cardinality, i.e., p^{ZZ_pE::degree()}

ZZ_pE::ZZ_pE(INIT_NO_ALLOC_TYPE);
// special constructor: invoke as ZZ_pE x(INIT_NO_ALLOC);
// initializes x to 0, but allocates no space (this is now the default)

ZZ_pE::ZZ_pE(INIT_ALLOC_TYPE);
// special constructor: invoke as ZZ_pE x(INIT_ALLOC);
// initializes x to 0, but allocates space

ZZ_pE::allocate();
// useful in conjunction with the INIT_NO_ALLLOC constructor:
// x.allocate() will pre-allocate space for x, using the
// current modulus

ntl-6.2.1/doc/ZZ_pE.txt000644 000765 000024 00000024011 12377144460 015121 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZ_pE SUMMARY: The class ZZ_pE is used to represent polynomials in Z_p[X] modulo a polynomial P. The modulus P may be any polynomial with deg(P) > 0, not necessarily irreducible. The modulus p defining Z_p need not be prime either. Objects of the class ZZ_pE are represented as a ZZ_pX of degree < deg(P). An executing program maintains a "current modulus", which is set to P using ZZ_pE::init(P). The current modulus for ZZ_pE (as well as for ZZ_p) *must* be initialized before an operations on ZZ_pE's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes ZZ_pEPush and ZZ_pEContext below). \**************************************************************************/ #include class ZZ_pE { public: ZZ_pE(); // initial value 0 ZZ_pE(const ZZ_pE& a); // copy constructor explicit ZZ_pE(const ZZ_p& a); // promotion explicit ZZ_pE(long a); // promotion ZZ_pE& operator=(const ZZ_pE& a); // assignment ZZ_pE& operator=(const ZZ_p& a); // assignment ZZ_pE& operator=(long a); // assignment ~ZZ_pE(); // destructor void init(const ZZ_pX& P); // ZZ_pE::init(P) initializes the current modulus to P; // required: deg(P) >= 1. static const ZZ_pXModulus& modulus(); // ZZ_pE::modulus() yields read-only reference to the current modulus static long degree(); // ZZ_pE::degree() returns deg(P) // typedefs to aid generic programming typedef ZZ_pX rep_type; typedef ZZ_pEContext context_type; typedef ZZ_pEBak bak_type; typedef ZZ_pEPush push_type; typedef ZZ_pEX poly_type; }; const ZZ_pX& rep(const ZZ_pE& a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZ_pE& a, const ZZ_pE& b); long operator!=(const ZZ_pE& a, const ZZ_pE& b); long IsZero(const ZZ_pE& a); // test for 0 long IsOne(const ZZ_pE& a); // test for 1 // PROMOTIONS: ==, != promote {long, ZZ_p} to ZZ_pE on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ_pE operator+(const ZZ_pE& a, const ZZ_pE& b); ZZ_pE operator-(const ZZ_pE& a, const ZZ_pE& b); ZZ_pE operator-(const ZZ_pE& a); ZZ_pE& operator+=(ZZ_pE& x, const ZZ_pE& a); ZZ_pE& operator+=(ZZ_pE& x, const ZZ_p& a); ZZ_pE& operator+=(ZZ_pE& x, long a); ZZ_pE& operator++(ZZ_pE& x); // prefix void operator++(ZZ_pE& x, int); // postfix ZZ_pE& operator-=(ZZ_pE& x, const ZZ_pE& a); ZZ_pE& operator-=(ZZ_pE& x, const ZZ_p& a); ZZ_pE& operator-=(ZZ_pE& x, long a); ZZ_pE& operator--(ZZ_pE& x); // prefix void operator--(ZZ_pE& x, int); // postfix // procedural versions: void add(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a + b void sub(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a - b void negate(ZZ_pE& x, const ZZ_pE& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long, ZZ_p} to ZZ_pE on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ_pE operator*(const ZZ_pE& a, const ZZ_pE& b); ZZ_pE& operator*=(ZZ_pE& x, const ZZ_pE& a); ZZ_pE& operator*=(ZZ_pE& x, const ZZ_p& a); ZZ_pE& operator*=(ZZ_pE& x, long a); // procedural versions: void mul(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a * b void sqr(ZZ_pE& x, const ZZ_pE& a); // x = a^2 ZZ_pE sqr(const ZZ_pE& a); // PROMOTIONS: *, mul promote {long, ZZ_p} to ZZ_pE on (a, b). /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ_pE operator/(const ZZ_pE& a, const ZZ_pE& b); ZZ_pE& operator/=(ZZ_pE& x, const ZZ_pE& a); ZZ_pE& operator/=(ZZ_pE& x, const ZZ_p& a); ZZ_pE& operator/=(ZZ_pE& x, long a); // procedural versions: void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a/b. If b is not invertible, an error is raised. void inv(ZZ_pE& x, const ZZ_pE& a); ZZ_pE inv(const ZZ_pE& a); // x = 1/a PROMOTIONS: /, div promote {long, ZZ_p} to ZZ_pE on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(ZZ_pE& x, const ZZ_pE& a, const ZZ& e); ZZ_pE power(const ZZ_pE& a, const ZZ& e); void power(ZZ_pE& x, const ZZ_pE& a, long e); ZZ_pE power(const ZZ_pE& a, long e); // x = a^e (e may be negative) /**************************************************************************\ Random Elements \**************************************************************************/ void random(ZZ_pE& x); ZZ_pE random_ZZ_pE(); // x = random element in ZZ_pE. /**************************************************************************\ Norms and Traces \**************************************************************************/ void trace(ZZ_p& x, const ZZ_pE& a); // x = trace of a ZZ_p trace(const ZZ_pE& a); void norm(ZZ_p& x, const ZZ_pE& a); // x = norm of a ZZ_p norm(const ZZ_pE& a); /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, const ZZ_pE& a); istream& operator>>(istream& s, ZZ_pE& x); // a ZZ_pX is read and reduced mod p /**************************************************************************\ Modulus Switching A class ZZ_pEPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to P, and automatically restore it: { ZZ_pEPush push(P); ... } The constructor for push will save the current modulus, and install P as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { ZZ_pEPush push(); // just backup current modulus ... ZZ_pE::init(P1); // install P1 ... ZZ_pE::init(P2); // install P2 // reinstall original modulus as close of scope } The ZZ_pEPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see ZZ_pEContext below. There is also an older ZZ_pEBak class that may also be useful. .......................................................................... It is critical that ZZ_pE objects created under one ZZ_pE modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) ZZ_pE modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any ZZ_pE object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. \**************************************************************************/ // A convenient interface for common cases class ZZ_pEPush { public: ZZ_pEPush(); // backup current modulus explicit ZZ_pEPush(const ZZ_pX& P); explicit ZZ_pEPush(const ZZ_pEContext& context); // backup current modulus and install the given one private: ZZ_pEPush(const ZZ_pEPush&); // disabled void operator=(const ZZ_pEPush&); // disabled }; // more general context switching: // A ZZ_pEContext object has a modulus Q (possibly "null"), class ZZ_pEContext { public: ZZ_pEContext(); // Q = "null" explicit ZZ_pEContext(const ZZ_pX& P); // Q = P void save(); // Q = CurrentModulus void restore() const; // CurrentModulus = Q ZZ_pEContext(const ZZ_pEContext&); // copy ZZ_pEContext& operator=(const ZZ_pEContext&); // assignment ~ZZ_pEContext(); // destructor }; // An older interface: // To describe this logic, think of a ZZ_pEBak object // of having two components: a modulus Q (possibly "null") and // an "auto-restore bit" b. class ZZ_pEBak { public: ZZ_pEBak(); // Q = "null", b = 0 ~ZZ_pEBak(); // if (b) CurrentModulus = Q void save(); // Q = CurrentModulus, b = 1 void restore(); // CurrentModulus = Q, b = 0 private: ZZ_pEBak(const ZZ_pEBak&); // copy disabled void operator=(const ZZ_pEBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZ_pE& x); // x = 0 void set(ZZ_pE& x); // x = 1 static const ZZ_pE& ZZ_pE::zero(); // ZZ_pE::zero() yields a read-only reference to zero void swap(ZZ_pE& x, ZZ_pE& y); // swap x and y (done by "pointer swapping", if possible). static ZZ& ZZ_pE::cardinality(); // yields the cardinality, i.e., p^{ZZ_pE::degree()} ZZ_pE::ZZ_pE(INIT_NO_ALLOC_TYPE); // special constructor: invoke as ZZ_pE x(INIT_NO_ALLOC); // initializes x to 0, but allocates no space (this is now the default) ZZ_pE::ZZ_pE(INIT_ALLOC_TYPE); // special constructor: invoke as ZZ_pE x(INIT_ALLOC); // initializes x to 0, but allocates space ZZ_pE::allocate(); // useful in conjunction with the INIT_NO_ALLLOC constructor: // x.allocate() will pre-allocate space for x, using the // current modulus ntl-6.2.1/doc/ZZ_pEX.cpp.html000644 000765 000024 00000156715 12377144460 016200 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZ_pEX.cpp.html

/**************************************************************************\

MODULE: ZZ_pEX

SUMMARY:

The class ZZ_pEX represents polynomials over ZZ_pE,
and so can be used, for example, for arithmentic in GF(p^n)[X].
However, except where mathematically necessary (e.g., GCD computations),
ZZ_pE need not be a field.

\**************************************************************************/

#include <NTL/ZZ_pE.h>
#include <NTL/vec_ZZ_pE.h>

class ZZ_pEX {
public:

   ZZ_pEX(); // initial value 0

   ZZ_pEX(const ZZ_pEX& a); // copy

   explicit ZZ_pEX(const ZZ_pE& a); // promotion
   explicit ZZ_pEX(const ZZ_p& a);
   explicit ZZ_pEX(long a);

   ZZ_pEX& operator=(const ZZ_pEX& a); // assignment
   ZZ_pEX& operator=(const ZZ_pE& a);
   ZZ_pEX& operator=(const ZZ_p& a);
   ZZ_pEX& operator=(long a);

   ~ZZ_pEX(); // destructor

   ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_pE& c);
   ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_p& c);
   ZZ_pEX(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as ZZ_pEX(INIT_MONO, i, c)

   ZZ_pEX(INIT_MONO_TYPE, long i);
   // initialize to X^i, invoke as ZZ_pEX(INIT_MONO, i)

   // typedefs to aid in generic programming
   typedef ZZ_pE coeff_type;
   typedef ZZ_pEXModulus modulus_type;

   // ...

};




/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const ZZ_pEX& a);  // return deg(a); deg(0) == -1.

const ZZ_pE& coeff(const ZZ_pEX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const ZZ_pE& LeadCoeff(const ZZ_pEX& a);
// returns leading term of a, or zero if a == 0

const ZZ_pE& ConstTerm(const ZZ_pEX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(ZZ_pEX& x, long i, const ZZ_pE& a);
void SetCoeff(ZZ_pEX& x, long i, const ZZ_p& a);
void SetCoeff(ZZ_pEX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(ZZ_pEX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(ZZ_pEX& x); // x is set to the monomial X

long IsX(const ZZ_pEX& a); // test if x = X




ZZ_pE& ZZ_pEX::operator[](long i);
const ZZ_pE& ZZ_pEX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void ZZ_pEX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void ZZ_pEX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void ZZ_pEX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.










/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const ZZ_pEX& a, const ZZ_pEX& b);
long operator!=(const ZZ_pEX& a, const ZZ_pEX& b);

long IsZero(const ZZ_pEX& a); // test for 0
long IsOne(const ZZ_pEX& a); // test for 1

// PROMOTIONS: ==, != promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b).

/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pEX operator-(const ZZ_pEX& a);

ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pE& a);
ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_p& a);
ZZ_pEX& operator+=(ZZ_pEX& x, long a);


ZZ_pEX& operator++(ZZ_pEX& x);  // prefix
void operator++(ZZ_pEX& x, int);  // postfix

ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pE& a);
ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_p& a);
ZZ_pEX& operator-=(ZZ_pEX& x, long a);

ZZ_pEX& operator--(ZZ_pEX& x);  // prefix
void operator--(ZZ_pEX& x, int);  // postfix

// procedural versions:

void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a + b
void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a - b 
void negate(ZZ_pEX& x, const ZZ_pEX& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b).



/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_pEX& b);

ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pE& a);
ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_p& a);
ZZ_pEX& operator*=(ZZ_pEX& x, long a);


// procedural versions:


void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a * b

void sqr(ZZ_pEX& x, const ZZ_pEX& a); // x = a^2
ZZ_pEX sqr(const ZZ_pEX& a);

// PROMOTIONS: *, mul promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b).

void power(ZZ_pEX& x, const ZZ_pEX& a, long e);  // x = a^e (e >= 0)
ZZ_pEX power(const ZZ_pEX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

ZZ_pEX operator<<(const ZZ_pEX& a, long n);
ZZ_pEX operator>>(const ZZ_pEX& a, long n);

ZZ_pEX& operator<<=(ZZ_pEX& x, long n);
ZZ_pEX& operator>>=(ZZ_pEX& x, long n);

// procedural versions:

void LeftShift(ZZ_pEX& x, const ZZ_pEX& a, long n);
ZZ_pEX LeftShift(const ZZ_pEX& a, long n);

void RightShift(ZZ_pEX& x, const ZZ_pEX& a, long n);
ZZ_pEX RightShift(const ZZ_pEX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pE& b);
ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_p& b);
ZZ_pEX operator/(const ZZ_pEX& a, long b);

ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEX& b);

ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pE& a);
ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_p& a);
ZZ_pEX& operator/=(ZZ_pEX& x, long a);

ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEX& a);

// procedural versions:


void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b);
// q = a/b, r = a%b

void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b);
void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pE& b);
void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_p& b);
void div(ZZ_pEX& q, const ZZ_pEX& a, long b);
// q = a/b

void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b);
// r = a%b

long divide(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const ZZ_pEX& a, const ZZ_pEX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


/**************************************************************************\

                                   GCD's

These routines are intended for use when ZZ_pE is a field.

\**************************************************************************/


void GCD(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pEX GCD(const ZZ_pEX& a, const ZZ_pEX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(ZZ_pEX& d, ZZ_pEX& s, ZZ_pEX& t, const ZZ_pEX& a, const ZZ_pEX& b);
// d = gcd(a,b), a s + b t = d 


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be polynomials of degree < ZZ_pE::degree() and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary polynomials which are reduced modulo ZZ_pE::modulus(), 
and leading zeros stripped.

\**************************************************************************/

istream& operator>>(istream& s, ZZ_pEX& x);
ostream& operator<<(ostream& s, const ZZ_pEX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(ZZ_pEX& x, const ZZ_pEX& a); // x = derivative of a
ZZ_pEX diff(const ZZ_pEX& a);

void MakeMonic(ZZ_pEX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case

void reverse(ZZ_pEX& x, const ZZ_pEX& a, long hi);
ZZ_pEX reverse(const ZZ_pEX& a, long hi);

void reverse(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX reverse(const ZZ_pEX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_ZZ_pE& x, const ZZ_pEX& a, long n);
vec_ZZ_pE VectorCopy(const ZZ_pEX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(ZZ_pEX& x, long n);
ZZ_pEX random_ZZ_pEX(long n);
// x = random polynomial of degree < n 


/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(ZZ_pEX& x, const vec_ZZ_pE& a);
ZZ_pEX BuildFromRoots(const vec_ZZ_pE& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length()

void eval(ZZ_pE& b, const ZZ_pEX& f, const ZZ_pE& a);
ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a);
// b = f(a)

void eval(ZZ_pE& b, const ZZ_pX& f, const ZZ_pE& a);
ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a);
// b = f(a); uses ModComp algorithm for ZZ_pX

void eval(vec_ZZ_pE& b, const ZZ_pEX& f, const vec_ZZ_pE& a);
vec_ZZ_pE eval(const ZZ_pEX& f, const vec_ZZ_pE& a);
//  b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(ZZ_pEX& f, const vec_ZZ_pE& a, const vec_ZZ_pE& b);
ZZ_pEX interpolate(const vec_ZZ_pE& a, const vec_ZZ_pE& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  

/**************************************************************************\

                       Arithmetic mod X^n

Required: n >= 0; otherwise, an error is raised.

\**************************************************************************/

void trunc(ZZ_pEX& x, const ZZ_pEX& a, long n); // x = a % X^n
ZZ_pEX trunc(const ZZ_pEX& a, long n);

void MulTrunc(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, long n);
ZZ_pEX MulTrunc(const ZZ_pEX& a, const ZZ_pEX& b, long n);
// x = a * b % X^n

void SqrTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n);
ZZ_pEX SqrTrunc(const ZZ_pEX& a, long n);
// x = a^2 % X^n

void InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n);
ZZ_pEX InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.


NOTE: if you want to do many computations with a fixed f, use the
ZZ_pEXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f);
ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f);
// x = (a * b) % f

void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEX& f);
// x = a^2 % f

void MulByXMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pEX MulByXMod(const ZZ_pEX& a, const ZZ_pEX& f);
// x = (a * X) mod f

void InvMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pEX InvMod(const ZZ_pEX& a, const ZZ_pEX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
ZZ_pEXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

As an example, the following routine the product modulo f of a vector
of polynomials.

#include <NTL/ZZ_pEX.h>

void product(ZZ_pEX& x, const vec_ZZ_pEX& v, const ZZ_pEX& f)
{
   ZZ_pEXModulus F(f);
   ZZ_pEX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}

NOTE: A ZZ_pEX may be used wherever a ZZ_pEXModulus is required,
and a ZZ_pEXModulus may be used wherever a ZZ_pEX is required.


\**************************************************************************/

class ZZ_pEXModulus {
public:
   ZZ_pEXModulus(); // initially in an unusable state

   ZZ_pEXModulus(const ZZ_pEX& f); // initialize with f, deg(f) > 0

   ZZ_pEXModulus(const ZZ_pEXModulus&); // copy

   ZZ_pEXModulus& operator=(const ZZ_pEXModulus&); // assignment

   ~ZZ_pEXModulus(); // destructor

   operator const ZZ_pEX& () const; // implicit read-only access to f

   const ZZ_pEX& val() const; // explicit read-only access to f
};

void build(ZZ_pEXModulus& F, const ZZ_pEX& f);
// pre-computes information about f and stores it in F.  Must have
// deg(f) > 0.  Note that the declaration ZZ_pEXModulus F(f) is
// equivalent to ZZ_pEXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).


long deg(const ZZ_pEXModulus& F);  // return n=deg(f)

void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b,
            const ZZ_pEXModulus& F);
ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F);
ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ& e, const ZZ_pEXModulus& F);
ZZ_pEX PowerMod(const ZZ_pEX& a, const ZZ& e, const ZZ_pEXModulus& F);

void PowerMod(ZZ_pEX& x, const ZZ_pEX& a, long e, const ZZ_pEXModulus& F);
ZZ_pEX PowerMod(const ZZ_pEX& a, long e, const ZZ_pEXModulus& F);

// x = a^e % f; e >= 0, deg(a) < n.  Uses a sliding window algorithm.
// (e may be negative)

void PowerXMod(ZZ_pEX& x, const ZZ& e, const ZZ_pEXModulus& F);
ZZ_pEX PowerXMod(const ZZ& e, const ZZ_pEXModulus& F);

void PowerXMod(ZZ_pEX& x, long e, const ZZ_pEXModulus& F);
ZZ_pEX PowerXMod(long e, const ZZ_pEXModulus& F);

// x = X^e % f (e may be negative)

void rem(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F);
// x = a % f

void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F);
// q = a/f, r = a%f

void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F);
// q = a/f

// operator notation:

ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEXModulus& F);
ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEXModulus& F);

ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEXModulus& F);
ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEXModulus& F);



/**************************************************************************\

                             vectors of ZZ_pEX's

\**************************************************************************/


typedef Vec<ZZ_pEX> vec_ZZ_pEX; // backward compatibility



/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.


\**************************************************************************/

void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEX& h,
             const ZZ_pEXModulus& F);
ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEX& h,
                    const ZZ_pEXModulus& F);

// x = g(h) mod f; deg(h) < n

void Comp2Mod(ZZ_pEX& x1, ZZ_pEX& x2, const ZZ_pEX& g1, const ZZ_pEX& g2,
              const ZZ_pEX& h, const ZZ_pEXModulus& F);
// xi = gi(h) mod f (i=1,2); deg(h) < n.


void Comp3Mod(ZZ_pEX& x1, ZZ_pEX& x2, ZZ_pEX& x3,
              const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& g3,
              const ZZ_pEX& h, const ZZ_pEXModulus& F);
// xi = gi(h) mod f (i=1..3); deg(h) < n.



/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a ZZ_pEXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct ZZ_pEXArgument {
   vec_ZZ_pEX H;
};

void build(ZZ_pEXArgument& H, const ZZ_pEX& h, const ZZ_pEXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n.

void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEXArgument& H,
             const ZZ_pEXModulus& F);

ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEXArgument& H,
                    const ZZ_pEXModulus& F);

extern long ZZ_pEXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// ZZ_pEXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in ZZ_pEXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(ZZ_pE& x, const ZZ_pEVector& a, const ZZ_pEX& b);
ZZ_pE project(const ZZ_pEVector& a, const ZZ_pEX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k,
                   const ZZ_pEX& h, const ZZ_pEXModulus& F);

vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k,
                   const ZZ_pEX& h, const ZZ_pEXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.

void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k,
                   const ZZ_pEXArgument& H, const ZZ_pEXModulus& F);

vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k,
                   const ZZ_pEXArgument& H, const ZZ_pEXModulus& F);

// same as above, but uses a pre-computed ZZ_pEXArgument


class ZZ_pEXTransMultiplier { /* ... */ };

void build(ZZ_pEXTransMultiplier& B, const ZZ_pEX& b, const ZZ_pEXModulus& F);

void UpdateMap(vec_ZZ_pE& x, const vec_ZZ_pE& a,
               const ZZ_pEXMultiplier& B, const ZZ_pEXModulus& F);

vec_ZZ_pE UpdateMap(const vec_ZZ_pE& a,
               const ZZ_pEXMultiplier& B, const ZZ_pEXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Required: a.length() <= deg(F), deg(b) < deg(F).
// This is "transposed" MulMod by B.
// Input may have "high order" zeroes stripped.
// Output always has high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

These routines should be used only when ZZ_pE is a field.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(ZZ_pEX& h, const vec_ZZ_pE& a, long m);
ZZ_pEX MinPolySeq(const vec_ZZ_pE& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m


void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);
ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);
ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/2^{ZZ_pE::degree()}.

void MinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);
ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void MinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);
ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);
ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);
ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).

/**************************************************************************\

           Composition and Minimal Polynomials in towers

These are implementations of algorithms that will be described
and analyzed in a forthcoming paper.

The routines require that p is prime, but ZZ_pE need not be a field.

\**************************************************************************/


void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEXArgument& h,
             const ZZ_pEXModulus& F);

ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEXArgument& h,
             const ZZ_pEXModulus& F);

void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEX& h,
             const ZZ_pEXModulus& F);

ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEX& h,
             const ZZ_pEXModulus& F);


// x = g(h) mod f


void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F,
                      long m);

ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);

ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// Uses a probabilistic algorithm to compute the minimal
// polynomial of (g mod f) over ZZ_p.
// The parameter m is a bound on the degree of the minimal polynomial
// (default = deg(f)*ZZ_pE::degree()).
// In general, the result will be a divisor of the true minimimal
// polynomial.  For correct results, use the MinPoly routines below.



void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);

ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// Same as above, but result is always correct.


void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);

ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// Same as above, but assumes the minimal polynomial is
// irreducible, and uses a slightly faster, deterministic algorithm.


/**************************************************************************\

                   Traces, norms, resultants

\**************************************************************************/


void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEXModulus& F);
ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& F);

void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_ZZ_pE& S, const ZZ_pEX& f);
vec_ZZ_pE TraceVec(const ZZ_pEX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above trace routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pE NormMod(const ZZ_pEX& a, const ZZ_pEX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)

void resultant(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pE resultant(const ZZ_pEX& a, const ZZ_pEX& b);
// x = resultant(a, b)

// NormMod and resultant require that ZZ_pE is a field.




/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(ZZ_pEX& x) // x = 0
void set(ZZ_pEX& x); // x = 1

void ZZ_pEX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

ZZ_pEX::ZZ_pEX(INIT_SIZE_TYPE, long n);
// ZZ_pEX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const ZZ_pEX& zero();
// ZZ_pEX::zero() is a read-only reference to 0

void swap(ZZ_pEX& x, ZZ_pEX& y);
// swap x and y (via "pointer swapping")


ZZ_pEX::ZZ_pEX(long i, const ZZ_pE& c);
ZZ_pEX::ZZ_pEX(long i, const ZZ_p& c);
ZZ_pEX::ZZ_pEX(long i, long c);
// initialize to c*X^i, provided for backward compatibility
ntl-6.2.1/doc/ZZ_pEX.txt000644 000765 000024 00000067025 12377144460 015265 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZ_pEX SUMMARY: The class ZZ_pEX represents polynomials over ZZ_pE, and so can be used, for example, for arithmentic in GF(p^n)[X]. However, except where mathematically necessary (e.g., GCD computations), ZZ_pE need not be a field. \**************************************************************************/ #include #include class ZZ_pEX { public: ZZ_pEX(); // initial value 0 ZZ_pEX(const ZZ_pEX& a); // copy explicit ZZ_pEX(const ZZ_pE& a); // promotion explicit ZZ_pEX(const ZZ_p& a); explicit ZZ_pEX(long a); ZZ_pEX& operator=(const ZZ_pEX& a); // assignment ZZ_pEX& operator=(const ZZ_pE& a); ZZ_pEX& operator=(const ZZ_p& a); ZZ_pEX& operator=(long a); ~ZZ_pEX(); // destructor ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_pE& c); ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_p& c); ZZ_pEX(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as ZZ_pEX(INIT_MONO, i, c) ZZ_pEX(INIT_MONO_TYPE, long i); // initialize to X^i, invoke as ZZ_pEX(INIT_MONO, i) // typedefs to aid in generic programming typedef ZZ_pE coeff_type; typedef ZZ_pEXModulus modulus_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const ZZ_pEX& a); // return deg(a); deg(0) == -1. const ZZ_pE& coeff(const ZZ_pEX& a, long i); // returns the coefficient of X^i, or zero if i not in range const ZZ_pE& LeadCoeff(const ZZ_pEX& a); // returns leading term of a, or zero if a == 0 const ZZ_pE& ConstTerm(const ZZ_pEX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(ZZ_pEX& x, long i, const ZZ_pE& a); void SetCoeff(ZZ_pEX& x, long i, const ZZ_p& a); void SetCoeff(ZZ_pEX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(ZZ_pEX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(ZZ_pEX& x); // x is set to the monomial X long IsX(const ZZ_pEX& a); // test if x = X ZZ_pE& ZZ_pEX::operator[](long i); const ZZ_pE& ZZ_pEX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void ZZ_pEX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void ZZ_pEX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void ZZ_pEX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZ_pEX& a, const ZZ_pEX& b); long operator!=(const ZZ_pEX& a, const ZZ_pEX& b); long IsZero(const ZZ_pEX& a); // test for 0 long IsOne(const ZZ_pEX& a); // test for 1 // PROMOTIONS: ==, != promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX operator-(const ZZ_pEX& a); ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pE& a); ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_p& a); ZZ_pEX& operator+=(ZZ_pEX& x, long a); ZZ_pEX& operator++(ZZ_pEX& x); // prefix void operator++(ZZ_pEX& x, int); // postfix ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pE& a); ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_p& a); ZZ_pEX& operator-=(ZZ_pEX& x, long a); ZZ_pEX& operator--(ZZ_pEX& x); // prefix void operator--(ZZ_pEX& x, int); // postfix // procedural versions: void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a + b void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a - b void negate(ZZ_pEX& x, const ZZ_pEX& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pE& a); ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_p& a); ZZ_pEX& operator*=(ZZ_pEX& x, long a); // procedural versions: void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a * b void sqr(ZZ_pEX& x, const ZZ_pEX& a); // x = a^2 ZZ_pEX sqr(const ZZ_pEX& a); // PROMOTIONS: *, mul promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b). void power(ZZ_pEX& x, const ZZ_pEX& a, long e); // x = a^e (e >= 0) ZZ_pEX power(const ZZ_pEX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: ZZ_pEX operator<<(const ZZ_pEX& a, long n); ZZ_pEX operator>>(const ZZ_pEX& a, long n); ZZ_pEX& operator<<=(ZZ_pEX& x, long n); ZZ_pEX& operator>>=(ZZ_pEX& x, long n); // procedural versions: void LeftShift(ZZ_pEX& x, const ZZ_pEX& a, long n); ZZ_pEX LeftShift(const ZZ_pEX& a, long n); void RightShift(ZZ_pEX& x, const ZZ_pEX& a, long n); ZZ_pEX RightShift(const ZZ_pEX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pE& b); ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_p& b); ZZ_pEX operator/(const ZZ_pEX& a, long b); ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pE& a); ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_p& a); ZZ_pEX& operator/=(ZZ_pEX& x, long a); ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEX& a); // procedural versions: void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b); // q = a/b, r = a%b void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pE& b); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_p& b); void div(ZZ_pEX& q, const ZZ_pEX& a, long b); // q = a/b void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b); // r = a%b long divide(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZ_pEX& a, const ZZ_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 /**************************************************************************\ GCD's These routines are intended for use when ZZ_pE is a field. \**************************************************************************/ void GCD(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX GCD(const ZZ_pEX& a, const ZZ_pEX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(ZZ_pEX& d, ZZ_pEX& s, ZZ_pEX& t, const ZZ_pEX& a, const ZZ_pEX& b); // d = gcd(a,b), a s + b t = d /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be polynomials of degree < ZZ_pE::degree() and a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary polynomials which are reduced modulo ZZ_pE::modulus(), and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, ZZ_pEX& x); ostream& operator<<(ostream& s, const ZZ_pEX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(ZZ_pEX& x, const ZZ_pEX& a); // x = derivative of a ZZ_pEX diff(const ZZ_pEX& a); void MakeMonic(ZZ_pEX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case void reverse(ZZ_pEX& x, const ZZ_pEX& a, long hi); ZZ_pEX reverse(const ZZ_pEX& a, long hi); void reverse(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX reverse(const ZZ_pEX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_ZZ_pE& x, const ZZ_pEX& a, long n); vec_ZZ_pE VectorCopy(const ZZ_pEX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(ZZ_pEX& x, long n); ZZ_pEX random_ZZ_pEX(long n); // x = random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(ZZ_pEX& x, const vec_ZZ_pE& a); ZZ_pEX BuildFromRoots(const vec_ZZ_pE& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(ZZ_pE& b, const ZZ_pEX& f, const ZZ_pE& a); ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a); // b = f(a) void eval(ZZ_pE& b, const ZZ_pX& f, const ZZ_pE& a); ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a); // b = f(a); uses ModComp algorithm for ZZ_pX void eval(vec_ZZ_pE& b, const ZZ_pEX& f, const vec_ZZ_pE& a); vec_ZZ_pE eval(const ZZ_pEX& f, const vec_ZZ_pE& a); // b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(ZZ_pEX& f, const vec_ZZ_pE& a, const vec_ZZ_pE& b); ZZ_pEX interpolate(const vec_ZZ_pE& a, const vec_ZZ_pE& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. /**************************************************************************\ Arithmetic mod X^n Required: n >= 0; otherwise, an error is raised. \**************************************************************************/ void trunc(ZZ_pEX& x, const ZZ_pEX& a, long n); // x = a % X^n ZZ_pEX trunc(const ZZ_pEX& a, long n); void MulTrunc(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, long n); ZZ_pEX MulTrunc(const ZZ_pEX& a, const ZZ_pEX& b, long n); // x = a * b % X^n void SqrTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n); ZZ_pEX SqrTrunc(const ZZ_pEX& a, long n); // x = a^2 % X^n void InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n); ZZ_pEX InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the ZZ_pEXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f); ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f); // x = (a * b) % f void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEX& f); // x = a^2 % f void MulByXMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pEX MulByXMod(const ZZ_pEX& a, const ZZ_pEX& f); // x = (a * X) mod f void InvMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pEX InvMod(const ZZ_pEX& a, const ZZ_pEX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build ZZ_pEXModulus F for f. This pre-computes information about f that speeds up subsequent computations. As an example, the following routine the product modulo f of a vector of polynomials. #include void product(ZZ_pEX& x, const vec_ZZ_pEX& v, const ZZ_pEX& f) { ZZ_pEXModulus F(f); ZZ_pEX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } NOTE: A ZZ_pEX may be used wherever a ZZ_pEXModulus is required, and a ZZ_pEXModulus may be used wherever a ZZ_pEX is required. \**************************************************************************/ class ZZ_pEXModulus { public: ZZ_pEXModulus(); // initially in an unusable state ZZ_pEXModulus(const ZZ_pEX& f); // initialize with f, deg(f) > 0 ZZ_pEXModulus(const ZZ_pEXModulus&); // copy ZZ_pEXModulus& operator=(const ZZ_pEXModulus&); // assignment ~ZZ_pEXModulus(); // destructor operator const ZZ_pEX& () const; // implicit read-only access to f const ZZ_pEX& val() const; // explicit read-only access to f }; void build(ZZ_pEXModulus& F, const ZZ_pEX& f); // pre-computes information about f and stores it in F. Must have // deg(f) > 0. Note that the declaration ZZ_pEXModulus F(f) is // equivalent to ZZ_pEXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const ZZ_pEXModulus& F); // return n=deg(f) void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F); ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F); ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ& e, const ZZ_pEXModulus& F); ZZ_pEX PowerMod(const ZZ_pEX& a, const ZZ& e, const ZZ_pEXModulus& F); void PowerMod(ZZ_pEX& x, const ZZ_pEX& a, long e, const ZZ_pEXModulus& F); ZZ_pEX PowerMod(const ZZ_pEX& a, long e, const ZZ_pEXModulus& F); // x = a^e % f; e >= 0, deg(a) < n. Uses a sliding window algorithm. // (e may be negative) void PowerXMod(ZZ_pEX& x, const ZZ& e, const ZZ_pEXModulus& F); ZZ_pEX PowerXMod(const ZZ& e, const ZZ_pEXModulus& F); void PowerXMod(ZZ_pEX& x, long e, const ZZ_pEXModulus& F); ZZ_pEX PowerXMod(long e, const ZZ_pEXModulus& F); // x = X^e % f (e may be negative) void rem(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F); // x = a % f void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F); // q = a/f, r = a%f void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F); // q = a/f // operator notation: ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEXModulus& F); ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEXModulus& F); ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEXModulus& F); ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEXModulus& F); /**************************************************************************\ vectors of ZZ_pEX's \**************************************************************************/ typedef Vec vec_ZZ_pEX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(ZZ_pEX& x1, ZZ_pEX& x2, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& h, const ZZ_pEXModulus& F); // xi = gi(h) mod f (i=1,2); deg(h) < n. void Comp3Mod(ZZ_pEX& x1, ZZ_pEX& x2, ZZ_pEX& x3, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& g3, const ZZ_pEX& h, const ZZ_pEXModulus& F); // xi = gi(h) mod f (i=1..3); deg(h) < n. /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a ZZ_pEXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct ZZ_pEXArgument { vec_ZZ_pEX H; }; void build(ZZ_pEXArgument& H, const ZZ_pEX& h, const ZZ_pEXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n. void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); extern long ZZ_pEXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // ZZ_pEXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in ZZ_pEXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(ZZ_pE& x, const ZZ_pEVector& a, const ZZ_pEX& b); ZZ_pE project(const ZZ_pEVector& a, const ZZ_pEX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F); vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); // same as above, but uses a pre-computed ZZ_pEXArgument class ZZ_pEXTransMultiplier { /* ... */ }; void build(ZZ_pEXTransMultiplier& B, const ZZ_pEX& b, const ZZ_pEXModulus& F); void UpdateMap(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pEXMultiplier& B, const ZZ_pEXModulus& F); vec_ZZ_pE UpdateMap(const vec_ZZ_pE& a, const ZZ_pEXMultiplier& B, const ZZ_pEXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Required: a.length() <= deg(F), deg(b) < deg(F). // This is "transposed" MulMod by B. // Input may have "high order" zeroes stripped. // Output always has high order zeroes stripped. /**************************************************************************\ Minimum Polynomials These routines should be used only when ZZ_pE is a field. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(ZZ_pEX& h, const vec_ZZ_pE& a, long m); ZZ_pEX MinPolySeq(const vec_ZZ_pE& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/2^{ZZ_pE::degree()}. void MinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void MinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Composition and Minimal Polynomials in towers These are implementations of algorithms that will be described and analyzed in a forthcoming paper. The routines require that p is prime, but ZZ_pE need not be a field. \**************************************************************************/ void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEXArgument& h, const ZZ_pEXModulus& F); ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEXArgument& h, const ZZ_pEXModulus& F); void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); // x = g(h) mod f void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F); // Uses a probabilistic algorithm to compute the minimal // polynomial of (g mod f) over ZZ_p. // The parameter m is a bound on the degree of the minimal polynomial // (default = deg(f)*ZZ_pE::degree()). // In general, the result will be a divisor of the true minimimal // polynomial. For correct results, use the MinPoly routines below. void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F); // Same as above, but result is always correct. void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F); // Same as above, but assumes the minimal polynomial is // irreducible, and uses a slightly faster, deterministic algorithm. /**************************************************************************\ Traces, norms, resultants \**************************************************************************/ void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEXModulus& F); ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& F); void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_ZZ_pE& S, const ZZ_pEX& f); vec_ZZ_pE TraceVec(const ZZ_pEX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above trace routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pE NormMod(const ZZ_pEX& a, const ZZ_pEX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pE resultant(const ZZ_pEX& a, const ZZ_pEX& b); // x = resultant(a, b) // NormMod and resultant require that ZZ_pE is a field. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZ_pEX& x) // x = 0 void set(ZZ_pEX& x); // x = 1 void ZZ_pEX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). ZZ_pEX::ZZ_pEX(INIT_SIZE_TYPE, long n); // ZZ_pEX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const ZZ_pEX& zero(); // ZZ_pEX::zero() is a read-only reference to 0 void swap(ZZ_pEX& x, ZZ_pEX& y); // swap x and y (via "pointer swapping") ZZ_pEX::ZZ_pEX(long i, const ZZ_pE& c); ZZ_pEX::ZZ_pEX(long i, const ZZ_p& c); ZZ_pEX::ZZ_pEX(long i, long c); // initialize to c*X^i, provided for backward compatibility ntl-6.2.1/doc/ZZ_pEXFactoring.cpp.html000644 000765 000024 00000030704 12377144460 020022 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZ_pEXFactoring.cpp.html

/**************************************************************************\

MODULE: ZZ_pEXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over ZZ_pE, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/ZZ_pEX.h>
#include <NTL/pair_ZZ_pEX_long.h>

void SquareFreeDecomp(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& f);
vec_pair_ZZ_pEX_long SquareFreeDecomp(const ZZ_pEX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a list of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_ZZ_pE& x, const ZZ_pEX& f);
vec_ZZ_pE FindRoots(const ZZ_pEX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(ZZ_pE& root, const ZZ_pEX& f);
ZZ_pE FindRoot(const ZZ_pEX& f);

// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void NewDDF(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f,
            const ZZ_pEX& h, long verbose=0);

vec_pair_ZZ_pEX_long NewDDF(const ZZ_pEX& f, const ZZ_pEX& h,
         long verbose=0);


// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^{ZZ_pE::cardinality()} mod f.  

// This routine implements the baby step/giant step algorithm
// of [Kaltofen and Shoup, STOC 1995].
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

// NOTE: When factoring "large" polynomials,
// this routine uses external files to store some intermediate
// results, which are removed if the routine terminates normally.
// These files are stored in the current directory under names of the
// form ddf-*-baby-* and ddf-*-giant-*.
// The definition of "large" is controlled by the variable

      extern double ZZ_pEXFileThresh

// which can be set by the user.  If the sizes of the tables
// exceeds ZZ_pEXFileThresh KB, external files are used.
// Initial value is NTL_FILE_THRESH (defined in tools.h).




void EDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& h,
         long d, long verbose=0);

vec_ZZ_pEX EDF(const ZZ_pEX& f, const ZZ_pEX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  h = X^{ZZ_pE::cardinality()} mod
// f.  d = degree of irreducible factors of f.  This routine
// implements the algorithm of [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void RootEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0);
vec_ZZ_pEX RootEDF(const ZZ_pEX& f, long verbose=0);

// EDF for d==1


void SFCanZass(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0);
vec_ZZ_pEX SFCanZass(const ZZ_pEX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f,
             long verbose=0);

vec_pair_ZZ_pEX_long CanZass(const ZZ_pEX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: these routines use modular composition.  The space
// used for the required tables can be controlled by the variable
// ZZ_pEXArgBound (see ZZ_pEX.txt).



void mul(ZZ_pEX& f, const vec_pair_ZZ_pEX_long& v);
ZZ_pEX mul(const vec_pair_ZZ_pEX_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const ZZ_pEX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// ZZ_pE::cardinality()^{-iter}.  This implements an algorithm from [Shoup,
// J. Symbolic Comp. 17:371-391, 1994].

long DetIrredTest(const ZZ_pEX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const ZZ_pEX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(ZZ_pEX& f, long n);
ZZ_pEX BuildIrred_ZZ_pEX(long n);

// Build a monic irreducible poly of degree n. 

void BuildRandomIrred(ZZ_pEX& f, const ZZ_pEX& g);
ZZ_pEX BuildRandomIrred(const ZZ_pEX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.


long IterComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F);

// f is assumed to be an "equal degree" polynomial, and h =
// X^{ZZ_pE::cardinality()} mod f.  The common degree of the irreducible 
// factors of f is computed.  Uses a "baby step/giant step" algorithm, similar
// to NewDDF.  Although asymptotocally slower than RecComputeDegree
// (below), it is faster for reasonably sized inputs.

long RecComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F);

// f is assumed to be an "equal degree" polynomial, 
// h = X^{ZZ_pE::cardinality()} mod f.  
// The common degree of the irreducible factors of f is
// computed Uses a recursive algorithm similar to DetIrredTest.

void TraceMap(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F,
              const ZZ_pEX& h);

ZZ_pEX TraceMap(const ZZ_pEX& a, long d, const ZZ_pEXModulus& F,
              const ZZ_pEX& h);

// Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0,
// and h = X^q mod f, q a power of ZZ_pE::cardinality().  This routine
// implements an algorithm from [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void PowerCompose(ZZ_pEX& w, const ZZ_pEX& h, long d, const ZZ_pEXModulus& F);

ZZ_pEX PowerCompose(const ZZ_pEX& h, long d, const ZZ_pEXModulus& F);

// Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q
// mod f, q a power of ZZ_pE::cardinality().  This routine implements an
// algorithm from [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992]

ntl-6.2.1/doc/ZZ_pEXFactoring.txt000644 000765 000024 00000015010 12377144460 017105 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZ_pEXFactoring SUMMARY: Routines are provided for factorization of polynomials over ZZ_pE, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& f); vec_pair_ZZ_pEX_long SquareFreeDecomp(const ZZ_pEX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a list of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_ZZ_pE& x, const ZZ_pEX& f); vec_ZZ_pE FindRoots(const ZZ_pEX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(ZZ_pE& root, const ZZ_pEX& f); ZZ_pE FindRoot(const ZZ_pEX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void NewDDF(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, const ZZ_pEX& h, long verbose=0); vec_pair_ZZ_pEX_long NewDDF(const ZZ_pEX& f, const ZZ_pEX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^{ZZ_pE::cardinality()} mod f. // This routine implements the baby step/giant step algorithm // of [Kaltofen and Shoup, STOC 1995]. // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. // NOTE: When factoring "large" polynomials, // this routine uses external files to store some intermediate // results, which are removed if the routine terminates normally. // These files are stored in the current directory under names of the // form ddf-*-baby-* and ddf-*-giant-*. // The definition of "large" is controlled by the variable extern double ZZ_pEXFileThresh // which can be set by the user. If the sizes of the tables // exceeds ZZ_pEXFileThresh KB, external files are used. // Initial value is NTL_FILE_THRESH (defined in tools.h). void EDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& h, long d, long verbose=0); vec_ZZ_pEX EDF(const ZZ_pEX& f, const ZZ_pEX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. h = X^{ZZ_pE::cardinality()} mod // f. d = degree of irreducible factors of f. This routine // implements the algorithm of [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void RootEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0); vec_ZZ_pEX RootEDF(const ZZ_pEX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0); vec_ZZ_pEX SFCanZass(const ZZ_pEX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, long verbose=0); vec_pair_ZZ_pEX_long CanZass(const ZZ_pEX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: these routines use modular composition. The space // used for the required tables can be controlled by the variable // ZZ_pEXArgBound (see ZZ_pEX.txt). void mul(ZZ_pEX& f, const vec_pair_ZZ_pEX_long& v); ZZ_pEX mul(const vec_pair_ZZ_pEX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const ZZ_pEX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // ZZ_pE::cardinality()^{-iter}. This implements an algorithm from [Shoup, // J. Symbolic Comp. 17:371-391, 1994]. long DetIrredTest(const ZZ_pEX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const ZZ_pEX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(ZZ_pEX& f, long n); ZZ_pEX BuildIrred_ZZ_pEX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(ZZ_pEX& f, const ZZ_pEX& g); ZZ_pEX BuildRandomIrred(const ZZ_pEX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. long IterComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F); // f is assumed to be an "equal degree" polynomial, and h = // X^{ZZ_pE::cardinality()} mod f. The common degree of the irreducible // factors of f is computed. Uses a "baby step/giant step" algorithm, similar // to NewDDF. Although asymptotocally slower than RecComputeDegree // (below), it is faster for reasonably sized inputs. long RecComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F); // f is assumed to be an "equal degree" polynomial, // h = X^{ZZ_pE::cardinality()} mod f. // The common degree of the irreducible factors of f is // computed Uses a recursive algorithm similar to DetIrredTest. void TraceMap(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& h); ZZ_pEX TraceMap(const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& h); // Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, // and h = X^q mod f, q a power of ZZ_pE::cardinality(). This routine // implements an algorithm from [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void PowerCompose(ZZ_pEX& w, const ZZ_pEX& h, long d, const ZZ_pEXModulus& F); ZZ_pEX PowerCompose(const ZZ_pEX& h, long d, const ZZ_pEXModulus& F); // Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q // mod f, q a power of ZZ_pE::cardinality(). This routine implements an // algorithm from [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992] ntl-6.2.1/doc/ZZ_pX.cpp.html000644 000765 000024 00000154233 12377144460 016064 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZ_pX.cpp.html

/**************************************************************************\

MODULE: ZZ_pX

SUMMARY:

The class ZZ_pX implements polynomial arithmetic modulo p.

Polynomial arithmetic is implemented using the FFT, combined with the
Chinese Remainder Theorem.  A more detailed description of the
techniques used here can be found in [Shoup, J. Symbolic
Comp. 20:363-397, 1995].

Small degree polynomials are multiplied either with classical 
or Karatsuba algorithms.

\**************************************************************************/

#include <NTL/ZZ_p.h>
#include <NTL/vec_ZZ_p.h>

class ZZ_pX {
public:

   ZZ_pX(); // initialize to 0

   ZZ_pX(const ZZ_pX& a); // copy constructor
   explicit ZZ_pX(const ZZ_p& a); // promotion 
   explicit ZZ_pX(long a); // promotion 

   ZZ_pX& operator=(const ZZ_pX& a); // assignment
   ZZ_pX& operator=(const ZZ_p& a); // assignment
   ZZ_pX& operator=(const long a); // assignment

   ~ZZ_pX(); // destructor

   ZZ_pX(INIT_MONO_TYPE, long i, const ZZ_p& c);
   ZZ_pX(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as ZZ_pX(INIT_MONO, i, c)

   ZZ_pX(INIT_MONO_TYPE, long i, long c);
   // initialize to X^i, invoke as ZZ_pX(INIT_MONO, i)


   // typedefs to aid in generic programming
   typedef zz_p coeff_type;
   typedef zz_pE residue_type;
   typedef zz_pXModulus modulus_type;
   typedef zz_pXMultiplier multiplier_type;
   typedef fftRep fft_type;


   // ...


};





/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const ZZ_pX& a);  // return deg(a); deg(0) == -1.

const ZZ_p& coeff(const ZZ_pX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const ZZ_p& LeadCoeff(const ZZ_pX& a);
// returns leading term of a, or zero if a == 0

const ZZ_p& ConstTerm(const ZZ_pX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(ZZ_pX& x, long i, const ZZ_p& a);
void SetCoeff(ZZ_pX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(ZZ_pX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(ZZ_pX& x); // x is set to the monomial X

long IsX(const ZZ_pX& a); // test if x = X




ZZ_p& ZZ_pX::operator[](long i);
const ZZ_p& ZZ_pX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).


void ZZ_pX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void ZZ_pX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void ZZ_pX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const ZZ_pX& a, const ZZ_pX& b);
long operator!=(const ZZ_pX& a, const ZZ_pX& b);

// PROMOTIONS: operators ==, != promote {long, ZZ_p} to ZZ_pX on (a, b).

long IsZero(const ZZ_pX& a); // test for 0
long IsOne(const ZZ_pX& a); // test for 1


/**************************************************************************\

                                   Addition

\**************************************************************************/


// operator notation:

ZZ_pX operator+(const ZZ_pX& a, const ZZ_pX& b);
ZZ_pX operator-(const ZZ_pX& a, const ZZ_pX& b);

ZZ_pX operator-(const ZZ_pX& a); // unary -

ZZ_pX& operator+=(ZZ_pX& x, const ZZ_pX& a);
ZZ_pX& operator+=(ZZ_pX& x, const ZZ_p& a);
ZZ_pX& operator+=(ZZ_pX& x, long a);

ZZ_pX& operator-=(ZZ_pX& x, const ZZ_pX& a);
ZZ_pX& operator-=(ZZ_pX& x, const ZZ_p& a);
ZZ_pX& operator-=(ZZ_pX& x, long a);

ZZ_pX& operator++(ZZ_pX& x);  // prefix
void operator++(ZZ_pX& x, int);  // postfix

ZZ_pX& operator--(ZZ_pX& x);  // prefix
void operator--(ZZ_pX& x, int);  // postfix

// procedural versions:


void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a + b
void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a - b
void negate(ZZ_pX& x, const ZZ_pX& a); // x = -a


// PROMOTIONS: binary +, - and procedures add, sub promote
// {long, ZZ_p} to ZZ_pX on (a, b).


/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

ZZ_pX operator*(const ZZ_pX& a, const ZZ_pX& b);

ZZ_pX& operator*=(ZZ_pX& x, const ZZ_pX& a);
ZZ_pX& operator*=(ZZ_pX& x, const ZZ_p& a);
ZZ_pX& operator*=(ZZ_pX& x, long a);

// procedural versions:

void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a * b

void sqr(ZZ_pX& x, const ZZ_pX& a); // x = a^2
ZZ_pX sqr(const ZZ_pX& a);

// PROMOTIONS: operator * and procedure mul promote {long, ZZ_p} to ZZ_pX
// on (a, b).

void power(ZZ_pX& x, const ZZ_pX& a, long e);  // x = a^e (e >= 0)
ZZ_pX power(const ZZ_pX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

ZZ_pX operator<<(const ZZ_pX& a, long n);
ZZ_pX operator>>(const ZZ_pX& a, long n);

ZZ_pX& operator<<=(ZZ_pX& x, long n);
ZZ_pX& operator>>=(ZZ_pX& x, long n);

// procedural versions:

void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n);
ZZ_pX LeftShift(const ZZ_pX& a, long n);

void RightShift(ZZ_pX& x, const ZZ_pX& a, long n);
ZZ_pX RightShift(const ZZ_pX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

ZZ_pX operator/(const ZZ_pX& a, const ZZ_pX& b);
ZZ_pX operator/(const ZZ_pX& a, const ZZ_p& b);
ZZ_pX operator/(const ZZ_pX& a, long b);


ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pX& b);
ZZ_pX& operator/=(ZZ_pX& x, const ZZ_p& b);
ZZ_pX& operator/=(ZZ_pX& x, long b);

ZZ_pX operator%(const ZZ_pX& a, const ZZ_pX& b);

ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pX& b);


// procedural versions:


void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b);
// q = a/b, r = a%b

void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b);
void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_p& b);
void div(ZZ_pX& q, const ZZ_pX& a, long b);
// q = a/b

void rem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b);
// r = a%b

long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const ZZ_pX& a, const ZZ_pX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


/**************************************************************************\

                                   GCD's

These routines are intended for use when p is prime.

\**************************************************************************/


void GCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b);
ZZ_pX GCD(const ZZ_pX& a, const ZZ_pX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b);
// d = gcd(a,b), a s + b t = d 


// NOTE: A classical algorithm is used, switching over to a
// "half-GCD" algorithm for large degree


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be integers between 0 and p-1, and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary integers which are reduced modulo p, and leading zeros
stripped.

\**************************************************************************/

istream& operator>>(istream& s, ZZ_pX& x);
ostream& operator<<(ostream& s, const ZZ_pX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/

void diff(ZZ_pX& x, const ZZ_pX& a); // x = derivative of a
ZZ_pX diff(const ZZ_pX& a);

void MakeMonic(ZZ_pX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case.

void reverse(ZZ_pX& x, const ZZ_pX& a, long hi);
ZZ_pX reverse(const ZZ_pX& a, long hi);

void reverse(ZZ_pX& x, const ZZ_pX& a);
ZZ_pX reverse(const ZZ_pX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_ZZ_p& x, const ZZ_pX& a, long n);
vec_ZZ_p VectorCopy(const ZZ_pX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(ZZ_pX& x, long n);
ZZ_pX random_ZZ_pX(long n);
// generate a random polynomial of degree < n 



/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a);
ZZ_pX BuildFromRoots(const vec_ZZ_p& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length()

void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a);
ZZ_p eval(const ZZ_pX& f, const ZZ_p& a);
// b = f(a)

void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a);
vec_ZZ_p eval(const ZZ_pX& f, const vec_ZZ_p& a);
//  b.SetLength(a.length()).  b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b);
ZZ_pX interpolate(const vec_ZZ_p& a, const vec_ZZ_p& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  p should
// be prime.

/**************************************************************************\

                       Arithmetic mod X^n

All routines require n >= 0, otherwise an error is raised.

\**************************************************************************/

void trunc(ZZ_pX& x, const ZZ_pX& a, long n); // x = a % X^n
ZZ_pX trunc(const ZZ_pX& a, long n);

void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n);
ZZ_pX MulTrunc(const ZZ_pX& a, const ZZ_pX& b, long n);
// x = a * b % X^n

void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n);
ZZ_pX SqrTrunc(const ZZ_pX& a, long n);
// x = a^2 % X^n

void InvTrunc(ZZ_pX& x, const ZZ_pX& a, long n);
ZZ_pX InvTrunc(const ZZ_pX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.

NOTE: if you want to do many computations with a fixed f, use the
ZZ_pXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f);
ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f);
// x = (a * b) % f

void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pX& f);
// x = a^2 % f

void MulByXMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_pX MulByXMod(const ZZ_pX& a, const ZZ_pX& f);
// x = (a * X) mod f

void InvMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_pX InvMod(const ZZ_pX& a, const ZZ_pX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


// for modular exponentiation, see below



/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build a
ZZ_pXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

It is required that deg(f) > 0 and that LeadCoeff(f) is invertible.

As an example, the following routine computes the product modulo f of a vector
of polynomials.

#include <NTL/ZZ_pX.h>

void product(ZZ_pX& x, const vec_ZZ_pX& v, const ZZ_pX& f)
{
   ZZ_pXModulus F(f);
   ZZ_pX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}

Note that automatic conversions are provided so that a ZZ_pX can
be used wherever a ZZ_pXModulus is required, and a ZZ_pXModulus
can be used wherever a ZZ_pX is required.

\**************************************************************************/


class ZZ_pXModulus {
public:
   ZZ_pXModulus(); // initially in an unusable state

   ZZ_pXModulus(const ZZ_pXModulus&);  // copy

   ZZ_pXModulus& operator=(const ZZ_pXModulus&); // assignment

   ~ZZ_pXModulus();

   ZZ_pXModulus(const ZZ_pX& f); // initialize with f, deg(f) > 0

   operator const ZZ_pX& () const;
   // read-only access to f, implicit conversion operator

   const ZZ_pX& val() const;
   // read-only access to f, explicit notation

};

void build(ZZ_pXModulus& F, const ZZ_pX& f);
// pre-computes information about f and stores it in F.
// Note that the declaration ZZ_pXModulus F(f) is equivalent to
// ZZ_pXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).

long deg(const ZZ_pXModulus& F);  // return n=deg(f)

void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F);
ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F);
ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(ZZ_pX& x, const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F);
ZZ_pX PowerMod(const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F);

void PowerMod(ZZ_pX& x, const ZZ_pX& a, long e, const ZZ_pXModulus& F);
ZZ_pX PowerMod(const ZZ_pX& a, long e, const ZZ_pXModulus& F);

// x = a^e % f; deg(a) < n (e may be negative)

void PowerXMod(ZZ_pX& x, const ZZ& e, const ZZ_pXModulus& F);
ZZ_pX PowerXMod(const ZZ& e, const ZZ_pXModulus& F);

void PowerXMod(ZZ_pX& x, long e, const ZZ_pXModulus& F);
ZZ_pX PowerXMod(long e, const ZZ_pXModulus& F);

// x = X^e % f (e may be negative)

void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, const ZZ& e,
                    const ZZ_pXModulus& F);

ZZ_pX PowerXPlusAMod(const ZZ_p& a, const ZZ& e,
                           const ZZ_pXModulus& F);

void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, long e,
                    const ZZ_pXModulus& F);

ZZ_pX PowerXPlusAMod(const ZZ_p& a, long e,
                           const ZZ_pXModulus& F);

// x = (X + a)^e % f (e may be negative)


void rem(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F);
// x = a % f

void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pXModulus& F);
// q = a/f, r = a%f

void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pXModulus& F);
// q = a/f

// operator notation:

ZZ_pX operator/(const ZZ_pX& a, const ZZ_pXModulus& F);
ZZ_pX operator%(const ZZ_pX& a, const ZZ_pXModulus& F);

ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pXModulus& F);
ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pXModulus& F);



/**************************************************************************\


                                More Pre-Conditioning

If you need to compute a * b % f for a fixed b, but for many a's, it
is much more efficient to first build a ZZ_pXMultiplier B for b, and
then use the MulMod routine below.

Here is an example that multiplies each element of a vector by a fixed
polynomial modulo f.

#include <NTL/ZZ_pX.h>

void mul(vec_ZZ_pX& v, const ZZ_pX& b, const ZZ_pX& f)
{
   ZZ_pXModulus F(f);
   ZZ_pXMultiplier B(b, F);
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(v[i], v[i], B, F);
}

\**************************************************************************/


class ZZ_pXMultiplier {
public:
   ZZ_pXMultiplier(); // initially zero

   ZZ_pXMultiplier(const ZZ_pX& b, const ZZ_pXModulus& F);
      // initializes with b mod F, where deg(b) < deg(F)

   ZZ_pXMultiplier(const ZZ_pXMultiplier&);  // copy

   ZZ_pXMultiplier& operator=(const ZZ_pXMultiplier&);  // assignment

   ~ZZ_pXMultiplier();

   const ZZ_pX& val() const; // read-only access to b

};


void build(ZZ_pXMultiplier& B, const ZZ_pX& b, const ZZ_pXModulus& F);
// pre-computes information about b and stores it in B; deg(b) <
// deg(F)

void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXMultiplier& B,
                                      const ZZ_pXModulus& F);

// x = (a * b) % F; deg(a) < deg(F)

/**************************************************************************\

                             vectors of ZZ_pX's

\**************************************************************************/

typedef Vec<ZZ_pX> vec_ZZ_pX; // backward compatibility


/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.


\**************************************************************************/

void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F);
ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pX& h,
                    const ZZ_pXModulus& F);

// x = g(h) mod f; deg(h) < n

void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2,
              const ZZ_pX& h, const ZZ_pXModulus& F);
// xi = gi(h) mod f (i=1,2); deg(h) < n.

void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3,
              const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3,
              const ZZ_pX& h, const ZZ_pXModulus& F);
// xi = gi(h) mod f (i=1..3); deg(h) < n.


/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a ZZ_pXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct ZZ_pXArgument {
   vec_ZZ_pX H;
};

void build(ZZ_pXArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n.

void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& H,
             const ZZ_pXModulus& F);

ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pXArgument& H,
                    const ZZ_pXModulus& F);

extern long ZZ_pXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// ZZ_pXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in ZZ_pXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(ZZ_p& x, const ZZ_pVector& a, const ZZ_pX& b);
ZZ_p project(const ZZ_pVector& a, const ZZ_pX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k,
                   const ZZ_pX& h, const ZZ_pXModulus& F);

vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k,
                   const ZZ_pX& h, const ZZ_pXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.

void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k,
                   const ZZ_pXArgument& H, const ZZ_pXModulus& F);

vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k,
                   const ZZ_pXArgument& H, const ZZ_pXModulus& F);

// same as above, but uses a pre-computed ZZ_pXArgument


void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a,
               const ZZ_pXMultiplier& B, const ZZ_pXModulus& F);

vec_ZZ_p UpdateMap(const vec_ZZ_p& a,
               const ZZ_pXMultiplier& B, const ZZ_pXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Restriction: must have a.length() <= deg(F).
// This is "transposed" MulMod by B.
// Input may have "high order" zeroes stripped.
// Output will always have high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

These routines should be used with prime p.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m);
ZZ_pX MinPolySeq(const vec_ZZ_p& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m

void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m);
ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m);

void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F);
ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/p.

void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m);
ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m);

void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F);
ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m);
ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m);

void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F);
ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).


/**************************************************************************\

                   Traces, norms, resultants

These routines should be used with prime p.

\**************************************************************************/


void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F);
ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& F);

void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_ZZ_p& S, const ZZ_pX& f);
vec_ZZ_p TraceVec(const ZZ_pX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above trace routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_p NormMod(const ZZ_pX& a, const ZZ_pX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)

void resultant(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& b);
ZZ_p resultant(const ZZ_pX& a, const ZZ_pX& b);
// x = resultant(a, b)

void CharPolyMod(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& f);
ZZ_pX CharPolyMod(const ZZ_pX& a, const ZZ_pX& f);
// g = charcteristic polynomial of (a mod f); 0 < deg(f), deg(g) <
// deg(f);  this routine works for arbitrary f;  if f is irreducible,
// it is faster to use the IrredPolyMod routine, and then exponentiate
// if necessary (since in this case the CharPoly is just a power of
// the IrredPoly).


/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(ZZ_pX& x) // x = 0
void set(ZZ_pX& x); // x = 1

void ZZ_pX::kill();
// f.kill() sets f to 0 and frees all memory held by f; Equivalent to
// f.rep.kill().

ZZ_pX::ZZ_pX(INIT_SIZE_TYPE, long n);
// ZZ_pX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const ZZ_pX& ZZ_pX::zero();
// ZZ_pX::zero() is a read-only reference to 0

void swap(ZZ_pX& x, ZZ_pX& y);
// swap x and y (via "pointer swapping")


ZZ_pX::ZZ_pX(long i, const ZZ_p& c);
ZZ_pX::ZZ_pX(long i, long c);
// initialize to c*X^i, provided for backward compatibility
ntl-6.2.1/doc/ZZ_pX.txt000644 000765 000024 00000065522 12377144460 015160 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZ_pX SUMMARY: The class ZZ_pX implements polynomial arithmetic modulo p. Polynomial arithmetic is implemented using the FFT, combined with the Chinese Remainder Theorem. A more detailed description of the techniques used here can be found in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. Small degree polynomials are multiplied either with classical or Karatsuba algorithms. \**************************************************************************/ #include #include class ZZ_pX { public: ZZ_pX(); // initialize to 0 ZZ_pX(const ZZ_pX& a); // copy constructor explicit ZZ_pX(const ZZ_p& a); // promotion explicit ZZ_pX(long a); // promotion ZZ_pX& operator=(const ZZ_pX& a); // assignment ZZ_pX& operator=(const ZZ_p& a); // assignment ZZ_pX& operator=(const long a); // assignment ~ZZ_pX(); // destructor ZZ_pX(INIT_MONO_TYPE, long i, const ZZ_p& c); ZZ_pX(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as ZZ_pX(INIT_MONO, i, c) ZZ_pX(INIT_MONO_TYPE, long i, long c); // initialize to X^i, invoke as ZZ_pX(INIT_MONO, i) // typedefs to aid in generic programming typedef zz_p coeff_type; typedef zz_pE residue_type; typedef zz_pXModulus modulus_type; typedef zz_pXMultiplier multiplier_type; typedef fftRep fft_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const ZZ_pX& a); // return deg(a); deg(0) == -1. const ZZ_p& coeff(const ZZ_pX& a, long i); // returns the coefficient of X^i, or zero if i not in range const ZZ_p& LeadCoeff(const ZZ_pX& a); // returns leading term of a, or zero if a == 0 const ZZ_p& ConstTerm(const ZZ_pX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(ZZ_pX& x, long i, const ZZ_p& a); void SetCoeff(ZZ_pX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(ZZ_pX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(ZZ_pX& x); // x is set to the monomial X long IsX(const ZZ_pX& a); // test if x = X ZZ_p& ZZ_pX::operator[](long i); const ZZ_p& ZZ_pX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void ZZ_pX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void ZZ_pX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void ZZ_pX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZ_pX& a, const ZZ_pX& b); long operator!=(const ZZ_pX& a, const ZZ_pX& b); // PROMOTIONS: operators ==, != promote {long, ZZ_p} to ZZ_pX on (a, b). long IsZero(const ZZ_pX& a); // test for 0 long IsOne(const ZZ_pX& a); // test for 1 /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ_pX operator+(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX operator-(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX operator-(const ZZ_pX& a); // unary - ZZ_pX& operator+=(ZZ_pX& x, const ZZ_pX& a); ZZ_pX& operator+=(ZZ_pX& x, const ZZ_p& a); ZZ_pX& operator+=(ZZ_pX& x, long a); ZZ_pX& operator-=(ZZ_pX& x, const ZZ_pX& a); ZZ_pX& operator-=(ZZ_pX& x, const ZZ_p& a); ZZ_pX& operator-=(ZZ_pX& x, long a); ZZ_pX& operator++(ZZ_pX& x); // prefix void operator++(ZZ_pX& x, int); // postfix ZZ_pX& operator--(ZZ_pX& x); // prefix void operator--(ZZ_pX& x, int); // postfix // procedural versions: void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a + b void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a - b void negate(ZZ_pX& x, const ZZ_pX& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub promote // {long, ZZ_p} to ZZ_pX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ_pX operator*(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX& operator*=(ZZ_pX& x, const ZZ_pX& a); ZZ_pX& operator*=(ZZ_pX& x, const ZZ_p& a); ZZ_pX& operator*=(ZZ_pX& x, long a); // procedural versions: void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a * b void sqr(ZZ_pX& x, const ZZ_pX& a); // x = a^2 ZZ_pX sqr(const ZZ_pX& a); // PROMOTIONS: operator * and procedure mul promote {long, ZZ_p} to ZZ_pX // on (a, b). void power(ZZ_pX& x, const ZZ_pX& a, long e); // x = a^e (e >= 0) ZZ_pX power(const ZZ_pX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: ZZ_pX operator<<(const ZZ_pX& a, long n); ZZ_pX operator>>(const ZZ_pX& a, long n); ZZ_pX& operator<<=(ZZ_pX& x, long n); ZZ_pX& operator>>=(ZZ_pX& x, long n); // procedural versions: void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n); ZZ_pX LeftShift(const ZZ_pX& a, long n); void RightShift(ZZ_pX& x, const ZZ_pX& a, long n); ZZ_pX RightShift(const ZZ_pX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ_pX operator/(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX operator/(const ZZ_pX& a, const ZZ_p& b); ZZ_pX operator/(const ZZ_pX& a, long b); ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pX& b); ZZ_pX& operator/=(ZZ_pX& x, const ZZ_p& b); ZZ_pX& operator/=(ZZ_pX& x, long b); ZZ_pX operator%(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pX& b); // procedural versions: void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); // q = a/b, r = a%b void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_p& b); void div(ZZ_pX& q, const ZZ_pX& a, long b); // q = a/b void rem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); // r = a%b long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZ_pX& a, const ZZ_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 /**************************************************************************\ GCD's These routines are intended for use when p is prime. \**************************************************************************/ void GCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); ZZ_pX GCD(const ZZ_pX& a, const ZZ_pX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b); // d = gcd(a,b), a s + b t = d // NOTE: A classical algorithm is used, switching over to a // "half-GCD" algorithm for large degree /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, and a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary integers which are reduced modulo p, and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, ZZ_pX& x); ostream& operator<<(ostream& s, const ZZ_pX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(ZZ_pX& x, const ZZ_pX& a); // x = derivative of a ZZ_pX diff(const ZZ_pX& a); void MakeMonic(ZZ_pX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case. void reverse(ZZ_pX& x, const ZZ_pX& a, long hi); ZZ_pX reverse(const ZZ_pX& a, long hi); void reverse(ZZ_pX& x, const ZZ_pX& a); ZZ_pX reverse(const ZZ_pX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_ZZ_p& x, const ZZ_pX& a, long n); vec_ZZ_p VectorCopy(const ZZ_pX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(ZZ_pX& x, long n); ZZ_pX random_ZZ_pX(long n); // generate a random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a); ZZ_pX BuildFromRoots(const vec_ZZ_p& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a); ZZ_p eval(const ZZ_pX& f, const ZZ_p& a); // b = f(a) void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a); vec_ZZ_p eval(const ZZ_pX& f, const vec_ZZ_p& a); // b.SetLength(a.length()). b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b); ZZ_pX interpolate(const vec_ZZ_p& a, const vec_ZZ_p& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. p should // be prime. /**************************************************************************\ Arithmetic mod X^n All routines require n >= 0, otherwise an error is raised. \**************************************************************************/ void trunc(ZZ_pX& x, const ZZ_pX& a, long n); // x = a % X^n ZZ_pX trunc(const ZZ_pX& a, long n); void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n); ZZ_pX MulTrunc(const ZZ_pX& a, const ZZ_pX& b, long n); // x = a * b % X^n void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n); ZZ_pX SqrTrunc(const ZZ_pX& a, long n); // x = a^2 % X^n void InvTrunc(ZZ_pX& x, const ZZ_pX& a, long n); ZZ_pX InvTrunc(const ZZ_pX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the ZZ_pXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f); ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f); // x = (a * b) % f void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pX& f); // x = a^2 % f void MulByXMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_pX MulByXMod(const ZZ_pX& a, const ZZ_pX& f); // x = (a * X) mod f void InvMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_pX InvMod(const ZZ_pX& a, const ZZ_pX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) // for modular exponentiation, see below /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build a ZZ_pXModulus F for f. This pre-computes information about f that speeds up subsequent computations. It is required that deg(f) > 0 and that LeadCoeff(f) is invertible. As an example, the following routine computes the product modulo f of a vector of polynomials. #include void product(ZZ_pX& x, const vec_ZZ_pX& v, const ZZ_pX& f) { ZZ_pXModulus F(f); ZZ_pX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } Note that automatic conversions are provided so that a ZZ_pX can be used wherever a ZZ_pXModulus is required, and a ZZ_pXModulus can be used wherever a ZZ_pX is required. \**************************************************************************/ class ZZ_pXModulus { public: ZZ_pXModulus(); // initially in an unusable state ZZ_pXModulus(const ZZ_pXModulus&); // copy ZZ_pXModulus& operator=(const ZZ_pXModulus&); // assignment ~ZZ_pXModulus(); ZZ_pXModulus(const ZZ_pX& f); // initialize with f, deg(f) > 0 operator const ZZ_pX& () const; // read-only access to f, implicit conversion operator const ZZ_pX& val() const; // read-only access to f, explicit notation }; void build(ZZ_pXModulus& F, const ZZ_pX& f); // pre-computes information about f and stores it in F. // Note that the declaration ZZ_pXModulus F(f) is equivalent to // ZZ_pXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const ZZ_pXModulus& F); // return n=deg(f) void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F); ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(ZZ_pX& x, const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F); ZZ_pX PowerMod(const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F); void PowerMod(ZZ_pX& x, const ZZ_pX& a, long e, const ZZ_pXModulus& F); ZZ_pX PowerMod(const ZZ_pX& a, long e, const ZZ_pXModulus& F); // x = a^e % f; deg(a) < n (e may be negative) void PowerXMod(ZZ_pX& x, const ZZ& e, const ZZ_pXModulus& F); ZZ_pX PowerXMod(const ZZ& e, const ZZ_pXModulus& F); void PowerXMod(ZZ_pX& x, long e, const ZZ_pXModulus& F); ZZ_pX PowerXMod(long e, const ZZ_pXModulus& F); // x = X^e % f (e may be negative) void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F); ZZ_pX PowerXPlusAMod(const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F); void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, long e, const ZZ_pXModulus& F); ZZ_pX PowerXPlusAMod(const ZZ_p& a, long e, const ZZ_pXModulus& F); // x = (X + a)^e % f (e may be negative) void rem(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); // x = a % f void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pXModulus& F); // q = a/f, r = a%f void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pXModulus& F); // q = a/f // operator notation: ZZ_pX operator/(const ZZ_pX& a, const ZZ_pXModulus& F); ZZ_pX operator%(const ZZ_pX& a, const ZZ_pXModulus& F); ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pXModulus& F); ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pXModulus& F); /**************************************************************************\ More Pre-Conditioning If you need to compute a * b % f for a fixed b, but for many a's, it is much more efficient to first build a ZZ_pXMultiplier B for b, and then use the MulMod routine below. Here is an example that multiplies each element of a vector by a fixed polynomial modulo f. #include void mul(vec_ZZ_pX& v, const ZZ_pX& b, const ZZ_pX& f) { ZZ_pXModulus F(f); ZZ_pXMultiplier B(b, F); long i; for (i = 0; i < v.length(); i++) MulMod(v[i], v[i], B, F); } \**************************************************************************/ class ZZ_pXMultiplier { public: ZZ_pXMultiplier(); // initially zero ZZ_pXMultiplier(const ZZ_pX& b, const ZZ_pXModulus& F); // initializes with b mod F, where deg(b) < deg(F) ZZ_pXMultiplier(const ZZ_pXMultiplier&); // copy ZZ_pXMultiplier& operator=(const ZZ_pXMultiplier&); // assignment ~ZZ_pXMultiplier(); const ZZ_pX& val() const; // read-only access to b }; void build(ZZ_pXMultiplier& B, const ZZ_pX& b, const ZZ_pXModulus& F); // pre-computes information about b and stores it in B; deg(b) < // deg(F) void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); // x = (a * b) % F; deg(a) < deg(F) /**************************************************************************\ vectors of ZZ_pX's \**************************************************************************/ typedef Vec vec_ZZ_pX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F); ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& h, const ZZ_pXModulus& F); // xi = gi(h) mod f (i=1,2); deg(h) < n. void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3, const ZZ_pX& h, const ZZ_pXModulus& F); // xi = gi(h) mod f (i=1..3); deg(h) < n. /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a ZZ_pXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct ZZ_pXArgument { vec_ZZ_pX H; }; void build(ZZ_pXArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n. void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& H, const ZZ_pXModulus& F); ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pXArgument& H, const ZZ_pXModulus& F); extern long ZZ_pXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // ZZ_pXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in ZZ_pXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(ZZ_p& x, const ZZ_pVector& a, const ZZ_pX& b); ZZ_p project(const ZZ_pVector& a, const ZZ_pX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F); vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F); vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F); // same as above, but uses a pre-computed ZZ_pXArgument void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); vec_ZZ_p UpdateMap(const vec_ZZ_p& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Restriction: must have a.length() <= deg(F). // This is "transposed" MulMod by B. // Input may have "high order" zeroes stripped. // Output will always have high order zeroes stripped. /**************************************************************************\ Minimum Polynomials These routines should be used with prime p. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m); ZZ_pX MinPolySeq(const vec_ZZ_p& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m); void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F); ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/p. void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m); void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F); ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m); void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F); ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Traces, norms, resultants These routines should be used with prime p. \**************************************************************************/ void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F); ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& F); void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_ZZ_p& S, const ZZ_pX& f); vec_ZZ_p TraceVec(const ZZ_pX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above trace routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_p NormMod(const ZZ_pX& a, const ZZ_pX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& b); ZZ_p resultant(const ZZ_pX& a, const ZZ_pX& b); // x = resultant(a, b) void CharPolyMod(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& f); ZZ_pX CharPolyMod(const ZZ_pX& a, const ZZ_pX& f); // g = charcteristic polynomial of (a mod f); 0 < deg(f), deg(g) < // deg(f); this routine works for arbitrary f; if f is irreducible, // it is faster to use the IrredPolyMod routine, and then exponentiate // if necessary (since in this case the CharPoly is just a power of // the IrredPoly). /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZ_pX& x) // x = 0 void set(ZZ_pX& x); // x = 1 void ZZ_pX::kill(); // f.kill() sets f to 0 and frees all memory held by f; Equivalent to // f.rep.kill(). ZZ_pX::ZZ_pX(INIT_SIZE_TYPE, long n); // ZZ_pX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const ZZ_pX& ZZ_pX::zero(); // ZZ_pX::zero() is a read-only reference to 0 void swap(ZZ_pX& x, ZZ_pX& y); // swap x and y (via "pointer swapping") ZZ_pX::ZZ_pX(long i, const ZZ_p& c); ZZ_pX::ZZ_pX(long i, long c); // initialize to c*X^i, provided for backward compatibility ntl-6.2.1/doc/ZZ_pXFactoring.cpp.html000644 000765 000024 00000032053 12377144460 017714 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/ZZ_pXFactoring.cpp.html

/**************************************************************************\

MODULE: ZZ_pXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over ZZ_p, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/ZZ_pX.h>
#include <NTL/pair_ZZ_pX_long.h>

void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& f);
vec_pair_ZZ_pX_long SquareFreeDecomp(const ZZ_pX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a lest of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_ZZ_p& x, const ZZ_pX& f);
vec_ZZ_p FindRoots(const ZZ_pX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(ZZ_p& root, const ZZ_pX& f);
ZZ_p FindRoot(const ZZ_pX& f);

// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0);
vec_ZZ_pX  SFBerlekamp(const ZZ_pX& f, long verbose=0);

// Assumes f is square-free and monic.  returns list of factors of f.
// Uses "Berlekamp" approach, as described in detail in [Shoup,
// J. Symbolic Comp. 20:363-397, 1995].


void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f,
               long verbose=0);

vec_pair_ZZ_pX_long berlekamp(const ZZ_pX& f, long verbose=0);

// returns a list of factors, with multiplicities.  f must be monic.
// Calls SFBerlekamp.



void NewDDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h,
         long verbose=0);

vec_pair_ZZ_pX_long NewDDF(const ZZ_pX& f, const ZZ_pX& h,
         long verbose=0);

// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^p mod f.  

// This routine implements the baby step/giant step algorithm 
// of [Kaltofen and Shoup, STOC 1995].
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

// NOTE: When factoring "large" polynomials,
// this routine uses external files to store some intermediate
// results, which are removed if the routine terminates normally.
// These files are stored in the current directory under names of the
// form ddf-*-baby-* and ddf-*-giant-*.  
// The definition of "large" is controlled by the variable

      extern double ZZ_pXFileThresh

// which can be set by the user.  If the sizes of the tables
// exceeds ZZ_pXFileThresh KB, external files are used.
// Initial value is NTL_FILE_THRESH (defined in tools.h).




void EDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& h,
         long d, long verbose=0);

vec_ZZ_pX EDF(const ZZ_pX& f, const ZZ_pX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  h = X^p mod f.  d =
// degree of irreducible factors of f.  This routine implements the
// algorithm of [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992].

void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0);
vec_ZZ_pX RootEDF(const ZZ_pX& f, long verbose=0);

// EDF for d==1

void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0);
vec_ZZ_pX SFCanZass(const ZZ_pX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f,
             long verbose=0);

vec_pair_ZZ_pX_long CanZass(const ZZ_pX& f, long verbose=0);

// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: these routines use modular composition.  The space
// used for the required tables can be controlled by the variable
// ZZ_pXArgBound (see ZZ_pX.txt).


void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v);
ZZ_pX mul(const vec_pair_ZZ_pX_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const ZZ_pX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// p^{-iter}.  This implements an algorithm from [Shoup, J. Symbolic
// Comp. 17:371-391, 1994].

long DetIrredTest(const ZZ_pX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const ZZ_pX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(ZZ_pX& f, long n);
ZZ_pX BuildIrred_ZZ_pX(long n);

// Build a monic irreducible poly of degree n.

void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g);
ZZ_pX BuildRandomIrred(const ZZ_pX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.

long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F);

// f is assumed to be an "equal degree" polynomial; h = X^p mod f.
// The common degree of the irreducible factors of f is computed This
// routine is useful in counting points on elliptic curves

long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F);

// Same as above, but uses a slightly faster probabilistic algorithm.
// The return value may be 0 or may be too big, but for large p
// (relative to n), this happens with very low probability.

void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F,
              const ZZ_pX& h);

ZZ_pX TraceMap(const ZZ_pX& a, long d, const ZZ_pXModulus& F,
              const ZZ_pX& h);

// w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, and h =
// X^q mod f, q a power of p.  This routine implements an algorithm
// from [von zur Gathen and Shoup, Computational Complexity 2:187-224,
// 1992].

void PowerCompose(ZZ_pX& w, const ZZ_pX& h, long d, const ZZ_pXModulus& F);

ZZ_pX PowerCompose(const ZZ_pX& h, long d, const ZZ_pXModulus& F);

// w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q mod f, q
// a power of p.  This routine implements an algorithm from [von zur
// Gathen and Shoup, Computational Complexity 2:187-224, 1992]

ntl-6.2.1/doc/ZZ_pXFactoring.txt000644 000765 000024 00000015311 12377144460 017004 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: ZZ_pXFactoring SUMMARY: Routines are provided for factorization of polynomials over ZZ_p, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& f); vec_pair_ZZ_pX_long SquareFreeDecomp(const ZZ_pX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a lest of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_ZZ_p& x, const ZZ_pX& f); vec_ZZ_p FindRoots(const ZZ_pX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(ZZ_p& root, const ZZ_pX& f); ZZ_p FindRoot(const ZZ_pX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); vec_ZZ_pX SFBerlekamp(const ZZ_pX& f, long verbose=0); // Assumes f is square-free and monic. returns list of factors of f. // Uses "Berlekamp" approach, as described in detail in [Shoup, // J. Symbolic Comp. 20:363-397, 1995]. void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose=0); vec_pair_ZZ_pX_long berlekamp(const ZZ_pX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SFBerlekamp. void NewDDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h, long verbose=0); vec_pair_ZZ_pX_long NewDDF(const ZZ_pX& f, const ZZ_pX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^p mod f. // This routine implements the baby step/giant step algorithm // of [Kaltofen and Shoup, STOC 1995]. // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. // NOTE: When factoring "large" polynomials, // this routine uses external files to store some intermediate // results, which are removed if the routine terminates normally. // These files are stored in the current directory under names of the // form ddf-*-baby-* and ddf-*-giant-*. // The definition of "large" is controlled by the variable extern double ZZ_pXFileThresh // which can be set by the user. If the sizes of the tables // exceeds ZZ_pXFileThresh KB, external files are used. // Initial value is NTL_FILE_THRESH (defined in tools.h). void EDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& h, long d, long verbose=0); vec_ZZ_pX EDF(const ZZ_pX& f, const ZZ_pX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. h = X^p mod f. d = // degree of irreducible factors of f. This routine implements the // algorithm of [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992]. void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); vec_ZZ_pX RootEDF(const ZZ_pX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); vec_ZZ_pX SFCanZass(const ZZ_pX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose=0); vec_pair_ZZ_pX_long CanZass(const ZZ_pX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: these routines use modular composition. The space // used for the required tables can be controlled by the variable // ZZ_pXArgBound (see ZZ_pX.txt). void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v); ZZ_pX mul(const vec_pair_ZZ_pX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const ZZ_pX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // p^{-iter}. This implements an algorithm from [Shoup, J. Symbolic // Comp. 17:371-391, 1994]. long DetIrredTest(const ZZ_pX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const ZZ_pX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(ZZ_pX& f, long n); ZZ_pX BuildIrred_ZZ_pX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g); ZZ_pX BuildRandomIrred(const ZZ_pX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F); // f is assumed to be an "equal degree" polynomial; h = X^p mod f. // The common degree of the irreducible factors of f is computed This // routine is useful in counting points on elliptic curves long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F); // Same as above, but uses a slightly faster probabilistic algorithm. // The return value may be 0 or may be too big, but for large p // (relative to n), this happens with very low probability. void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& h); ZZ_pX TraceMap(const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& h); // w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, and h = // X^q mod f, q a power of p. This routine implements an algorithm // from [von zur Gathen and Shoup, Computational Complexity 2:187-224, // 1992]. void PowerCompose(ZZ_pX& w, const ZZ_pX& h, long d, const ZZ_pXModulus& F); ZZ_pX PowerCompose(const ZZ_pX& h, long d, const ZZ_pXModulus& F); // w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q mod f, q // a power of p. This routine implements an algorithm from [von zur // Gathen and Shoup, Computational Complexity 2:187-224, 1992] ntl-6.2.1/doc/arrow1.gif000644 000765 000024 00000001707 12377144460 015302 0ustar00shoupstaff000000 000000 GIF89a22öp*5¶+7º+7¼,8¾,9Á-:Å.;É/<Ë/<Í2>Á0<Ç2>É0=Î0>Ò5AÅ8DÆ4AÊ5BÍ:FÉ:FÍ7DÓ9FÒJØ@@ÀBLÁBMÎHSÂJUÉPZÊS]ÉU_ÎBOÝEQÓJUÖFRÙFSÞS^ÚQ]ßXbÆ_hÉWaØ`iÊ`iÍcl×cmÙdnÞnvÒJWãMZåMZéQ^êR_íUaàS`í@`ÿUbñWdóZfòYfõr{àanüo{ÿ{‚Õw€á~†ãz‡ÿ|‰ÿ€€À‰ÖŽ•Ú•šÚ›¡ÞŠ‘á’™ç€€ÿ’Ÿÿœ¢áŸ¥á€ ÿ–£ÿ¢¨á¦¬ï«±íº¾é¡«ÿ¬²ð¥²ÿ¿Ãñ·ÄÿÊÍîÃÇðÅÉòËÎñÌÏôÀÀÿÎÑñÎÚÿÒÕöÛÝõÀàÿåæöèêùìîüïðúïñýòóûòóýööýÿÿÿ!ù ,22þ€o‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž…m_¢£¢iŸ„j\X--!¯° -0O_¦šm\0¿À¿±° (0¸–iO!ÁÏÀòÆ&&0X¹jOÐà±ÅÕÈMak\îßááÄÔ&7MMQ_Oïþñàæ•3q›DlŒàï@h«Ý°¥ "… 6ÜØÐC¼WäÌÙ;XhJÆ“7†À‚ž¼iÊ]xR苆“8Sø€å`˜wA3¦o œH5¾ó@EÍ .?k1(Í€¤HÝyx¢MÐ..`Ãrñd.“XqníÊh…Kˆâh¾Á˜V€®’ܾ…CÐÑ´Œ°}¤wo°¾oZ¤%Ðà•Á þEõÍ“ºŒ1 xÉ›ÃgrÃÔ]X fÎŽÁ1>Ê0=Î0>Ñ1>Ô6AÂ:EÀ9EÆ?JÁ4AÉ3@Î6BÎ:FÉJÍ3@Ñ5BÑ9FÒ>JÓ=JÕÉ0=Ï0>Ñ1>Ô7CÆ9EÀ:FÇ3@Ë3@Ì5BÍ>JÏ9FÖ=IÒ;HÕ=JÕ:GØ;HÙ=JÙ=JÜ?LÝBMÂ@KÅPZÇQ[ÊANßEQÓFRÕCPÝLXÜR]ÓR]ß@`À\eÆ_hÇW`ËWaÌ_hÉ]gØ`iË`iÍltËmuÏcl×dnÛdnÞirÙJVáVcî@`ÿ_lùeoàkwÿmzÿzÑ{‚Õ€€ÀˆÚ–Ý•›Ý–œà€€ÿ€ÿœ¢à€ ÿœ©ÿ¡¦á¥«î¯³ã«°ë²·ï©µÿ¹¾ñ½Áê¾Âñ¾ÊÿÊÍîËÎñÌÏõÀÀÿÁÎÿÏÒòÆÓÿÕØöÑÞÿÞàõâãöåæ÷éêùìíùïðúòóûñòþööýùùþÿÿÿ!ù ,22þ€i‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ–gW£P6¦6P£Wc iWF22´·¸96FXgš_°µÃµ¹· ¼_–_CÄÓ¶ÆÉ99GJ`’cD âÒÔÄÖÊ9;GGY¿ŽWãòäåŸ×éëJÍŒPóäÕ›v ŸuYA aÀ‡2â•»§ Û.(‰¨ükèð¡<(bŒÄ£7ìÞ5l ‘ùÀ±%@R†)°$Eeb qér€ŠX@c]!†ÈH’öp )Df#φ¨8*Nµ{aQyÚ2*¤gU'H)h'W¨R#EZlé !Ög¡’}tJ†liÙ 4$n€±êÚh0Ëê4·‚ŒøÜHpƒ3BÈŠ_½°hÞœSë`È0 %#.¨S£&{å3Žâ^ŒaJܼ˜Ó`ÜàõÙ€s‘á÷éz3,þrï¡1,™s\ \:ÇdÁ³þ’{Ãü…)í»ŒÎ‹ÈY^>.„"îÞoÿt€Œð‘¬ÈpÚþƒÑÎ@CtÒ}Ýp†Æà`t*8è V°ÒJ!`P˜Ý…vèᇠ†(âˆ$–h≂!þ((c)1998 DeMorgan Industries CorpUSSPCMT!ÿ PIANYGIF1.0Image;ntl-6.2.1/doc/config.txt000644 000765 000024 00000041002 12377144460 015376 0ustar00shoupstaff000000 000000 usage: ./configure [ variable=value ]... This configure script generates the file 'makefile' and the file '../include/NTL/config.h', based upon the values assigned to the variables on the command line. Note that all of these configuration options can also be set by editing these two (well documented) files by hand. This command is intended only to provide a slightly more convenient and (perhaps more importantly) non-interactive way to do this. This script does not perform any 'magic', like finding out what the local C compiler is called, etc. If the defaults are not correct for your platform, you have to set an appropriate variable. ########### Here are the most important variables, and their default values. CXX=g++ # The C++ compiler CXXFLAGS=-O2 # C++ complilation flags DEF_PREFIX=/usr/local # Default software directory PREFIX=$(DEF_PREFIX) # Directory in which to install NTL library components SHARED=off # Generate a shared library (as well as static) NTL_STD_CXX=on # ISO Mode switch NTL_GMP_LIP=off # Switch to enable the use of GMP as primary # long integer package GMP_PREFIX=$(DEF_PREFIX) # Directory in which GMP components are installed NTL_GF2X_LIB=off # Switch to enable the use of the gf2x package # for faster arithmetic over GF(2)[X] GF2X_PREFIX=$(DEF_PREFIX) # Directory in which gf2x components are installed ########## Here are more detailed description of these variables. ########## Basic compilation variables: CXX=g++ # A C++ compiler, e.g., g++, CC, xlC # Note that NTL appends a ".c" siffix to both C and C++ files, # so you must, for example, use g++ (rather than gcc) as your C++ # compiler. CXXFLAGS=-O2 # Flags for the C compiler # Some useful flags: # -O2 -- recommended level of optimization # -g -- debugging ########## Installation path: DEF_PREFIX=/usr/local # Default software directory PREFIX=$(DEF_PREFIX) # Set this to the directory in which you want NTL components to be # installed. When 'make install' is executed, the header # files are copied into $(PREFIX)/include/NTL, the library itself is # copied to $(PREFIX)/lib/libntl.a, and the documentation files # are copied into $(PREFIX)/share/doc/NTL. # Unless you have root permissions when running 'make install', # you will have to override the default PREFIX value with the # name of your own local directory. # If you want finer-grained control over where the different # library components are installed, set the variables # INCLUDEDIR, LIBDIR, and DOCDIR (see below). ########## Shared library switch: SHARED=off # Set this to 'on' if you want to generate a shared library, in addition to # a static library. Shared libraries have many advantages, but # unfortunately, their use is rather less portable than that of good, # old-fashioned static libraries. If you set SHARED=on, then the makefile # attempts to make use of the GNU libtool program, which is meant to work # around these portability issues. You may also want to set the # configuration variable LIBTOOL (see below), to point to another version of # libtool. For example, on Mac OSX, the built-in command libtool is not # actually the GNU libtool program; in this case, you will want to set # LIBTOOL=glibtool. On other systems, it may be necssary to downlaod and # install a fresh copy of the libtool program (which can be obtained from # http://www.gnu.org/software/libtool). Note that if SHARED=on, then # in addition to using the libtool program, the makefile relies on # features specific to GNU make. ########## ISO mode switch: NTL_STD_CXX=on # Set to 'off' if you do not want to use the "Standard C++" version of NTL. # In this version, all of NTL is "wrapped" inside the namespace NTL, # and are no longer directly accessible---you must either use # explicit qualification, or using directives, or using declarations. # However, note that all names that begin with "NTL_" are macros, # and as such do not belong to any namespace. # Additionally, instead of including the traditional headers # , , and , the standard headers # , , and are included. # These "wrap" some (but not all) names in namespace std. # If your compiler is not yet up to date, but you want some # of the benefits of Standard C++, you might try the "partial Standard C++" # switches NTL_PSTD_NNS, NTL_PSTD_NHF, NTL_PSTD_NTN (see below). ########## GMP variables: NTL_GMP_LIP=off # Set to 'on' if you want to use GMP, the GNU Multi-Precision package, # as the primary long integer package. # This will typically yield significantly faster long integer arithmetic # compared to the traditional long integer package. # If you set this flag, please note the following. # If you have installed GMP in a standard "system" location, this is # all you have to do. Otherwise, if GMP is built, but not installed # in a standard place, you have to set the variable GMP_PREFIX. GMP_PREFIX=$(DEF_PREFIX) # If GMP was installed in a standard system directory, e.g., /usr/local, # then do not set this variable. # Otherwise, if you want to use GMP and GMP was installed in # a directory , then set GMP_PREFIX=. # This works if the directory /include contains gmp.h # and /lib contains libgmp.a. # For finer-grained control, set the variables GMP_INCDIR and GMP_LIBDIR # instead (see below). ########## GF2X variables: NTL_GF2X_LIB=off # Set to 'on' if you want to use the gf2x library for faster # arithmetic over GF(2)[X] (the NTL class GF2X). # If you set this flag, please note the following. # If you have installed gf2x in a standard "system" location, this is # all you have to do. Otherwise, if gf2x is built, but not installed # in a standard place, you have to set the variable GF2X_PREFIX. GF2X_PREFIX=$(DEF_PREFIX) # If gf2x was installed in a standard system directory, e.g., /usr/local, # then do not set this variable. # Otherwise, if you want to use gf2x and gf2x was installed in # a directory , then set GF2X_PREFIX=. # This works if the directory /include contains gf2x.h # and /lib contains libgf2x.a. # For finer-grained control, set the variables GF2X_INCDIR and GF2X_LIBDIR # instead (see below). ########### Examples: # If you are happy with all the default values: ./configure # Actually, the initially installed makefile and config.h files # already reflect the default values. # If your C++ compiler is called CC: ./configure CXX=CC # If GMP is installed in a standard system directory, and you want to use it: ./configure NTL_GMP_LIP=on # If GMP was installed in a non-standard directory, say, $HOME/sw: ./configure NTL_GMP_LIP=on GMP_PREFIX=$HOME/sw # If you want to use the options -g and -O for compiling C++, # just execute ./configure "CXXFLAGS=-g -O" # Note the use of quotes to keep the argument in one piece. # If you want to use both GMP and the gf2x library: ./configure NTL_GMP_LIP=on NTL_GF2X_LIB=on # If you want to use GMP as well as traditional (non-ISO) mode: ./configure NTL_GMP_LIP=on NTL_STD_CXX=off ########### Here is a complete list of the remaining variables, ########### with their default values. These variables are pretty ########### esoteric, and you will probably never change their ########### default values. AR=ar ARFLAGS=ruv RANLIB=ranlib LDFLAGS= LDLIBS=-lm CPPFLAGS= LIBTOOL=libtool LIBDIR=$(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include DOCDIR=$(PREFIX)/share/doc NTL_PSTD_NNS=off NTL_PSTD_NHF=off NTL_PSTD_NTN=off NTL_LONG_LONG_TYPE=undefined NTL_UNSIGNED_LONG_LONG_TYPE=undefined NTL_CLEAN_INT=off NTL_CLEAN_PTR=off NTL_RANGE_CHECK=off NTL_X86_FIX=off NTL_NO_X86_FIX=off NTL_NO_INIT_TRANS=off WIZARD=on NTL_LONG_LONG=off NTL_AVOID_FLOAT=off NTL_SPMM_UL=off NTL_SPMM_ULL=off NTL_SPMM_ASM=off NTL_FFT_BIGTAB=off NTL_FFT_LAZYMUL=off NTL_TBL_REM=off NTL_AVOID_BRANCHING=off NTL_GF2X_NOINLINE=off NTL_GF2X_ALTCODE=off NTL_GF2X_ALTCODE1=off GMP_INCDIR=$(GMP_PREFIX)/include GMP_LIBDIR=$(GMP_PREFIX)/lib GF2X_INCDIR=$(GF2X_PREFIX)/include GF2X_LIBDIR=$(GF2X_PREFIX)/lib ########### Here is a more detailed description of these variables. ########### Further compilation variables: AR=ar # command to make a library ARFLAGS=ruv # arguments for AR RANLIB=ranlib # set to echo if you want to disable it completely LDFLAGS= # arguments for linker for C++ programs LDLIBS=-lm # libraries for linking C++ programs CPPFLAGS= # arguments for the C preprocessor LIBTOOL=libtool # the libtool command -- only needed if SHARED=on ########### Details of the compilation process (when SHARED=off) # When a C++ file foo.c is compiled: $(CXX) -I../include $(CPPFLAGS) $(CXXFLAGS) -c foo.c # When a C++ file foo.c is compiled and linked: $(CXX) -I../include $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) \ -o foo foo.c $(LDLIBS) # When the library ntl.a is built $(AR) $(ARFLAGS) ntl.a [ object files ]... $(RANLIB) ntl.a # If the ranlib command does not exist, everything will still function OK. ########### Further installation variables: LIBDIR=$(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include DOCDIR=$(PREFIX)/share/doc # Where to install NTL. # Execution of 'make install' copies header files into $(INCLUDEDIR)/NTL, # copies the library itself to $(LIBDIR)/libntl.a, and copies the # documentation files into $(DOCDIR)/NTL. ########## Partial ISO modes NTL_PSTD_NNS=off # NTL namespace -- wraps NTL in a namespace NTL_PSTD_NHF=off # new header files -- use , etc., instead of , etc. NTL_PSTD_NTN=off # nothrow new -- use the nothrow version of new. # Any combination of these PSTD swtiches may be set -- setting them all # is equvalent to setting NTL_STD_CXX. Make sure you also unset NTL_STD_CXX; # otherwise, they have no effect. ########### Basic Configuration Options: NTL_LONG_LONG_TYPE=undefined # Name of double-word signed integer type. # This is a non-standard type, and is called 'long long' by many # compilers. MS C++ calls it '__int64'. # # Note that the new C99 standard defines the type 'long long' # to be at least 64-bits wide. On 32-bit machines, this is just right. # Although not officially part of the C++ standard (which predates C99), # it is widely supported by C++ compilers, and is likely to be added # to the C++ standard. # # Unfortunately, 64-bit machines usually define 'long long' # to also be 64-bits wide, which is kind of useless. # However, GCC provides a type __int128_t which does the job. # # If left undefined, NTL will use somee "ifdef magic" to find # the type most suitable for your machine (based on compiler and # word size). NTL_UNSIGNED_LONG_LONG_TYPE=undefined # Name of double-word unsigned integer type. # # If left undefined, NTL will use somee "ifdef magic" to find # the type most suitable for your machine (based on compiler and # word size). NTL_CLEAN_INT=off # Setting this to 'on' disables the use of some non-standard # integer arithmetic which would yield slightly better performance. NTL_CLEAN_PTR=off # Setting this to 'on' disables the use of some non-standard # pointer arithmetic which would yield slightly better performance. NTL_RANGE_CHECK=off # Setting this to 'on' will generate vector subscript range-check code. # Useful for debugging, but it slows things down of course. NTL_X86_FIX=off # Set to 'on' to force the "x86 floating point fix", # overriding the default behavior. # By default, NTL will apply the "fix" if it looks like it is # necessary, and if it knows how to fix it. # The problem addressed here is that x86 processors sometimes # run in a mode where FP registers have more precision than doubles. # This will cause code in quad_float.c some trouble. # NTL can normally automatically detect the problem, and fix it, # so you shouldn't need to worry about this or the next flag. NTL_NO_X86_FIX=off # Set to 'on' to forces no "x86 floating point fix", # overriding the default behavior. NTL_NO_INIT_TRANS=off # When 'off', NTL uses a special code sequence to avoid # copying large objects in return statements. However, if your # compiler optimizes away the return of a *named* local object, # this is not necessary, and setting this flag to 'on' will result # in *slightly* more compact and efficient code. The C++ # standard explicitly allows compilers to perform this optimization, # and with time, more compilers actually do this. # Traditionally, however, most will only avoid copying *temporary* # objects in return statements, and NTL's default code sequence # exploits this fact. ########## Performance Options: WIZARD=on # Set to 'off' if you want to bypass the wizard; otherwise, set to 'on'. # The wizard is a script that runs when NTL is built that sets the following # flags to 'optimize' performance on the current platform. NTL_LONG_LONG=off # For platforms that support it, this flag can be set to cause # the long-integer multiplication code to use the type "long long", # which on some platforms yields a significant performance gain, # but on others, it can yield no improvement and can even # slow things down. # The variable NTL_LONG_LONG_TYPE can be defined to use a type name # other than "long long". # If you set NTL_LONG_LONG, you might also want to set # the flag NTL_TBL_REM. NTL_AVOID_FLOAT=off # On machines with slow floating point or---more comminly---slow int/float # conversions, this flag can lead to faster long-integer multiplication code. # If you set NTL_AVOID_FLOAT, you should probably also # set NTL_TBL_REM. # Note that at most one of NTL_LONG_LONG and NTL_AVOID_FLOAT may be set. NTL_SPMM_UL=off # On machines with slow floating point or---more comminly---slow int/float # conversions, this flag can lead to faster single-precision multiplication # with preconditioning (see MulModPrecon in the ZZ module). # This sounds esoteric, but it is actually important. NTL_SPMM_ULL=off # Similar to NTL_SPMM_UL, but relies on double-word unsigned multiplication. # This is (usually) done using the type 'unsigned long long', # but you can set the variable NTL_UNSIGNED_LONG_LONG_TYPE to # override the default. NTL_SPMM_ASM=off # Similar to NTL_SPMM_ULL, but relies on double-word unsigned multiplication # using assembly code. Only supported on select machines # and only under GCC. NTL_FFT_BIGTAB=off # Precomputed tables are used to store all the roots of unity # used in an FFT computation for the first NTL_FFT_BIGTAB_LIMIT # FFT primes (the latter is defined in FFT.h). This can # lead to significant time savings but at the const of some space: # in the worst case, the precomputed tables will take of space # log_2(NTL_FFT_BUGTAB_LIMIT) * M, where M is roughly the maxmimum # space occupied by any one polynomial that was involved in an # FFT computation (this could be a polynomial over zz_p, ZZ_p, or ZZ). NTL_FFT_LAZYMUL=off # This flag only has an effect when combined with the NTL_FFT_BIGTAB # flag, and either the NTL_SPMM_ULL or NTL_SPMM_ASM flags. # When set, a "lazy multiplication" strategy due to David Harvey: # see his paper "FASTER ARITHMETIC FOR NUMBER-THEORETIC TRANSFORMS". NTL_TBL_REM=off # With this flag, some divisions are avoided in the # ZZ_pX multiplication routines. If you use the NTL_AVOID_FLOAT # or NTL_LONG_LONG flags, then you should probably use this one too. NTL_AVOID_BRANCHING=off # With this option, branches are replaced at several # key points with equivalent code using shifts and masks. # Recommended for use with RISC architectures, especially # ones with deep pipelines and high branch penalities. # This flag is becoming less helpful as newer machines # have much smaller branch penalties, but still may be worth a try. NTL_GF2X_NOINLINE=off # By default, the low-level GF2X multiplication routine in inlined. # This can potentially lead to some trouble on some platforms, # and you can override the default by setting this flag. NTL_GF2X_ALTCODE=off # With this option, the default strategy for implmenting low-level # GF2X multiplication is replaced with an alternative strategy. # This alternative strategy seems to work better on RISC machines # with deep pipelines and high branch penalties (like a powerpc), # but does no better (or even worse) on x86s. NTL_GF2X_ALTCODE1=off # Yet another alternative implementation for GF2X multiplication. ########## More GMP Options: GMP_INCDIR=$(GMP_PREFIX)/include # directory containing gmp.h GMP_LIBDIR=$(GMP_PREFIX)/lib # directory containing libgmp.a ####### More gf2x options: GF2X_INCDIR=$(GF2X_PREFIX)/include # directory containing gf2x.h GF2X_LIBDIR=$(GF2X_PREFIX)/lib # directory containing libgf2x.a ntl-6.2.1/doc/conversions.txt000644 000765 000024 00000014353 12377144460 016512 0ustar00shoupstaff000000 000000 CONVERSIONS notation: typedef unsigned int uint; typedef unsigned long ulong; typedef const char * cstr; destination: source int: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p long: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p uint: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p ulong: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p ZZ: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR, cstr GF2, zz_p, ZZ_p float: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR double: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR xdouble: int, long, uint, ulong, ZZ, float, double, xdouble, RR, cstr quad_float: int, long, uint, ulong, ZZ, float, double, quad_float, RR, cstr RR: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR, cstr ZZ_p: long, ZZ, ZZ_p ZZ_pX: long, ZZ, ZZ_p; ZZX, ZZ_pX; ZZ_pE; vec_ZZ_p zz_p: long, ZZ, zz_p zz_pX: long, ZZ, zz_p; ZZX, zz_pX; zz_pE; vec_zz_p ZZX: long, ZZ; ZZX, GF2X, zz_pX, ZZ_pX; vec_ZZ GF2: long, ZZ, GF2 GF2X: long, ZZ, GF2; ZZX, GF2X; GF2E; vec_GF2 GF2E: long, ZZ, GF2, GF2E; GF2X GF2EX: long, ZZ, GF2, GF2E; ZZX, GF2X, GF2EX; vec_GF2E ZZ_pE: long, ZZ, ZZ_p, ZZ_pE; ZZ_pX ZZ_pEX: long, ZZ, ZZ_p, ZZ_pE; ZZX, ZZ_pX, ZZ_pEX; vec_ZZ_pE zz_pE: long, ZZ, zz_p, zz_pE; zz_pX zz_pEX: long, ZZ, zz_p, zz_pE; ZZX, zz_pX, zz_pEX; vec_zz_pE vec_ZZ: ZZX vec_ZZ_p: ZZ_pX vec_zz_p: zz_pX vec_GF2: GF2X vec_ZZ_pE: ZZ_pEX vec_zz_pE: zz_pEX vec_GF2E: GF2EX ********** NOTES *********** nomenclature: - integral types: int, long, uint, ulong, ZZ - bounded integral types: int, long, uint, ulong - floating point types: float, double, xdouble, quad_float, RR [1] All conversion operators come in procedural or functional form. To convert a of type S to x of type T, you can write conv(x, a); or x = conv(a); E.g., conv(a), conv(a), conv< Vec >, etc. The notation conv(a) was introduced in NTL v6. Prior to this, the notation to_T(a) was used. For backard compatibility, the various "to_T" functions have been retained; however, their use is dicouraged. Also note that new conversions have been added in v6 for which there is no corresponding "to_T" function: for these, one must use the new "conv" notation. Note that conv is implemented as a template function: template T conv(const S& a) { T x; conv(x, a); return x; } Thus, the call conv(a) always resolves to the procedure call conv(x, a). Modern C++ compilers do a pretty good job implementing the "named return value optimization", so this should not create too any unnecessary temporary objects. [2] In addition to the conversions listed, for generic vector types, a template conversion operator is provided: template void conv(Vec& x, const Vec& a) { long n = a.length(); x.SetLength(n); for (long i = 0; i < n; i++) conv(x[i], a[i]); } This provides component-wise conversion. This, if there is a conversion provided from S to T, then there is automatically a conversion provided from Vec to Vec. Note that because of the simple implementation, this input a is not allowed to alias the output x. Similarly, for generic matrix types Mat, a template conversion operator provides component-wise conversion. Again, the input may not alias the output. [3] All conversions from an integral type to a bounded integral type compute the result modulo 2^n, where n is the number of bits of the destination type: no overflow occurs. [4] All floating point to signed integral conversions compute the floor function *exactly*, unless the destination type is int or long and overflow occurs, in which case the result is undefined. An exception: converting an RR x to int or long will always yield floor(x) modulo 2^n, where n is the number of bits in the destination type. [5] Conversions from floating point to unsigned int and unsigned long are done via conversions to signed long: if the conversion to long overflows, the result is undefined; otherwise, the result is computed modulo 2^n, where n is the number of bits in the destination type. [6] The ZZ to double conversion routine is very precise: the result is the nearest double, breaking ties using the "round to even" rule. Overflow results in +/- Infinity. All this assumes the underlying floating point adheres to the IEEE standard. [7] All conversions to RR round to the current working precision: even converting an RR to an RR. [8] All conversions from long or ZZ to one of the "mod p" types ZZ_p, ZZ_pX, ZZ_pE, ZZ_pEX, zz_p, zz_pX, zz_pE, zz_pEX, GF2, GF2X, GF2E, GF2EX yield the the residue class modulo p (or 2). [9] All polynomial-to-polynomial conversions apply coefficient-wise conversion. Note that as a rule, if a conversion S to T is provided, then there is a corresponding conversion from the polynomial ring S[X] to the polynomial ring T[X]. [10] All polynomial/vector conversions simply copy from/to the coefficient vector of the polynomial. [11] The GF2X/ZZ_pX/zz_pX to GF2E/ZZ_pE/zz_pE conversions reduce the given polynomial modulo the current modulus; the reverse conversions yield the standard representative (smallest degree polynomial). [12] Conversions from GF2, zz_p or ZZ_p to any integral type yeld the standard representative (least non-negative) of the given residue class. [13] All conversions from the type cstr apply the same algorithm as is used for reading from an I/O stream, so ZZ x = conv("999999999999999999"); initializes the ZZ x to the integer 999999999999999999. ntl-6.2.1/doc/copying.txt000644 000765 000024 00000043404 12377144460 015611 0ustar00shoupstaff000000 000000 COPYRIGHT NOTICE NTL -- A Library for Doing Number Theory Copyright (C) 1996-2014 Victor Shoup The most recent version of NTL is available at http://www.shoup.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. This entire copyright notice should be placed in an appropriately conspicuous place accompanying all distributions of software that make use of NTL. The above terms apply to all of the software modules distributed with NTL, i.e., all source files in either the ntl-xxx.tar.gz or WinNTL-xxx.zip distributions. In general, the individual files do not contain copyright notices. Note that the quad_float package is derived from the doubledouble package, originally developed by Keith Briggs, and also licensed unger the GNU GPL. The files quad_float.c and quad_float.h contain more detailed copyright notices. Note that the traditional long integer package used by NTL, lip.c, is derived from---and represents an extensive modification of--- a package originally developed and copyrighted by Arjen Lenstra, who has agreed to renounce any copyright claims on the particular version of the long integer package appearing in NTL, so that the this package now is covered by the GNU GPL as well. Note that the alternative long integer package used by NTL is GMP, which is written by Torbjorn Granlund . GMP is licensed under the terms of the GNU Lesser General Public License. Note that NTL makes use of the RSA Data Security, Inc. MD5 Message Digest Algorithm. Note that prior to version 4.0, NTL was distributed under the following terms: NTL is freely available for research and educational purposes. I don't want to attach any legalistic licensing restrictions on users of NTL. However, NTL should not be linked in a commercial program (although using data in a commercial product produced by a program that used NTL is fine). The hope is that the GNU GPL is actually less restrictive than these older terms; however, in any circumstances such that GNU GPL is more restrictive, then the following rule is in force: versions prior to 4.0 may continue to be used under the old terms, but users of versions 4.0 or later should adhere to the terms of the GNU GPL. END COPYRIGHT NOTICE Following is the complete text of the GNU General Public License. Note that the copyright notice below applies to the text of the license itself, and not to NTL. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS ntl-6.2.1/doc/flags.txt000644 000765 000024 00000002543 12377144460 015234 0ustar00shoupstaff000000 000000 Use the compiler flag -DNTL_TRANSITION to help with the transition to NTL 3.0 from earlier versions. This has the effect of undeclaring certain functions whose semantics in 3.0 is different than in versions < 3.0. Thus, one can use the compiler to find the trouble spots. THE LIBRARY CAN NOT BE COMPILED WITH THIS FLAG! ONLY USE TO FIND TRANSITION PROBLEMS IN CLIENT CODE. Undeclares all shift operators for NTL arithmetic type; in versions < 3.0, << was a conversion operator; now it is a shift operator. Undeclares division functions in ZZX; in versions < 3.0, these were defined in terms of pseudo-division; now they are defined as ordinary division with an error being raised if the result is not integral. Explicit pseudo-division functions are now provided for the old semantics. Undeclares the UpdateMap function in for ZZ_pX and zz_pX; in versions < 3.0, the output always had length n; now high-order zeroes are stripped. Undeclares the conversion from GF2X to GF2EX functions; in versions < 3.0, this was defined as creating a constant polynomial by reduction modulo GF2E::modulus(); now, it is defined as a coefiicient-wise "lift". GF2X and GF2EX happened to be called BB and BB_pX in versions < 3.0. Declares assignment and copy for RR to be private. The semantics of these have changed from "copy and round to current precision" to "exact copy". ntl-6.2.1/doc/lzz_p.cpp.html000644 000765 000024 00000051272 12377144460 016207 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/lzz_p.cpp.html


/**************************************************************************\

MODULE: zz_p

SUMMARY:

The class zz_p is used to represent integers mod p, where 1 <= p <
NTL_SP_BOUND.  Note that NTL_SP_BOUND is usually 2^30 on 32-bit machines and
2^50 on 64-bit machines.

The modulus p may be any positive integer, not necessarily prime.

Objects of the class zz_p are represented as a long in the range 0..p-1.

An executing program maintains a "current modulus", which is set to p using
zz_p::init(p).  The current modulus *must* be initialized before any operations
on zz_p's are performed.  The modulus may be changed, and a mechanism is provided
for saving and restoring a modulus (see classes zz_pPush and zz_pContext below).

\**************************************************************************/

#include <NTL/ZZ.h>


class zz_p {
public:

   zz_p(); // initial value 0

   zz_p(const zz_p& a); // copy constructor
   explicit zz_p(long a); // promotion constructor

   zz_p& operator=(const zz_p& a); // assignment
   zz_p& operator=(long a); // assignment

   static void init(long p);
   // set the modulus to p, where p > 1.  This must be called before any
   // zz_p constructors are invoked.
   // The number p must have at most NTL_SP_NBITS bits.

   static long modulus();
   // zz_p::modulus() yields read-only reference to the current
   // modulus


   // typedefs to aid in generic programming
   typedef long rep_type;
   typedef zz_pContext context_type;
   typedef zz_pBak bak_type;
   typedef zz_pPush push_type;
   typedef zz_pX poly_type;

};


long rep(zz_p a); // read-only access to representation of a



/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(zz_p a, zz_p b);
long operator!=(zz_p a, zz_p b);

long IsZero(zz_p a);  // test for 0
long IsOne(zz_p a);  // test for 1

// PROMOTIONS: operators ==, != promote long to zz_p on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

zz_p operator+(zz_p a, zz_p b);
zz_p operator-(zz_p a, zz_p b);

zz_p operator-(zz_p a); // unary -

zz_p& operator+=(zz_p& x, zz_p a);
zz_p& operator+=(zz_p& x, long a);

zz_p& operator-=(zz_p& x, zz_p a);
zz_p& operator-=(zz_p& x, long a);

zz_p& operator++(zz_p& x);  // prefix
void operator++(zz_p& x, int);  // postfix

zz_p& operator--(zz_p& x);  // prefix
void operator--(zz_p& x, int);  // postfix

// procedural versions:


void add(zz_p& x, zz_p a, zz_p b); // x = a + b
void sub(zz_p& x, zz_p a, zz_p b); // x = a - b 
void negate(zz_p& x, zz_p a); // x = -a

// PROMOTIONS: binary +, -, and procedures add, sub promote
// from long to zz_p on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/

// operator notation:

zz_p operator*(zz_p a, zz_p b);

zz_p& operator*=(zz_p& x, zz_p a);
zz_p& operator*=(zz_p& x, long a);

// procedural versions:

void mul(zz_p& x, zz_p a, zz_p b); // x = a * b

void sqr(zz_p& x, zz_p a); // x = a^2
zz_p sqr(zz_p a);

// PROMOTIONS: operator * and procedure mul promote from long to zz_p
// on (a, b).


/**************************************************************************\

                                  Division

\**************************************************************************/

operator notation:

zz_p operator/(z_p a, zz_p b);

zz_p& operator/=(zz_p& x, zz_p a);
zz_p& operator/=(zz_p& x, long a);

procedural versions:

void div(zz_p& x, zz_p a, zz_p b);
// x = a/b

void inv(zz_p& x, zz_p a);
zz_p inv(zz_p a);
// x = 1/a

// PROMOTIONS: operator / and procedure div promote from long to zz_p
// on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/


void power(zz_p& x, zz_p a, long e); // x = a^e (e may be negative)
zz_p power(zz_p a, long e);


/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(zz_p& x);
zz_p random_zz_p();
// x = random element in zz_p.  Uses RandomBnd from ZZ.


/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, zz_p a);

istream& operator>>(istream& s, zz_p& x);
// a ZZ is read and reduced mod p

/**************************************************************************\

                       Modulus Switching 

A class zz_pPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to p, and automatically restore it:

   { 
      zz_pPush push(p); 

      ...

   }

The constructor for push will save the current modulus, and install p as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      zz_pPush push(); // just backup current modulus

        ...

      zz_p::init(p1); // install p1 

        ...

      zz_p::init(p2); // install p2

      // reinstall original modulus as close of scope
   }

      
The zz_pPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see zz_pContext below.  There is also an older zz_pBak class
that may also be useful.

..........................................................................

It is critical that zz_p objects created under one zz_p modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
zz_p modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any zz_p object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.

\**************************************************************************/


// A convenient interface for common cases:

class zz_pPush {
public:

zz_pPush();  // just backup current modulus

explicit zz_pPush(long p, long maxroot=NTL_FFTMaxRoot);
zz_pPush(INIT_FFT_TYPE, long index);
zz_pPush(INIT_USER_FFT_TYPE, long p);
explicit zz_pPush(const zz_pContext& context);
  // backup current modulus and install the given one
  // see documentation for zz_p::init for more details

private:
zz_pPush(const zz_pPush&); // disabled
void operator=(const zz_pPush&); // disabled

};



// more general context switching:
// A zz_pContext object has a modulus q (possibly "null")

class zz_pContext {


public:

zz_pContext();  // q = "null"

explicit zz_pContext(long p);
zz_pContext(INIT_FFT_TYPE, long index);
zz_pContext(INIT_USER_FFT_TYPE, long p);
  // q = the given modulus
  // see documentation for zz_p::init for more details


void save(); // q = CurrentModulus
void restore() const; // CurrentModulus = q

zz_pContext(const zz_pContext&);  // copy
zz_pContext& operator=(const zz_pContext&); // assignment
~zz_pContext(); // destructor


};


/ An older interface:
// To describe this logic, think of a zz_pBak object
// of having two components: a modulus q (possibly "null") and 
// an "auto-restore bit" b.

class zz_pBak {
public:


   zz_pBak();  // q = "null", b = 0

   ~zz_pBak();  // if (b) CurrentModulus = q

   void save();  // q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = q, b = 0


private:
   zz_pBak(const zz_pBak&);  // copy disabled
   void operator=(const zz_pBak&);  // assignment disabled
};








/**************************************************************************\

                               Miscellany

\**************************************************************************/


void clear(zz_p& x); // x = 0
void set(zz_p& x); // x = 1

static double zz_p::ModulusInverse();
// zz_p::ModulusInverse() returns 1.0/(double(zz_p::modulus())) 

static zz_p zz_p::zero();
// zz_p::zero() yields a read-only reference to zero

void swap(zz_p& x, zz_p& y);
// swap x and y 

static void zz_p::init(long p, long maxroot);
// Same as ordinary zz_p::init(p), but somewhat more efficient.  If you are
// going to perform arithmetic modulo a degree n polynomial, in which
// case set maxroot to NextPowerOfTwo(n)+1.  This is useful, for
// example, if you are going to factor a polynomial of degree n modulo
// p, and you know n in advance.
// If maxroot is set too low, the program will abort with an
// appropriate error message.

static void zz_p::FFTInit(long i);
// sets modulus to the i-th FFT prime (counting from 0).  FFT primes
// are NTL_SP_NBITS-bit primes p, where p-1 is divisible by a high power
// of two.  Thus, polynomial arithmetic mod p can be implemented
// particularly efficiently using the FFT.  As i increases, the power
// of 2 that divides p-1 gets smaller, thus placing a more severe
// restriction on the degrees of the polynomials to be multiplied.

static void zz_p::UserFFTInit(long p);
// set the modulus to a user-provided FFT prime p. To be useful,
// p-1 should be divisibly by a high power of 2. 
// The function "long CalcMaxRoot(long p)" is a utility routine
// that may be used to calculate this value. 
// If you are going to perform arithmetic modulo a degree n polynomial, 
// you will want CalcMaxRoot(p) >= NextPowerOfTwo(n)+1. 

zz_pContext::zz_pContext(long p, long maxroot);
// constructor for a zz_pContext with same semantics
// as zz_p::init(p, maxroot) above.

zz_pContext::zz_pContext(INIT_FFT_TYPE, long i);
// constructor for a zz_pContext with same semantics
// as zz_p::FFTInit(i) above; invoke as zz_pContext(INIT_FFT, i).

zz_pContext::zz_pContext(INIT_USER_FFT_TYPE, long p);
// constructor for a zz_pContext with same semantics
// as zz_p::UserFFTInit(p) above; invoke as zz_pContext(INIT_USER_FFT, p).

zz_p::zz_p(INIT_NO_ALLOC_TYPE);
// provided for consistency with other classes, initialize to zero

zz_p::zz_p(INIT_ALLOC_TYPE);
// provided for consistency with other classes, initialize to zero

zz_p::allocate();
// provided for consistency with other classes, no action





ntl-6.2.1/doc/lzz_p.txt000644 000765 000024 00000025363 12377144460 015303 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: zz_p SUMMARY: The class zz_p is used to represent integers mod p, where 1 <= p < NTL_SP_BOUND. Note that NTL_SP_BOUND is usually 2^30 on 32-bit machines and 2^50 on 64-bit machines. The modulus p may be any positive integer, not necessarily prime. Objects of the class zz_p are represented as a long in the range 0..p-1. An executing program maintains a "current modulus", which is set to p using zz_p::init(p). The current modulus *must* be initialized before any operations on zz_p's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes zz_pPush and zz_pContext below). \**************************************************************************/ #include class zz_p { public: zz_p(); // initial value 0 zz_p(const zz_p& a); // copy constructor explicit zz_p(long a); // promotion constructor zz_p& operator=(const zz_p& a); // assignment zz_p& operator=(long a); // assignment static void init(long p); // set the modulus to p, where p > 1. This must be called before any // zz_p constructors are invoked. // The number p must have at most NTL_SP_NBITS bits. static long modulus(); // zz_p::modulus() yields read-only reference to the current // modulus // typedefs to aid in generic programming typedef long rep_type; typedef zz_pContext context_type; typedef zz_pBak bak_type; typedef zz_pPush push_type; typedef zz_pX poly_type; }; long rep(zz_p a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(zz_p a, zz_p b); long operator!=(zz_p a, zz_p b); long IsZero(zz_p a); // test for 0 long IsOne(zz_p a); // test for 1 // PROMOTIONS: operators ==, != promote long to zz_p on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: zz_p operator+(zz_p a, zz_p b); zz_p operator-(zz_p a, zz_p b); zz_p operator-(zz_p a); // unary - zz_p& operator+=(zz_p& x, zz_p a); zz_p& operator+=(zz_p& x, long a); zz_p& operator-=(zz_p& x, zz_p a); zz_p& operator-=(zz_p& x, long a); zz_p& operator++(zz_p& x); // prefix void operator++(zz_p& x, int); // postfix zz_p& operator--(zz_p& x); // prefix void operator--(zz_p& x, int); // postfix // procedural versions: void add(zz_p& x, zz_p a, zz_p b); // x = a + b void sub(zz_p& x, zz_p a, zz_p b); // x = a - b void negate(zz_p& x, zz_p a); // x = -a // PROMOTIONS: binary +, -, and procedures add, sub promote // from long to zz_p on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: zz_p operator*(zz_p a, zz_p b); zz_p& operator*=(zz_p& x, zz_p a); zz_p& operator*=(zz_p& x, long a); // procedural versions: void mul(zz_p& x, zz_p a, zz_p b); // x = a * b void sqr(zz_p& x, zz_p a); // x = a^2 zz_p sqr(zz_p a); // PROMOTIONS: operator * and procedure mul promote from long to zz_p // on (a, b). /**************************************************************************\ Division \**************************************************************************/ operator notation: zz_p operator/(z_p a, zz_p b); zz_p& operator/=(zz_p& x, zz_p a); zz_p& operator/=(zz_p& x, long a); procedural versions: void div(zz_p& x, zz_p a, zz_p b); // x = a/b void inv(zz_p& x, zz_p a); zz_p inv(zz_p a); // x = 1/a // PROMOTIONS: operator / and procedure div promote from long to zz_p // on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(zz_p& x, zz_p a, long e); // x = a^e (e may be negative) zz_p power(zz_p a, long e); /**************************************************************************\ Random Elements \**************************************************************************/ void random(zz_p& x); zz_p random_zz_p(); // x = random element in zz_p. Uses RandomBnd from ZZ. /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, zz_p a); istream& operator>>(istream& s, zz_p& x); // a ZZ is read and reduced mod p /**************************************************************************\ Modulus Switching A class zz_pPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to p, and automatically restore it: { zz_pPush push(p); ... } The constructor for push will save the current modulus, and install p as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { zz_pPush push(); // just backup current modulus ... zz_p::init(p1); // install p1 ... zz_p::init(p2); // install p2 // reinstall original modulus as close of scope } The zz_pPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see zz_pContext below. There is also an older zz_pBak class that may also be useful. .......................................................................... It is critical that zz_p objects created under one zz_p modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) zz_p modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any zz_p object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. \**************************************************************************/ // A convenient interface for common cases: class zz_pPush { public: zz_pPush(); // just backup current modulus explicit zz_pPush(long p, long maxroot=NTL_FFTMaxRoot); zz_pPush(INIT_FFT_TYPE, long index); zz_pPush(INIT_USER_FFT_TYPE, long p); explicit zz_pPush(const zz_pContext& context); // backup current modulus and install the given one // see documentation for zz_p::init for more details private: zz_pPush(const zz_pPush&); // disabled void operator=(const zz_pPush&); // disabled }; // more general context switching: // A zz_pContext object has a modulus q (possibly "null") class zz_pContext { public: zz_pContext(); // q = "null" explicit zz_pContext(long p); zz_pContext(INIT_FFT_TYPE, long index); zz_pContext(INIT_USER_FFT_TYPE, long p); // q = the given modulus // see documentation for zz_p::init for more details void save(); // q = CurrentModulus void restore() const; // CurrentModulus = q zz_pContext(const zz_pContext&); // copy zz_pContext& operator=(const zz_pContext&); // assignment ~zz_pContext(); // destructor }; / An older interface: // To describe this logic, think of a zz_pBak object // of having two components: a modulus q (possibly "null") and // an "auto-restore bit" b. class zz_pBak { public: zz_pBak(); // q = "null", b = 0 ~zz_pBak(); // if (b) CurrentModulus = q void save(); // q = CurrentModulus, b = 1 void restore(); // CurrentModulus = q, b = 0 private: zz_pBak(const zz_pBak&); // copy disabled void operator=(const zz_pBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(zz_p& x); // x = 0 void set(zz_p& x); // x = 1 static double zz_p::ModulusInverse(); // zz_p::ModulusInverse() returns 1.0/(double(zz_p::modulus())) static zz_p zz_p::zero(); // zz_p::zero() yields a read-only reference to zero void swap(zz_p& x, zz_p& y); // swap x and y static void zz_p::init(long p, long maxroot); // Same as ordinary zz_p::init(p), but somewhat more efficient. If you are // going to perform arithmetic modulo a degree n polynomial, in which // case set maxroot to NextPowerOfTwo(n)+1. This is useful, for // example, if you are going to factor a polynomial of degree n modulo // p, and you know n in advance. // If maxroot is set too low, the program will abort with an // appropriate error message. static void zz_p::FFTInit(long i); // sets modulus to the i-th FFT prime (counting from 0). FFT primes // are NTL_SP_NBITS-bit primes p, where p-1 is divisible by a high power // of two. Thus, polynomial arithmetic mod p can be implemented // particularly efficiently using the FFT. As i increases, the power // of 2 that divides p-1 gets smaller, thus placing a more severe // restriction on the degrees of the polynomials to be multiplied. static void zz_p::UserFFTInit(long p); // set the modulus to a user-provided FFT prime p. To be useful, // p-1 should be divisibly by a high power of 2. // The function "long CalcMaxRoot(long p)" is a utility routine // that may be used to calculate this value. // If you are going to perform arithmetic modulo a degree n polynomial, // you will want CalcMaxRoot(p) >= NextPowerOfTwo(n)+1. zz_pContext::zz_pContext(long p, long maxroot); // constructor for a zz_pContext with same semantics // as zz_p::init(p, maxroot) above. zz_pContext::zz_pContext(INIT_FFT_TYPE, long i); // constructor for a zz_pContext with same semantics // as zz_p::FFTInit(i) above; invoke as zz_pContext(INIT_FFT, i). zz_pContext::zz_pContext(INIT_USER_FFT_TYPE, long p); // constructor for a zz_pContext with same semantics // as zz_p::UserFFTInit(p) above; invoke as zz_pContext(INIT_USER_FFT, p). zz_p::zz_p(INIT_NO_ALLOC_TYPE); // provided for consistency with other classes, initialize to zero zz_p::zz_p(INIT_ALLOC_TYPE); // provided for consistency with other classes, initialize to zero zz_p::allocate(); // provided for consistency with other classes, no action ntl-6.2.1/doc/lzz_pE.cpp.html000644 000765 000024 00000051556 12377144460 016321 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/lzz_pE.cpp.html


/**************************************************************************\

MODULE: zz_pE

SUMMARY:

The class zz_pE is used to represent polynomials in Z_p[X] modulo a
polynomial P.  The modulus P may be any polynomial with deg(P) > 0,
not necessarily irreducible.  The modulus p defining Z_p need
not be prime either.

Objects of the class zz_pE are represented as a zz_pX of degree < deg(P).

An executing program maintains a "current modulus", which is set to P
using zz_pE::init(P).  The current modulus for zz_pE (as well as for zz_p)
*must* be initialized before an operations on zz_pE's are performed.

The modulus may be changed, and a mechanism is provided for saving and
restoring a modulus (see classes zz_pEPush and zz_pEContext below).

\**************************************************************************/

#include <NTL/lzz_pX.h>

class zz_pE {
public:

   zz_pE(); // initial value 0

   zz_pE(const zz_pE& a); // copy constructor
   explicit zz_pE(const zz_p& a); // promotion 
   explicit zz_pE(long a); // promotion 

   zz_pE& operator=(const zz_pE& a); // assignment
   zz_pE& operator=(const zz_p& a); // assignment
   zz_pE& operator=(long a); // assignment

   ~zz_pE(); // destructor

   void init(const zz_pX& P);
   // zz_pE::init(P) initializes the current modulus to P;
   // required: deg(P) >= 1.

   static const zz_pXModulus& modulus();
   // zz_pE::modulus() yields read-only reference to the current modulus 

   static long degree();
   // zz_pE::degree() returns deg(P)

   // typedefs to aid generic programming
   typedef zz_pX rep_type;
   typedef zz_pEContext context_type;
   typedef zz_pEBak bak_type;
   typedef zz_pEPush push_type;
   typedef zz_pEX poly_type;

};


const zz_pX& rep(const zz_pE& a); // read-only access to representation of a



/**************************************************************************\

                                  Comparison

\**************************************************************************/

long operator==(const zz_pE& a, const zz_pE& b);
long operator!=(const zz_pE& a, const zz_pE& b);

long IsZero(const zz_pE& a);  // test for 0
long IsOne(const zz_pE& a);  // test for 1

// PROMOTIONS: ==, != promote {long, zz_p} to zz_pE on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

zz_pE operator+(const zz_pE& a, const zz_pE& b);

zz_pE operator-(const zz_pE& a, const zz_pE& b);
zz_pE operator-(const zz_pE& a);

zz_pE& operator+=(zz_pE& x, const zz_pE& a);
zz_pE& operator+=(zz_pE& x, const zz_p& a);
zz_pE& operator+=(zz_pE& x, long a);

zz_pE& operator++(zz_pE& x); // prefix
void operator++(zz_pE& x, int); // postfix

zz_pE& operator-=(zz_pE& x, const zz_pE& a);
zz_pE& operator-=(zz_pE& x, const zz_p& a);
zz_pE& operator-=(zz_pE& x, long a);

zz_pE& operator--(zz_pE& x); // prefix
void operator--(zz_pE& x, int); // postfix

// procedural versions:

void add(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a + b
void sub(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a - b 
void negate(zz_pE& x, const zz_pE& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long, zz_p} to zz_pE on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/


// operator notation:

zz_pE operator*(const zz_pE& a, const zz_pE& b);

zz_pE& operator*=(zz_pE& x, const zz_pE& a);
zz_pE& operator*=(zz_pE& x, const zz_p& a);
zz_pE& operator*=(zz_pE& x, long a);

// procedural versions:


void mul(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a * b

void sqr(zz_pE& x, const zz_pE& a); // x = a^2
zz_pE sqr(const zz_pE& a);

// PROMOTIONS: *, mul promote {long, zz_p} to zz_pE on (a, b).



/**************************************************************************\

                                     Division

\**************************************************************************/


// operator notation:

zz_pE operator/(const zz_pE& a, const zz_pE& b);

zz_pE& operator/=(zz_pE& x, const zz_pE& a);
zz_pE& operator/=(zz_pE& x, const zz_p& a);
zz_pE& operator/=(zz_pE& x, long a);


// procedural versions:

void div(zz_pE& x, const zz_pE& a, const zz_pE& b);
// x = a/b.  If b is not invertible, an error is raised.

void inv(zz_pE& x, const zz_pE& a);
zz_pE inv(const zz_pE& a);
// x = 1/a

PROMOTIONS: /, div promote {long, zz_p} to zz_pE on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/



void power(zz_pE& x, const zz_pE& a, const ZZ& e);
zz_pE power(const zz_pE& a, const ZZ& e);

void power(zz_pE& x, const zz_pE& a, long e);
zz_pE power(const zz_pE& a, long e);

// x = a^e (e may be negative)



/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(zz_pE& x);
zz_pE random_zz_pE();
// x = random element in zz_pE.

/**************************************************************************\

                               Norms and Traces

\**************************************************************************/



void trace(zz_p& x, const zz_pE& a);  // x = trace of a
zz_p trace(const zz_pE& a);

void norm(zz_p& x, const zz_pE& a);   // x = norm of a
zz_p norm(const zz_pE& a);



/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, const zz_pE& a);

istream& operator>>(istream& s, zz_pE& x);
// a zz_pX is read and reduced mod p


/**************************************************************************\

                       Modulus Switching 

A class zz_pEPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to P, and automatically restore it:

   { 
      zz_pEPush push(P); 

      ...

   }

The constructor for push will save the current modulus, and install P as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      zz_pEPush push(); // just backup current modulus

        ...

      zz_pE::init(P1); // install P1 

        ...

      zz_pE::init(P2); // install P2

      // reinstall original modulus as close of scope
   }

      
The zz_pEPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see zz_pEContext below.  There is also an older zz_pEBak class
that may also be useful.

..........................................................................

It is critical that zz_pE objects created under one zz_pE modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
zz_pE modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any zz_pE object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.


\**************************************************************************/


// A convenient interface for common cases

class zz_pEPush {

public:
zz_pEPush();  // backup current modulus
explicit zz_pEPush(const zz_pX& p);
explicit zz_pEPush(const zz_pEContext& context);
  // backup current modulus and install the given one

private:
zz_pEPush(const zz_pEPush&); // disabled
void operator=(const zz_pEPush&); // disabled

};



// more general context switching:
// A zz_pEContext object has a modulus Q (possibly "null"),

class zz_pEContext {


public:

zz_pEContext(); // Q = "null"
explicit zz_pEContext(const zz_pX& P); // Q = P

void save(); // Q = CurrentModulus
void restore() const; // CurrentModulus = Q

zz_pEContext(const zz_pEContext&);  // copy
zz_pEContext& operator=(const zz_pEContext&); // assignment
~zz_pEContext(); // destructor


};


// An older interface:
// To describe this logic, think of a zz_pEBak object
// of having two components: a modulus Q (possibly "null") and 
// an "auto-restore bit" b.


class zz_pEBak {
public:


   zz_pEBak();  // Q = "null", b = 0

   ~zz_pEBak();  // if (b) CurrentModulus = Q

   void save();  // Q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = Q, b = 0


private:
   zz_pEBak(const zz_pEBak&);  // copy disabled
   void operator=(const zz_pEBak&);  // assignment disabled
};






/**************************************************************************\

                               Miscellany

\**************************************************************************/

void clear(zz_pE& x); // x = 0
void set(zz_pE& x); // x = 1

static const zz_pE& zz_pE::zero();
// zz_pE::zero() yields a read-only reference to zero

void swap(zz_pE& x, zz_pE& y);
// swap x and y (done by "pointer swapping", if possible).

static ZZ& zz_pE::cardinality();
// yields the cardinality, i.e., p^{zz_pE::degree()}

zz_pE::zz_pE(INIT_NO_ALLOC_TYPE);
// special constructor: invoke as zz_pE x(INIT_NO_ALLOC);
// initializes x to 0, but allocates no space (this is now the default)

zz_pE::zz_pE(INIT_ALLOC_TYPE);
// special constructor: invoke as zz_pE x(INIT_ALLOC);
// initializes x to 0, but allocates space

zz_pE::allocate();
// useful in conjunction with the INIT_NO_ALLLOC constructor:
// x.allocate() will pre-allocate space for x, using the
// current modulus

ntl-6.2.1/doc/lzz_pE.txt000644 000765 000024 00000024012 12377144460 015376 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: zz_pE SUMMARY: The class zz_pE is used to represent polynomials in Z_p[X] modulo a polynomial P. The modulus P may be any polynomial with deg(P) > 0, not necessarily irreducible. The modulus p defining Z_p need not be prime either. Objects of the class zz_pE are represented as a zz_pX of degree < deg(P). An executing program maintains a "current modulus", which is set to P using zz_pE::init(P). The current modulus for zz_pE (as well as for zz_p) *must* be initialized before an operations on zz_pE's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes zz_pEPush and zz_pEContext below). \**************************************************************************/ #include class zz_pE { public: zz_pE(); // initial value 0 zz_pE(const zz_pE& a); // copy constructor explicit zz_pE(const zz_p& a); // promotion explicit zz_pE(long a); // promotion zz_pE& operator=(const zz_pE& a); // assignment zz_pE& operator=(const zz_p& a); // assignment zz_pE& operator=(long a); // assignment ~zz_pE(); // destructor void init(const zz_pX& P); // zz_pE::init(P) initializes the current modulus to P; // required: deg(P) >= 1. static const zz_pXModulus& modulus(); // zz_pE::modulus() yields read-only reference to the current modulus static long degree(); // zz_pE::degree() returns deg(P) // typedefs to aid generic programming typedef zz_pX rep_type; typedef zz_pEContext context_type; typedef zz_pEBak bak_type; typedef zz_pEPush push_type; typedef zz_pEX poly_type; }; const zz_pX& rep(const zz_pE& a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const zz_pE& a, const zz_pE& b); long operator!=(const zz_pE& a, const zz_pE& b); long IsZero(const zz_pE& a); // test for 0 long IsOne(const zz_pE& a); // test for 1 // PROMOTIONS: ==, != promote {long, zz_p} to zz_pE on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: zz_pE operator+(const zz_pE& a, const zz_pE& b); zz_pE operator-(const zz_pE& a, const zz_pE& b); zz_pE operator-(const zz_pE& a); zz_pE& operator+=(zz_pE& x, const zz_pE& a); zz_pE& operator+=(zz_pE& x, const zz_p& a); zz_pE& operator+=(zz_pE& x, long a); zz_pE& operator++(zz_pE& x); // prefix void operator++(zz_pE& x, int); // postfix zz_pE& operator-=(zz_pE& x, const zz_pE& a); zz_pE& operator-=(zz_pE& x, const zz_p& a); zz_pE& operator-=(zz_pE& x, long a); zz_pE& operator--(zz_pE& x); // prefix void operator--(zz_pE& x, int); // postfix // procedural versions: void add(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a + b void sub(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a - b void negate(zz_pE& x, const zz_pE& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long, zz_p} to zz_pE on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: zz_pE operator*(const zz_pE& a, const zz_pE& b); zz_pE& operator*=(zz_pE& x, const zz_pE& a); zz_pE& operator*=(zz_pE& x, const zz_p& a); zz_pE& operator*=(zz_pE& x, long a); // procedural versions: void mul(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a * b void sqr(zz_pE& x, const zz_pE& a); // x = a^2 zz_pE sqr(const zz_pE& a); // PROMOTIONS: *, mul promote {long, zz_p} to zz_pE on (a, b). /**************************************************************************\ Division \**************************************************************************/ // operator notation: zz_pE operator/(const zz_pE& a, const zz_pE& b); zz_pE& operator/=(zz_pE& x, const zz_pE& a); zz_pE& operator/=(zz_pE& x, const zz_p& a); zz_pE& operator/=(zz_pE& x, long a); // procedural versions: void div(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a/b. If b is not invertible, an error is raised. void inv(zz_pE& x, const zz_pE& a); zz_pE inv(const zz_pE& a); // x = 1/a PROMOTIONS: /, div promote {long, zz_p} to zz_pE on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(zz_pE& x, const zz_pE& a, const ZZ& e); zz_pE power(const zz_pE& a, const ZZ& e); void power(zz_pE& x, const zz_pE& a, long e); zz_pE power(const zz_pE& a, long e); // x = a^e (e may be negative) /**************************************************************************\ Random Elements \**************************************************************************/ void random(zz_pE& x); zz_pE random_zz_pE(); // x = random element in zz_pE. /**************************************************************************\ Norms and Traces \**************************************************************************/ void trace(zz_p& x, const zz_pE& a); // x = trace of a zz_p trace(const zz_pE& a); void norm(zz_p& x, const zz_pE& a); // x = norm of a zz_p norm(const zz_pE& a); /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, const zz_pE& a); istream& operator>>(istream& s, zz_pE& x); // a zz_pX is read and reduced mod p /**************************************************************************\ Modulus Switching A class zz_pEPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to P, and automatically restore it: { zz_pEPush push(P); ... } The constructor for push will save the current modulus, and install P as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { zz_pEPush push(); // just backup current modulus ... zz_pE::init(P1); // install P1 ... zz_pE::init(P2); // install P2 // reinstall original modulus as close of scope } The zz_pEPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see zz_pEContext below. There is also an older zz_pEBak class that may also be useful. .......................................................................... It is critical that zz_pE objects created under one zz_pE modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) zz_pE modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any zz_pE object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. \**************************************************************************/ // A convenient interface for common cases class zz_pEPush { public: zz_pEPush(); // backup current modulus explicit zz_pEPush(const zz_pX& p); explicit zz_pEPush(const zz_pEContext& context); // backup current modulus and install the given one private: zz_pEPush(const zz_pEPush&); // disabled void operator=(const zz_pEPush&); // disabled }; // more general context switching: // A zz_pEContext object has a modulus Q (possibly "null"), class zz_pEContext { public: zz_pEContext(); // Q = "null" explicit zz_pEContext(const zz_pX& P); // Q = P void save(); // Q = CurrentModulus void restore() const; // CurrentModulus = Q zz_pEContext(const zz_pEContext&); // copy zz_pEContext& operator=(const zz_pEContext&); // assignment ~zz_pEContext(); // destructor }; // An older interface: // To describe this logic, think of a zz_pEBak object // of having two components: a modulus Q (possibly "null") and // an "auto-restore bit" b. class zz_pEBak { public: zz_pEBak(); // Q = "null", b = 0 ~zz_pEBak(); // if (b) CurrentModulus = Q void save(); // Q = CurrentModulus, b = 1 void restore(); // CurrentModulus = Q, b = 0 private: zz_pEBak(const zz_pEBak&); // copy disabled void operator=(const zz_pEBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(zz_pE& x); // x = 0 void set(zz_pE& x); // x = 1 static const zz_pE& zz_pE::zero(); // zz_pE::zero() yields a read-only reference to zero void swap(zz_pE& x, zz_pE& y); // swap x and y (done by "pointer swapping", if possible). static ZZ& zz_pE::cardinality(); // yields the cardinality, i.e., p^{zz_pE::degree()} zz_pE::zz_pE(INIT_NO_ALLOC_TYPE); // special constructor: invoke as zz_pE x(INIT_NO_ALLOC); // initializes x to 0, but allocates no space (this is now the default) zz_pE::zz_pE(INIT_ALLOC_TYPE); // special constructor: invoke as zz_pE x(INIT_ALLOC); // initializes x to 0, but allocates space zz_pE::allocate(); // useful in conjunction with the INIT_NO_ALLLOC constructor: // x.allocate() will pre-allocate space for x, using the // current modulus ntl-6.2.1/doc/lzz_pEX.cpp.html000644 000765 000024 00000156542 12377144460 016452 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/lzz_pEX.cpp.html

/**************************************************************************\

MODULE: zz_pEX

SUMMARY:

The class zz_pEX represents polynomials over zz_pE,
and so can be used, for example, for arithmentic in GF(p^n)[X].
However, except where mathematically necessary (e.g., GCD computations),
zz_pE need not be a field.

\**************************************************************************/

#include <NTL/lzz_pE.h>
#include <NTL/vec_lzz_pE.h>

class zz_pEX {
public:

   zz_pEX(); // initial value 0

   zz_pEX(const zz_pEX& a); // copy
   zz_pEX(const zz_pE& a); // promotion
   zz_pEX(const zz_p& a);
   zz_pEX(long a);

   zz_pEX& operator=(const zz_pEX& a); // assignment
   zz_pEX& operator=(const zz_pE& a);
   zz_pEX& operator=(const zz_p& a);
   zz_pEX& operator=(long a);

   ~zz_pEX(); // destructor

   zz_pEX(INIT_MONO_TYPE, long i, const zz_pE& c);
   zz_pEX(INIT_MONO_TYPE, long i, const zz_p& c);
   zz_pEX(INIT_MONO_TYPE, long i, long c);
   // initilaize to c*X^i; invoke as zz_pEX(INIT_MONO, i, c)

   zz_pEX(INIT_MONO_TYPE, long i);
   // initilaize to X^i; invoke as zz_pEX(INIT_MONO, i)

   // typedefs to aid in generic programming
   typedef zz_pE coeff_type;
   typedef zz_pEXModulus modulus_type;

   // ...


};



/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const zz_pEX& a);  // return deg(a); deg(0) == -1.

const zz_pE& coeff(const zz_pEX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const zz_pE& LeadCoeff(const zz_pEX& a);
// returns leading term of a, or zero if a == 0

const zz_pE& ConstTerm(const zz_pEX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(zz_pEX& x, long i, const zz_pE& a);
void SetCoeff(zz_pEX& x, long i, const zz_p& a);
void SetCoeff(zz_pEX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(zz_pEX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(zz_pEX& x); // x is set to the monomial X

long IsX(const zz_pEX& a); // test if x = X




zz_pE& zz_pEX::operator[](long i);
const zz_pE& zz_pEX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void zz_pEX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void zz_pEX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void zz_pEX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const zz_pEX& a, const zz_pEX& b);
long operator!=(const zz_pEX& a, const zz_pEX& b);

long IsZero(const zz_pEX& a); // test for 0
long IsOne(const zz_pEX& a); // test for 1

// PROMOTIONS: ==, != promote {long,zz_p,zz_pE} to zz_pEX on (a, b).

/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

zz_pEX operator+(const zz_pEX& a, const zz_pEX& b);
zz_pEX operator-(const zz_pEX& a, const zz_pEX& b);
zz_pEX operator-(const zz_pEX& a);

zz_pEX& operator+=(zz_pEX& x, const zz_pEX& a);
zz_pEX& operator+=(zz_pEX& x, const zz_pE& a);
zz_pEX& operator+=(zz_pEX& x, const zz_p& a);
zz_pEX& operator+=(zz_pEX& x, long a);


zz_pEX& operator++(zz_pEX& x);  // prefix
void operator++(zz_pEX& x, int);  // postfix

zz_pEX& operator-=(zz_pEX& x, const zz_pEX& a);
zz_pEX& operator-=(zz_pEX& x, const zz_pE& a);
zz_pEX& operator-=(zz_pEX& x, const zz_p& a);
zz_pEX& operator-=(zz_pEX& x, long a);

zz_pEX& operator--(zz_pEX& x);  // prefix
void operator--(zz_pEX& x, int);  // postfix

// procedural versions:

void add(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a + b
void sub(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a - b 
void negate(zz_pEX& x, const zz_pEX& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long,zz_p,zz_pE} to zz_pEX on (a, b).



/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

zz_pEX operator*(const zz_pEX& a, const zz_pEX& b);

zz_pEX& operator*=(zz_pEX& x, const zz_pEX& a);
zz_pEX& operator*=(zz_pEX& x, const zz_pE& a);
zz_pEX& operator*=(zz_pEX& x, const zz_p& a);
zz_pEX& operator*=(zz_pEX& x, long a);


// procedural versions:


void mul(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a * b

void sqr(zz_pEX& x, const zz_pEX& a); // x = a^2
zz_pEX sqr(const zz_pEX& a);

// PROMOTIONS: *, mul promote {long,zz_p,zz_pE} to zz_pEX on (a, b).

void power(zz_pEX& x, const zz_pEX& a, long e);  // x = a^e (e >= 0)
zz_pEX power(const zz_pEX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

zz_pEX operator<<(const zz_pEX& a, long n);
zz_pEX operator>>(const zz_pEX& a, long n);

zz_pEX& operator<<=(zz_pEX& x, long n);
zz_pEX& operator>>=(zz_pEX& x, long n);

// procedural versions:

void LeftShift(zz_pEX& x, const zz_pEX& a, long n);
zz_pEX LeftShift(const zz_pEX& a, long n);

void RightShift(zz_pEX& x, const zz_pEX& a, long n);
zz_pEX RightShift(const zz_pEX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

zz_pEX operator/(const zz_pEX& a, const zz_pEX& b);
zz_pEX operator/(const zz_pEX& a, const zz_pE& b);
zz_pEX operator/(const zz_pEX& a, const zz_p& b);
zz_pEX operator/(const zz_pEX& a, long b);

zz_pEX operator%(const zz_pEX& a, const zz_pEX& b);

zz_pEX& operator/=(zz_pEX& x, const zz_pEX& a);
zz_pEX& operator/=(zz_pEX& x, const zz_pE& a);
zz_pEX& operator/=(zz_pEX& x, const zz_p& a);
zz_pEX& operator/=(zz_pEX& x, long a);

zz_pEX& operator%=(zz_pEX& x, const zz_pEX& a);

// procedural versions:


void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b);
// q = a/b, r = a%b

void div(zz_pEX& q, const zz_pEX& a, const zz_pEX& b);
void div(zz_pEX& q, const zz_pEX& a, const zz_pE& b);
void div(zz_pEX& q, const zz_pEX& a, const zz_p& b);
void div(zz_pEX& q, const zz_pEX& a, long b);
// q = a/b

void rem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b);
// r = a%b

long divide(zz_pEX& q, const zz_pEX& a, const zz_pEX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const zz_pEX& a, const zz_pEX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


/**************************************************************************\

                                   GCD's

These routines are intended for use when zz_pE is a field.

\**************************************************************************/


void GCD(zz_pEX& x, const zz_pEX& a, const zz_pEX& b);
zz_pEX GCD(const zz_pEX& a, const zz_pEX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(zz_pEX& d, zz_pEX& s, zz_pEX& t, const zz_pEX& a, const zz_pEX& b);
// d = gcd(a,b), a s + b t = d 


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be polynomials of degree < zz_pE::degree() and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary polynomials which are reduced modulo zz_pE::modulus(), 
and leading zeros stripped.

\**************************************************************************/

istream& operator>>(istream& s, zz_pEX& x);
ostream& operator<<(ostream& s, const zz_pEX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(zz_pEX& x, const zz_pEX& a); // x = derivative of a
zz_pEX diff(const zz_pEX& a);

void MakeMonic(zz_pEX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case

void reverse(zz_pEX& x, const zz_pEX& a, long hi);
zz_pEX reverse(const zz_pEX& a, long hi);

void reverse(zz_pEX& x, const zz_pEX& a);
zz_pEX reverse(const zz_pEX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_zz_pE& x, const zz_pEX& a, long n);
vec_zz_pE VectorCopy(const zz_pEX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(zz_pEX& x, long n);
zz_pEX random_zz_pEX(long n);
// x = random polynomial of degree < n 


/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(zz_pEX& x, const vec_zz_pE& a);
zz_pEX BuildFromRoots(const vec_zz_pE& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length()

void eval(zz_pE& b, const zz_pEX& f, const zz_pE& a);
zz_pE eval(const zz_pEX& f, const zz_pE& a);
// b = f(a)

void eval(zz_pE& b, const zz_pX& f, const zz_pE& a);
zz_pE eval(const zz_pEX& f, const zz_pE& a);
// b = f(a); uses ModComp algorithm for zz_pX

void eval(vec_zz_pE& b, const zz_pEX& f, const vec_zz_pE& a);
vec_zz_pE eval(const zz_pEX& f, const vec_zz_pE& a);
//  b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(zz_pEX& f, const vec_zz_pE& a, const vec_zz_pE& b);
zz_pEX interpolate(const vec_zz_pE& a, const vec_zz_pE& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  

/**************************************************************************\

                       Arithmetic mod X^n

Required: n >= 0; otherwise, an error is raised.

\**************************************************************************/

void trunc(zz_pEX& x, const zz_pEX& a, long n); // x = a % X^n
zz_pEX trunc(const zz_pEX& a, long n);

void MulTrunc(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, long n);
zz_pEX MulTrunc(const zz_pEX& a, const zz_pEX& b, long n);
// x = a * b % X^n

void SqrTrunc(zz_pEX& x, const zz_pEX& a, long n);
zz_pEX SqrTrunc(const zz_pEX& a, long n);
// x = a^2 % X^n

void InvTrunc(zz_pEX& x, const zz_pEX& a, long n);
zz_pEX InvTrunc(zz_pEX& x, const zz_pEX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.


NOTE: if you want to do many computations with a fixed f, use the
zz_pEXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEX& f);
zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEX& f);
// x = (a * b) % f

void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f);
zz_pEX SqrMod(const zz_pEX& a, const zz_pEX& f);
// x = a^2 % f

void MulByXMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f);
zz_pEX MulByXMod(const zz_pEX& a, const zz_pEX& f);
// x = (a * X) mod f

void InvMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f);
zz_pEX InvMod(const zz_pEX& a, const zz_pEX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(zz_pEX& x, const zz_pEX& a, const zz_pEX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
zz_pEXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

As an example, the following routine the product modulo f of a vector
of polynomials.

#include <NTL/lzz_pEX.h>

void product(zz_pEX& x, const vec_zz_pEX& v, const zz_pEX& f)
{
   zz_pEXModulus F(f);
   zz_pEX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}

NOTE: A zz_pEX may be used wherever a zz_pEXModulus is required,
and a zz_pEXModulus may be used wherever a zz_pEX is required.


\**************************************************************************/

class zz_pEXModulus {
public:
   zz_pEXModulus(); // initially in an unusable state

   zz_pEXModulus(const zz_pEX& f); // initialize with f, deg(f) > 0

   zz_pEXModulus(const zz_pEXModulus&); // copy

   zz_pEXModulus& operator=(const zz_pEXModulus&); // assignment

   ~zz_pEXModulus(); // destructor

   operator const zz_pEX& () const; // implicit read-only access to f

   const zz_pEX& val() const; // explicit read-only access to f
};

void build(zz_pEXModulus& F, const zz_pEX& f);
// pre-computes information about f and stores it in F.  Must have
// deg(f) > 0.  Note that the declaration zz_pEXModulus F(f) is
// equivalent to zz_pEXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).


long deg(const zz_pEXModulus& F);  // return n=deg(f)

void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b,
            const zz_pEXModulus& F);
zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F);
zz_pEX SqrMod(const zz_pEX& a, const zz_pEXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(zz_pEX& x, const zz_pEX& a, const ZZ& e, const zz_pEXModulus& F);
zz_pEX PowerMod(const zz_pEX& a, const ZZ& e, const zz_pEXModulus& F);

void PowerMod(zz_pEX& x, const zz_pEX& a, long e, const zz_pEXModulus& F);
zz_pEX PowerMod(const zz_pEX& a, long e, const zz_pEXModulus& F);

// x = a^e % f; e >= 0, deg(a) < n.  Uses a sliding window algorithm.
// (e may be negative)

void PowerXMod(zz_pEX& x, const ZZ& e, const zz_pEXModulus& F);
zz_pEX PowerXMod(const ZZ& e, const zz_pEXModulus& F);

void PowerXMod(zz_pEX& x, long e, const zz_pEXModulus& F);
zz_pEX PowerXMod(long e, const zz_pEXModulus& F);

// x = X^e % f (e may be negative)

void rem(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F);
// x = a % f

void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F);
// q = a/f, r = a%f

void div(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F);
// q = a/f

// operator notation:

zz_pEX operator/(const zz_pEX& a, const zz_pEXModulus& F);
zz_pEX operator%(const zz_pEX& a, const zz_pEXModulus& F);

zz_pEX& operator/=(zz_pEX& x, const zz_pEXModulus& F);
zz_pEX& operator%=(zz_pEX& x, const zz_pEXModulus& F);



/**************************************************************************\

                             vectors of zz_pEX's

\**************************************************************************/


typedef Vec<zz_pEX> vec_zz_pEX; // backward compatibility



/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.


\**************************************************************************/

void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEX& h,
             const zz_pEXModulus& F);
zz_pEX CompMod(const zz_pEX& g, const zz_pEX& h,
                    const zz_pEXModulus& F);

// x = g(h) mod f; deg(h) < n

void Comp2Mod(zz_pEX& x1, zz_pEX& x2, const zz_pEX& g1, const zz_pEX& g2,
              const zz_pEX& h, const zz_pEXModulus& F);
// xi = gi(h) mod f (i=1,2); deg(h) < n.


void Comp3Mod(zz_pEX& x1, zz_pEX& x2, zz_pEX& x3,
              const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& g3,
              const zz_pEX& h, const zz_pEXModulus& F);
// xi = gi(h) mod f (i=1..3); deg(h) < n.



/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a zz_pEXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct zz_pEXArgument {
   vec_zz_pEX H;
};

void build(zz_pEXArgument& H, const zz_pEX& h, const zz_pEXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n.

void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEXArgument& H,
             const zz_pEXModulus& F);

zz_pEX CompMod(const zz_pEX& g, const zz_pEXArgument& H,
                    const zz_pEXModulus& F);

extern long zz_pEXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// zz_pEXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in zz_pEXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(zz_pE& x, const zz_pEVector& a, const zz_pEX& b);
zz_pE project(const zz_pEVector& a, const zz_pEX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k,
                   const zz_pEX& h, const zz_pEXModulus& F);

vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k,
                   const zz_pEX& h, const zz_pEXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.

void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k,
                   const zz_pEXArgument& H, const zz_pEXModulus& F);

vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k,
                   const zz_pEXArgument& H, const zz_pEXModulus& F);

// same as above, but uses a pre-computed zz_pEXArgument


class zz_pEXTransMultiplier { /* ... */ };

void build(zz_pEXTransMultiplier& B, const zz_pEX& b, const zz_pEXModulus& F);

void UpdateMap(vec_zz_pE& x, const vec_zz_pE& a,
               const zz_pEXMultiplier& B, const zz_pEXModulus& F);

vec_zz_pE UpdateMap(const vec_zz_pE& a,
               const zz_pEXMultiplier& B, const zz_pEXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Required: a.length() <= deg(F), deg(b) < deg(F).
// This is "transposed" MulMod by B.
// Input may have "high order" zeroes stripped.
// Output always has high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

These routines should be used only when zz_pE is a field.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(zz_pEX& h, const vec_zz_pE& a, long m);
zz_pEX MinPolySeq(const vec_zz_pE& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m


void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);
zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m);

void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F);
zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/2^{zz_pE::degree()}.

void MinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);
zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m);

void MinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F);
zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);
zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m);

void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F);
zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).

/**************************************************************************\

           Composition and Minimal Polynomials in towers

These are implementations of algorithms that will be described
and analyzed in a forthcoming paper.

The routines require that p is prime, but zz_pE need not be a field.

\**************************************************************************/


void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEXArgument& h,
             const zz_pEXModulus& F);

zz_pEX CompTower(const zz_pX& g, const zz_pEXArgument& h,
             const zz_pEXModulus& F);

void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEX& h,
             const zz_pEXModulus& F);

zz_pEX CompTower(const zz_pX& g, const zz_pEX& h,
             const zz_pEXModulus& F);


// x = g(h) mod f


void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F,
                      long m);

zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m);

void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F);

zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F);

// Uses a probabilistic algorithm to compute the minimal
// polynomial of (g mod f) over zz_p.
// The parameter m is a bound on the degree of the minimal polynomial
// (default = deg(f)*zz_pE::degree()).
// In general, the result will be a divisor of the true minimimal
// polynomial.  For correct results, use the MinPoly routines below.



void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);

zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m);

void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F);

zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F);

// Same as above, but result is always correct.


void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);

zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m);

void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F);

zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F);

// Same as above, but assumes the minimal polynomial is
// irreducible, and uses a slightly faster, deterministic algorithm.


/**************************************************************************\

                   Traces, norms, resultants

\**************************************************************************/


void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEXModulus& F);
zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& F);

void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f);
zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_zz_pE& S, const zz_pEX& f);
vec_zz_pE TraceVec(const zz_pEX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above trace routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f);
zz_pE NormMod(const zz_pEX& a, const zz_pEX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)

void resultant(zz_pE& x, const zz_pEX& a, const zz_pEX& b);
zz_pE resultant(const zz_pEX& a, const zz_pEX& b);
// x = resultant(a, b)

// NormMod and resultant require that zz_pE is a field.




/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(zz_pEX& x) // x = 0
void set(zz_pEX& x); // x = 1

void zz_pEX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

zz_pEX::zz_pEX(INIT_SIZE_TYPE, long n);
// zz_pEX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const zz_pEX& zero();
// zz_pEX::zero() is a read-only reference to 0

void swap(zz_pEX& x, zz_pEX& y);
// swap x and y (via "pointer swapping")


zz_pEX::zz_pEX(long i, const zz_pE& c);
zz_pEX::zz_pEX(long i, const zz_p& c);
zz_pEX::zz_pEX(long i, long c);
// initilaize to c*X^i; provided for backward compatibility
ntl-6.2.1/doc/lzz_pEX.txt000644 000765 000024 00000066772 12377144460 015551 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: zz_pEX SUMMARY: The class zz_pEX represents polynomials over zz_pE, and so can be used, for example, for arithmentic in GF(p^n)[X]. However, except where mathematically necessary (e.g., GCD computations), zz_pE need not be a field. \**************************************************************************/ #include #include class zz_pEX { public: zz_pEX(); // initial value 0 zz_pEX(const zz_pEX& a); // copy zz_pEX(const zz_pE& a); // promotion zz_pEX(const zz_p& a); zz_pEX(long a); zz_pEX& operator=(const zz_pEX& a); // assignment zz_pEX& operator=(const zz_pE& a); zz_pEX& operator=(const zz_p& a); zz_pEX& operator=(long a); ~zz_pEX(); // destructor zz_pEX(INIT_MONO_TYPE, long i, const zz_pE& c); zz_pEX(INIT_MONO_TYPE, long i, const zz_p& c); zz_pEX(INIT_MONO_TYPE, long i, long c); // initilaize to c*X^i; invoke as zz_pEX(INIT_MONO, i, c) zz_pEX(INIT_MONO_TYPE, long i); // initilaize to X^i; invoke as zz_pEX(INIT_MONO, i) // typedefs to aid in generic programming typedef zz_pE coeff_type; typedef zz_pEXModulus modulus_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const zz_pEX& a); // return deg(a); deg(0) == -1. const zz_pE& coeff(const zz_pEX& a, long i); // returns the coefficient of X^i, or zero if i not in range const zz_pE& LeadCoeff(const zz_pEX& a); // returns leading term of a, or zero if a == 0 const zz_pE& ConstTerm(const zz_pEX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(zz_pEX& x, long i, const zz_pE& a); void SetCoeff(zz_pEX& x, long i, const zz_p& a); void SetCoeff(zz_pEX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(zz_pEX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(zz_pEX& x); // x is set to the monomial X long IsX(const zz_pEX& a); // test if x = X zz_pE& zz_pEX::operator[](long i); const zz_pE& zz_pEX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void zz_pEX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void zz_pEX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void zz_pEX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const zz_pEX& a, const zz_pEX& b); long operator!=(const zz_pEX& a, const zz_pEX& b); long IsZero(const zz_pEX& a); // test for 0 long IsOne(const zz_pEX& a); // test for 1 // PROMOTIONS: ==, != promote {long,zz_p,zz_pE} to zz_pEX on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: zz_pEX operator+(const zz_pEX& a, const zz_pEX& b); zz_pEX operator-(const zz_pEX& a, const zz_pEX& b); zz_pEX operator-(const zz_pEX& a); zz_pEX& operator+=(zz_pEX& x, const zz_pEX& a); zz_pEX& operator+=(zz_pEX& x, const zz_pE& a); zz_pEX& operator+=(zz_pEX& x, const zz_p& a); zz_pEX& operator+=(zz_pEX& x, long a); zz_pEX& operator++(zz_pEX& x); // prefix void operator++(zz_pEX& x, int); // postfix zz_pEX& operator-=(zz_pEX& x, const zz_pEX& a); zz_pEX& operator-=(zz_pEX& x, const zz_pE& a); zz_pEX& operator-=(zz_pEX& x, const zz_p& a); zz_pEX& operator-=(zz_pEX& x, long a); zz_pEX& operator--(zz_pEX& x); // prefix void operator--(zz_pEX& x, int); // postfix // procedural versions: void add(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a + b void sub(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a - b void negate(zz_pEX& x, const zz_pEX& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long,zz_p,zz_pE} to zz_pEX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: zz_pEX operator*(const zz_pEX& a, const zz_pEX& b); zz_pEX& operator*=(zz_pEX& x, const zz_pEX& a); zz_pEX& operator*=(zz_pEX& x, const zz_pE& a); zz_pEX& operator*=(zz_pEX& x, const zz_p& a); zz_pEX& operator*=(zz_pEX& x, long a); // procedural versions: void mul(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a * b void sqr(zz_pEX& x, const zz_pEX& a); // x = a^2 zz_pEX sqr(const zz_pEX& a); // PROMOTIONS: *, mul promote {long,zz_p,zz_pE} to zz_pEX on (a, b). void power(zz_pEX& x, const zz_pEX& a, long e); // x = a^e (e >= 0) zz_pEX power(const zz_pEX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: zz_pEX operator<<(const zz_pEX& a, long n); zz_pEX operator>>(const zz_pEX& a, long n); zz_pEX& operator<<=(zz_pEX& x, long n); zz_pEX& operator>>=(zz_pEX& x, long n); // procedural versions: void LeftShift(zz_pEX& x, const zz_pEX& a, long n); zz_pEX LeftShift(const zz_pEX& a, long n); void RightShift(zz_pEX& x, const zz_pEX& a, long n); zz_pEX RightShift(const zz_pEX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: zz_pEX operator/(const zz_pEX& a, const zz_pEX& b); zz_pEX operator/(const zz_pEX& a, const zz_pE& b); zz_pEX operator/(const zz_pEX& a, const zz_p& b); zz_pEX operator/(const zz_pEX& a, long b); zz_pEX operator%(const zz_pEX& a, const zz_pEX& b); zz_pEX& operator/=(zz_pEX& x, const zz_pEX& a); zz_pEX& operator/=(zz_pEX& x, const zz_pE& a); zz_pEX& operator/=(zz_pEX& x, const zz_p& a); zz_pEX& operator/=(zz_pEX& x, long a); zz_pEX& operator%=(zz_pEX& x, const zz_pEX& a); // procedural versions: void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b); // q = a/b, r = a%b void div(zz_pEX& q, const zz_pEX& a, const zz_pEX& b); void div(zz_pEX& q, const zz_pEX& a, const zz_pE& b); void div(zz_pEX& q, const zz_pEX& a, const zz_p& b); void div(zz_pEX& q, const zz_pEX& a, long b); // q = a/b void rem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b); // r = a%b long divide(zz_pEX& q, const zz_pEX& a, const zz_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const zz_pEX& a, const zz_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 /**************************************************************************\ GCD's These routines are intended for use when zz_pE is a field. \**************************************************************************/ void GCD(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); zz_pEX GCD(const zz_pEX& a, const zz_pEX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(zz_pEX& d, zz_pEX& s, zz_pEX& t, const zz_pEX& a, const zz_pEX& b); // d = gcd(a,b), a s + b t = d /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be polynomials of degree < zz_pE::degree() and a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary polynomials which are reduced modulo zz_pE::modulus(), and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, zz_pEX& x); ostream& operator<<(ostream& s, const zz_pEX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(zz_pEX& x, const zz_pEX& a); // x = derivative of a zz_pEX diff(const zz_pEX& a); void MakeMonic(zz_pEX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case void reverse(zz_pEX& x, const zz_pEX& a, long hi); zz_pEX reverse(const zz_pEX& a, long hi); void reverse(zz_pEX& x, const zz_pEX& a); zz_pEX reverse(const zz_pEX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_zz_pE& x, const zz_pEX& a, long n); vec_zz_pE VectorCopy(const zz_pEX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(zz_pEX& x, long n); zz_pEX random_zz_pEX(long n); // x = random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(zz_pEX& x, const vec_zz_pE& a); zz_pEX BuildFromRoots(const vec_zz_pE& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(zz_pE& b, const zz_pEX& f, const zz_pE& a); zz_pE eval(const zz_pEX& f, const zz_pE& a); // b = f(a) void eval(zz_pE& b, const zz_pX& f, const zz_pE& a); zz_pE eval(const zz_pEX& f, const zz_pE& a); // b = f(a); uses ModComp algorithm for zz_pX void eval(vec_zz_pE& b, const zz_pEX& f, const vec_zz_pE& a); vec_zz_pE eval(const zz_pEX& f, const vec_zz_pE& a); // b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(zz_pEX& f, const vec_zz_pE& a, const vec_zz_pE& b); zz_pEX interpolate(const vec_zz_pE& a, const vec_zz_pE& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. /**************************************************************************\ Arithmetic mod X^n Required: n >= 0; otherwise, an error is raised. \**************************************************************************/ void trunc(zz_pEX& x, const zz_pEX& a, long n); // x = a % X^n zz_pEX trunc(const zz_pEX& a, long n); void MulTrunc(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, long n); zz_pEX MulTrunc(const zz_pEX& a, const zz_pEX& b, long n); // x = a * b % X^n void SqrTrunc(zz_pEX& x, const zz_pEX& a, long n); zz_pEX SqrTrunc(const zz_pEX& a, long n); // x = a^2 % X^n void InvTrunc(zz_pEX& x, const zz_pEX& a, long n); zz_pEX InvTrunc(zz_pEX& x, const zz_pEX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the zz_pEXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEX& f); zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEX& f); // x = (a * b) % f void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); zz_pEX SqrMod(const zz_pEX& a, const zz_pEX& f); // x = a^2 % f void MulByXMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); zz_pEX MulByXMod(const zz_pEX& a, const zz_pEX& f); // x = (a * X) mod f void InvMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); zz_pEX InvMod(const zz_pEX& a, const zz_pEX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build zz_pEXModulus F for f. This pre-computes information about f that speeds up subsequent computations. As an example, the following routine the product modulo f of a vector of polynomials. #include void product(zz_pEX& x, const vec_zz_pEX& v, const zz_pEX& f) { zz_pEXModulus F(f); zz_pEX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } NOTE: A zz_pEX may be used wherever a zz_pEXModulus is required, and a zz_pEXModulus may be used wherever a zz_pEX is required. \**************************************************************************/ class zz_pEXModulus { public: zz_pEXModulus(); // initially in an unusable state zz_pEXModulus(const zz_pEX& f); // initialize with f, deg(f) > 0 zz_pEXModulus(const zz_pEXModulus&); // copy zz_pEXModulus& operator=(const zz_pEXModulus&); // assignment ~zz_pEXModulus(); // destructor operator const zz_pEX& () const; // implicit read-only access to f const zz_pEX& val() const; // explicit read-only access to f }; void build(zz_pEXModulus& F, const zz_pEX& f); // pre-computes information about f and stores it in F. Must have // deg(f) > 0. Note that the declaration zz_pEXModulus F(f) is // equivalent to zz_pEXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const zz_pEXModulus& F); // return n=deg(f) void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F); zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F); zz_pEX SqrMod(const zz_pEX& a, const zz_pEXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(zz_pEX& x, const zz_pEX& a, const ZZ& e, const zz_pEXModulus& F); zz_pEX PowerMod(const zz_pEX& a, const ZZ& e, const zz_pEXModulus& F); void PowerMod(zz_pEX& x, const zz_pEX& a, long e, const zz_pEXModulus& F); zz_pEX PowerMod(const zz_pEX& a, long e, const zz_pEXModulus& F); // x = a^e % f; e >= 0, deg(a) < n. Uses a sliding window algorithm. // (e may be negative) void PowerXMod(zz_pEX& x, const ZZ& e, const zz_pEXModulus& F); zz_pEX PowerXMod(const ZZ& e, const zz_pEXModulus& F); void PowerXMod(zz_pEX& x, long e, const zz_pEXModulus& F); zz_pEX PowerXMod(long e, const zz_pEXModulus& F); // x = X^e % f (e may be negative) void rem(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F); // x = a % f void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F); // q = a/f, r = a%f void div(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F); // q = a/f // operator notation: zz_pEX operator/(const zz_pEX& a, const zz_pEXModulus& F); zz_pEX operator%(const zz_pEX& a, const zz_pEXModulus& F); zz_pEX& operator/=(zz_pEX& x, const zz_pEXModulus& F); zz_pEX& operator%=(zz_pEX& x, const zz_pEXModulus& F); /**************************************************************************\ vectors of zz_pEX's \**************************************************************************/ typedef Vec vec_zz_pEX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F); zz_pEX CompMod(const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(zz_pEX& x1, zz_pEX& x2, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& h, const zz_pEXModulus& F); // xi = gi(h) mod f (i=1,2); deg(h) < n. void Comp3Mod(zz_pEX& x1, zz_pEX& x2, zz_pEX& x3, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& g3, const zz_pEX& h, const zz_pEXModulus& F); // xi = gi(h) mod f (i=1..3); deg(h) < n. /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a zz_pEXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct zz_pEXArgument { vec_zz_pEX H; }; void build(zz_pEXArgument& H, const zz_pEX& h, const zz_pEXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n. void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEXArgument& H, const zz_pEXModulus& F); zz_pEX CompMod(const zz_pEX& g, const zz_pEXArgument& H, const zz_pEXModulus& F); extern long zz_pEXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // zz_pEXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in zz_pEXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(zz_pE& x, const zz_pEVector& a, const zz_pEX& b); zz_pE project(const zz_pEVector& a, const zz_pEX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F); vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F); vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F); // same as above, but uses a pre-computed zz_pEXArgument class zz_pEXTransMultiplier { /* ... */ }; void build(zz_pEXTransMultiplier& B, const zz_pEX& b, const zz_pEXModulus& F); void UpdateMap(vec_zz_pE& x, const vec_zz_pE& a, const zz_pEXMultiplier& B, const zz_pEXModulus& F); vec_zz_pE UpdateMap(const vec_zz_pE& a, const zz_pEXMultiplier& B, const zz_pEXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Required: a.length() <= deg(F), deg(b) < deg(F). // This is "transposed" MulMod by B. // Input may have "high order" zeroes stripped. // Output always has high order zeroes stripped. /**************************************************************************\ Minimum Polynomials These routines should be used only when zz_pE is a field. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(zz_pEX& h, const vec_zz_pE& a, long m); zz_pEX MinPolySeq(const vec_zz_pE& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m); void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/2^{zz_pE::degree()}. void MinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m); void MinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m); void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Composition and Minimal Polynomials in towers These are implementations of algorithms that will be described and analyzed in a forthcoming paper. The routines require that p is prime, but zz_pE need not be a field. \**************************************************************************/ void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEXArgument& h, const zz_pEXModulus& F); zz_pEX CompTower(const zz_pX& g, const zz_pEXArgument& h, const zz_pEXModulus& F); void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F); zz_pEX CompTower(const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F); // x = g(h) mod f void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m); void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F); // Uses a probabilistic algorithm to compute the minimal // polynomial of (g mod f) over zz_p. // The parameter m is a bound on the degree of the minimal polynomial // (default = deg(f)*zz_pE::degree()). // In general, the result will be a divisor of the true minimimal // polynomial. For correct results, use the MinPoly routines below. void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m); void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F); // Same as above, but result is always correct. void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m); void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F); // Same as above, but assumes the minimal polynomial is // irreducible, and uses a slightly faster, deterministic algorithm. /**************************************************************************\ Traces, norms, resultants \**************************************************************************/ void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEXModulus& F); zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& F); void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f); zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_zz_pE& S, const zz_pEX& f); vec_zz_pE TraceVec(const zz_pEX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above trace routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f); zz_pE NormMod(const zz_pEX& a, const zz_pEX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(zz_pE& x, const zz_pEX& a, const zz_pEX& b); zz_pE resultant(const zz_pEX& a, const zz_pEX& b); // x = resultant(a, b) // NormMod and resultant require that zz_pE is a field. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(zz_pEX& x) // x = 0 void set(zz_pEX& x); // x = 1 void zz_pEX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). zz_pEX::zz_pEX(INIT_SIZE_TYPE, long n); // zz_pEX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const zz_pEX& zero(); // zz_pEX::zero() is a read-only reference to 0 void swap(zz_pEX& x, zz_pEX& y); // swap x and y (via "pointer swapping") zz_pEX::zz_pEX(long i, const zz_pE& c); zz_pEX::zz_pEX(long i, const zz_p& c); zz_pEX::zz_pEX(long i, long c); // initilaize to c*X^i; provided for backward compatibility ntl-6.2.1/doc/lzz_pEXFactoring.cpp.html000644 000765 000024 00000030704 12377144460 020276 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/lzz_pEXFactoring.cpp.html

/**************************************************************************\

MODULE: zz_pEXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over zz_pE, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/lzz_pEX.h>
#include <NTL/pair_lzz_pEX_long.h>

void SquareFreeDecomp(vec_pair_zz_pEX_long& u, const zz_pEX& f);
vec_pair_zz_pEX_long SquareFreeDecomp(const zz_pEX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a list of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_zz_pE& x, const zz_pEX& f);
vec_zz_pE FindRoots(const zz_pEX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(zz_pE& root, const zz_pEX& f);
zz_pE FindRoot(const zz_pEX& f);

// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void NewDDF(vec_pair_zz_pEX_long& factors, const zz_pEX& f,
            const zz_pEX& h, long verbose=0);

vec_pair_zz_pEX_long NewDDF(const zz_pEX& f, const zz_pEX& h,
         long verbose=0);


// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^{zz_pE::cardinality()} mod f.

// This routine implements the baby step/giant step algorithm
// of [Kaltofen and Shoup, STOC 1995].
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

// NOTE: When factoring "large" polynomials,
// this routine uses external files to store some intermediate
// results, which are removed if the routine terminates normally.
// These files are stored in the current directory under names of the
// form ddf-*-baby-* and ddf-*-giant-*.
// The definition of "large" is controlled by the variable

      extern double zz_pEXFileThresh

// which can be set by the user.  If the sizes of the tables
// exceeds zz_pEXFileThresh KB, external files are used.
// Initial value is NTL_FILE_THRESH (defined in tools.h).



void EDF(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& h,
         long d, long verbose=0);

vec_zz_pEX EDF(const zz_pEX& f, const zz_pEX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  h = X^{zz_pE::cardinality()} mod
// f.  d = degree of irreducible factors of f.  This routine
// implements the algorithm of [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void RootEDF(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0);
vec_zz_pEX RootEDF(const zz_pEX& f, long verbose=0);

// EDF for d==1


void SFCanZass(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0);
vec_zz_pEX SFCanZass(const zz_pEX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_zz_pEX_long& factors, const zz_pEX& f,
             long verbose=0);

vec_pair_zz_pEX_long CanZass(const zz_pEX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: these routines use modular composition.  The space
// used for the required tables can be controlled by the variable
// zz_pEXArgBound (see zz_pEX.txt).



void mul(zz_pEX& f, const vec_pair_zz_pEX_long& v);
zz_pEX mul(const vec_pair_zz_pEX_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const zz_pEX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// zz_pE::cardinality()^{-iter}.  This implements an algorithm from [Shoup,
// J. Symbolic Comp. 17:371-391, 1994].

long DetIrredTest(const zz_pEX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const zz_pEX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(zz_pEX& f, long n);
zz_pEX BuildIrred_zz_pEX(long n);

// Build a monic irreducible poly of degree n. 

void BuildRandomIrred(zz_pEX& f, const zz_pEX& g);
zz_pEX BuildRandomIrred(const zz_pEX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.


long IterComputeDegree(const zz_pEX& h, const zz_pEXModulus& F);

// f is assumed to be an "equal degree" polynomial, and h =
// X^{zz_pE::cardinality()} mod f.  The common degree of the irreducible 
// factors of f is computed.  Uses a "baby step/giant step" algorithm, similar
// to NewDDF.  Although asymptotocally slower than RecComputeDegree
// (below), it is faster for reasonably sized inputs.

long RecComputeDegree(const zz_pEX& h, const zz_pEXModulus& F);

// f is assumed to be an "equal degree" polynomial, 
// h = X^{zz_pE::cardinality()} mod f.  
// The common degree of the irreducible factors of f is
// computed Uses a recursive algorithm similar to DetIrredTest.

void TraceMap(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F,
              const zz_pEX& h);

zz_pEX TraceMap(const zz_pEX& a, long d, const zz_pEXModulus& F,
              const zz_pEX& h);

// Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0,
// and h = X^q mod f, q a power of zz_pE::cardinality().  This routine
// implements an algorithm from [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void PowerCompose(zz_pEX& w, const zz_pEX& h, long d, const zz_pEXModulus& F);

zz_pEX PowerCompose(const zz_pEX& h, long d, const zz_pEXModulus& F);

// Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q
// mod f, q a power of zz_pE::cardinality().  This routine implements an
// algorithm from [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992]

ntl-6.2.1/doc/lzz_pEXFactoring.txt000644 000765 000024 00000015007 12377144460 017367 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: zz_pEXFactoring SUMMARY: Routines are provided for factorization of polynomials over zz_pE, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_zz_pEX_long& u, const zz_pEX& f); vec_pair_zz_pEX_long SquareFreeDecomp(const zz_pEX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a list of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_zz_pE& x, const zz_pEX& f); vec_zz_pE FindRoots(const zz_pEX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(zz_pE& root, const zz_pEX& f); zz_pE FindRoot(const zz_pEX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void NewDDF(vec_pair_zz_pEX_long& factors, const zz_pEX& f, const zz_pEX& h, long verbose=0); vec_pair_zz_pEX_long NewDDF(const zz_pEX& f, const zz_pEX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^{zz_pE::cardinality()} mod f. // This routine implements the baby step/giant step algorithm // of [Kaltofen and Shoup, STOC 1995]. // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. // NOTE: When factoring "large" polynomials, // this routine uses external files to store some intermediate // results, which are removed if the routine terminates normally. // These files are stored in the current directory under names of the // form ddf-*-baby-* and ddf-*-giant-*. // The definition of "large" is controlled by the variable extern double zz_pEXFileThresh // which can be set by the user. If the sizes of the tables // exceeds zz_pEXFileThresh KB, external files are used. // Initial value is NTL_FILE_THRESH (defined in tools.h). void EDF(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& h, long d, long verbose=0); vec_zz_pEX EDF(const zz_pEX& f, const zz_pEX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. h = X^{zz_pE::cardinality()} mod // f. d = degree of irreducible factors of f. This routine // implements the algorithm of [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void RootEDF(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0); vec_zz_pEX RootEDF(const zz_pEX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0); vec_zz_pEX SFCanZass(const zz_pEX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_zz_pEX_long& factors, const zz_pEX& f, long verbose=0); vec_pair_zz_pEX_long CanZass(const zz_pEX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: these routines use modular composition. The space // used for the required tables can be controlled by the variable // zz_pEXArgBound (see zz_pEX.txt). void mul(zz_pEX& f, const vec_pair_zz_pEX_long& v); zz_pEX mul(const vec_pair_zz_pEX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const zz_pEX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // zz_pE::cardinality()^{-iter}. This implements an algorithm from [Shoup, // J. Symbolic Comp. 17:371-391, 1994]. long DetIrredTest(const zz_pEX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const zz_pEX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(zz_pEX& f, long n); zz_pEX BuildIrred_zz_pEX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(zz_pEX& f, const zz_pEX& g); zz_pEX BuildRandomIrred(const zz_pEX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. long IterComputeDegree(const zz_pEX& h, const zz_pEXModulus& F); // f is assumed to be an "equal degree" polynomial, and h = // X^{zz_pE::cardinality()} mod f. The common degree of the irreducible // factors of f is computed. Uses a "baby step/giant step" algorithm, similar // to NewDDF. Although asymptotocally slower than RecComputeDegree // (below), it is faster for reasonably sized inputs. long RecComputeDegree(const zz_pEX& h, const zz_pEXModulus& F); // f is assumed to be an "equal degree" polynomial, // h = X^{zz_pE::cardinality()} mod f. // The common degree of the irreducible factors of f is // computed Uses a recursive algorithm similar to DetIrredTest. void TraceMap(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& h); zz_pEX TraceMap(const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& h); // Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, // and h = X^q mod f, q a power of zz_pE::cardinality(). This routine // implements an algorithm from [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void PowerCompose(zz_pEX& w, const zz_pEX& h, long d, const zz_pEXModulus& F); zz_pEX PowerCompose(const zz_pEX& h, long d, const zz_pEXModulus& F); // Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q // mod f, q a power of zz_pE::cardinality(). This routine implements an // algorithm from [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992] ntl-6.2.1/doc/lzz_pX.cpp.html000644 000765 000024 00000151601 12377144460 016334 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/lzz_pX.cpp.html

/**************************************************************************\

MODULE: zz_pX

SUMMARY:

The class zz_pX implements polynomial arithmetic modulo p.

Polynomial arithmetic is implemented using a combination of classical
routines, Karatsuba, and FFT.

\**************************************************************************/

#include "zz_p.h"
#include "vec_zz_p.h"

class zz_pX {
public:

   zz_pX(); // initial value 0

   zz_pX(const zz_pX& a); // copy
   explicit zz_pX(zz_p a); // promotion
   explicit zz_pX(long a); // promotion

   zz_pX& operator=(const zz_pX& a); // assignment
   zz_pX& operator=(zz_p a);
   zz_pX& operator=(long a);

   ~zz_pX(); // destructor

   zz_pX(INIT_MONO_TYPE, long i, zz_p c);
   zz_pX(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as zz_pX(INIT_MONO, i, c)

   zz_pX(INIT_MONO_TYPE, long i);
   // initialize to X^i, invoke as zz_pX(INIT_MONO, i)

   typedef zz_p coeff_type;

   // ...


};





/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().


NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const zz_pX& a);  // return deg(a); deg(0) == -1.

const zz_p coeff(const zz_pX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const zz_p LeadCoeff(const zz_pX& a);
// returns leading term of a, or zero if a == 0

const zz_p ConstTerm(const zz_pX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(zz_pX& x, long i, zz_p a);
void SetCoeff(zz_pX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(zz_pX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(zz_pX& x); // x is set to the monomial X

long IsX(const zz_pX& a); // test if x = X




zz_p& zz_pX::operator[](long i);
const zz_p& zz_pX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void zz_pX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void zz_pX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void zz_pX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const zz_pX& a, const zz_pX& b);
long operator!=(const zz_pX& a, const zz_pX& b);

long IsZero(const zz_pX& a); // test for 0
long IsOne(const zz_pX& a); // test for 1

// PROMOTIONS: operators ==, != promote {long, zz_p} to zz_pX on (a, b)


/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

zz_pX operator+(const zz_pX& a, const zz_pX& b);
zz_pX operator-(const zz_pX& a, const zz_pX& b);

zz_pX operator-(const zz_pX& a); // unary -

zz_pX& operator+=(zz_pX& x, const zz_pX& a);
zz_pX& operator+=(zz_pX& x, zz_p a);
zz_pX& operator+=(zz_pX& x, long a);

zz_pX& operator-=(zz_pX& x, const zz_pX& a);
zz_pX& operator-=(zz_pX& x, zz_p a);
zz_pX& operator-=(zz_pX& x, long a);

zz_pX& operator++(zz_pX& x);  // prefix
void operator++(zz_pX& x, int);  // postfix

zz_pX& operator--(zz_pX& x);  // prefix
void operator--(zz_pX& x, int);  // postfix

// procedural versions:


void add(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a + b
void sub(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a - b
void negate(zz_pX& x, const zz_pX& a); // x = -a

// PROMOTIONS: binary +, - and procedures add, sub promote {long, zz_p}
// to zz_pX on (a, b).


/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

zz_pX operator*(const zz_pX& a, const zz_pX& b);

zz_pX& operator*=(zz_pX& x, const zz_pX& a);
zz_pX& operator*=(zz_pX& x, zz_p a);
zz_pX& operator*=(zz_pX& x, long a);

// procedural versions:


void mul(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a * b

void sqr(zz_pX& x, const zz_pX& a); // x = a^2
zz_pX sqr(const zz_pX& a);

// PROMOTIONS: operator * and procedure mul promote {long, zz_p} to zz_pX
// on (a, b).

void power(zz_pX& x, const zz_pX& a, long e);  // x = a^e (e >= 0)
zz_pX power(const zz_pX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

zz_pX operator<<(const zz_pX& a, long n);
zz_pX operator>>(const zz_pX& a, long n);

zz_pX& operator<<=(zz_pX& x, long n);
zz_pX& operator>>=(zz_pX& x, long n);

// procedural versions:

void LeftShift(zz_pX& x, const zz_pX& a, long n);
zz_pX LeftShift(const zz_pX& a, long n);

void RightShift(zz_pX& x, const zz_pX& a, long n);
zz_pX RightShift(const zz_pX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

zz_pX operator/(const zz_pX& a, const zz_pX& b);
zz_pX operator%(const zz_pX& a, const zz_pX& b);

zz_pX& operator/=(zz_pX& x, const zz_pX& a);
zz_pX& operator/=(zz_pX& x, zz_p a);
zz_pX& operator/=(zz_pX& x, long a);

zz_pX& operator%=(zz_pX& x, const zz_pX& b);


// procedural versions:


void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b);
// q = a/b, r = a%b

void div(zz_pX& q, const zz_pX& a, const zz_pX& b);
// q = a/b

void rem(zz_pX& r, const zz_pX& a, const zz_pX& b);
// r = a%b

long divide(zz_pX& q, const zz_pX& a, const zz_pX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const zz_pX& a, const zz_pX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

// PROMOTIONS: operator / and procedure div promote {long, zz_p} to zz_pX
// on (a, b).


/**************************************************************************\

                                   GCD's

These routines are intended for use when p is prime.

\**************************************************************************/


void GCD(zz_pX& x, const zz_pX& a, const zz_pX& b);
zz_pX GCD(const zz_pX& a, const zz_pX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b);
// d = gcd(a,b), a s + b t = d 


// NOTE: A classical algorithm is used, switching over to a
// "half-GCD" algorithm for large degree


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be integers between 0 and p-1, amd
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary integers which are reduced modulo p, and leading zeros
stripped.

\**************************************************************************/

istream& operator>>(istream& s, zz_pX& x);
ostream& operator<<(ostream& s, const zz_pX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(zz_pX& x, const zz_pX& a);
zz_pX diff(const zz_pX& a);
// x = derivative of a


void MakeMonic(zz_pX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case.

void reverse(zz_pX& x, const zz_pX& a, long hi);
zz_pX reverse(const zz_pX& a, long hi);

void reverse(zz_pX& x, const zz_pX& a);
zz_pX reverse(const zz_pX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_zz_p& x, const zz_pX& a, long n);
vec_zz_p VectorCopy(const zz_pX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.





/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(zz_pX& x, long n);
zz_pX random_zz_pX(long n);
// x = random polynomial of degree < n 


/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(zz_pX& x, const vec_zz_p& a);
zz_pX BuildFromRoots(const vec_zz_p& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n =
// a.length()

void eval(zz_p& b, const zz_pX& f, zz_p a);
zz_p eval(const zz_pX& f, zz_p a);
// b = f(a)

void eval(vec_zz_p& b, const zz_pX& f, const vec_zz_p& a);
vec_zz_p eval(const zz_pX& f, const vec_zz_p& a);
//  b.SetLength(a.length());  b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(zz_pX& f, const vec_zz_p& a, const vec_zz_p& b);
zz_pX interpolate(const vec_zz_p& a, const vec_zz_p& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  p should
// be prime.

/**************************************************************************\

                       Arithmetic mod X^n

It is required that n >= 0, otherwise an error is raised.

\**************************************************************************/

void trunc(zz_pX& x, const zz_pX& a, long n); // x = a % X^n
zz_pX trunc(const zz_pX& a, long n);

void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n);
zz_pX MulTrunc(const zz_pX& a, const zz_pX& b, long n);
// x = a * b % X^n

void SqrTrunc(zz_pX& x, const zz_pX& a, long n);
zz_pX SqrTrunc(const zz_pX& a, long n);
// x = a^2 % X^n

void InvTrunc(zz_pX& x, const zz_pX& a, long n);
zz_pX InvTrunc(const zz_pX& a, long n);
// computes x = a^{-1} % X^n.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.

NOTE: if you want to do many computations with a fixed f, use the
zz_pXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pX& f);
zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pX& f);
// x = (a * b) % f

void SqrMod(zz_pX& x, const zz_pX& a, const zz_pX& f);
zz_pX SqrMod(const zz_pX& a, const zz_pX& f);
// x = a^2 % f

void MulByXMod(zz_pX& x, const zz_pX& a, const zz_pX& f);
zz_pX MulByXMod(const zz_pX& a, const zz_pX& f);
// x = (a * X) mod f

void InvMod(zz_pX& x, const zz_pX& a, const zz_pX& f);
zz_pX InvMod(const zz_pX& a, const zz_pX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(zz_pX& x, const zz_pX& a, const zz_pX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


// for modular exponentiation, see below



/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
zz_pXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations. Required: deg(f) > 0 and LeadCoeff(f)
invertible.

As an example, the following routine computes the product modulo f of a vector
of polynomials.

#include "zz_pX.h"

void product(zz_pX& x, const vec_zz_pX& v, const zz_pX& f)
{
   zz_pXModulus F(f);
   zz_pX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}


Note that automatic conversions are provided so that a zz_pX can
be used wherever a zz_pXModulus is required, and a zz_pXModulus
can be used wherever a zz_pX is required.



\**************************************************************************/

class zz_pXModulus {
public:
   zz_pXModulus(); // initially in an unusable state
   ~zz_pXModulus();

   zz_pXModulus(const zz_pXModulus&);  // copy

   zz_pXModulus& operator=(const zz_pXModulus&);  // assignment

   zz_pXModulus(const zz_pX& f); // initialize with f, deg(f) > 0

   operator const zz_pX& () const;
   // read-only access to f, implicit conversion operator

   const zz_pX& val() const;
   // read-only access to f, explicit notation

};

void build(zz_pXModulus& F, const zz_pX& f);
// pre-computes information about f and stores it in F.
// Note that the declaration zz_pXModulus F(f) is equivalent to
// zz_pXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).

long deg(const zz_pXModulus& F);  // return deg(f)

void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pXModulus& F);
zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(zz_pX& x, const zz_pX& a, const zz_pXModulus& F);
zz_pX SqrMod(const zz_pX& a, const zz_pXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(zz_pX& x, const zz_pX& a, const ZZ& e, const zz_pXModulus& F);
zz_pX PowerMod(const zz_pX& a, const ZZ& e, const zz_pXModulus& F);

void PowerMod(zz_pX& x, const zz_pX& a, long e, const zz_pXModulus& F);
zz_pX PowerMod(const zz_pX& a, long e, const zz_pXModulus& F);

// x = a^e % f; deg(a) < n (e may be negative)

void PowerXMod(zz_pX& x, const ZZ& e, const zz_pXModulus& F);
zz_pX PowerXMod(const ZZ& e, const zz_pXModulus& F);

void PowerXMod(zz_pX& x, long e, const zz_pXModulus& F);
zz_pX PowerXMod(long e, const zz_pXModulus& F);

// x = X^e % f (e may be negative)

void PowerXPlusAMod(zz_pX& x, const zz_p& a, const ZZ& e,
                    const zz_pXModulus& F);

zz_pX PowerXPlusAMod(const zz_p& a, const ZZ& e,
                           const zz_pXModulus& F);

void PowerXPlusAMod(zz_pX& x, const zz_p& a, long e,
                    const zz_pXModulus& F);

zz_pX PowerXPlusAMod(const zz_p& a, long e,
                           const zz_pXModulus& F);

// x = (X + a)^e % f (e may be negative)


void rem(zz_pX& x, const zz_pX& a, const zz_pXModulus& F);
// x = a % f

void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pXModulus& F);
// q = a/f, r = a%f

void div(zz_pX& q, const zz_pX& a, const zz_pXModulus& F);
// q = a/f

// operator notation:

zz_pX operator/(const zz_pX& a, const zz_pXModulus& F);
zz_pX operator%(const zz_pX& a, const zz_pXModulus& F);

zz_pX& operator/=(zz_pX& x, const zz_pXModulus& F);
zz_pX& operator%=(zz_pX& x, const zz_pXModulus& F);




/**************************************************************************\


                        More Pre-Conditioning

If you need to compute a * b % f for a fixed b, but for many a's, it
is much more efficient to first build a zz_pXMultiplier B for b, and
then use the MulMod routine below.

Here is an example that multiplies each element of a vector by a fixed
polynomial modulo f.

#include "zz_pX.h"

void mul(vec_zz_pX& v, const zz_pX& b, const zz_pX& f)
{
   zz_pXModulus F(f);
   zz_pXMultiplier B(b, F);
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(v[i], v[i], B, F);
}

Note that a (trivial) conversion operator from zz_pXMultiplier to zz_pX
is provided, so that a zz_pXMultiplier can be used in a context
where a zz_pX is required.


\**************************************************************************/


class zz_pXMultiplier {
public:
   zz_pXMultiplier(); // initially zero

   zz_pXMultiplier(const zz_pX& b, const zz_pXModulus& F);
      // initializes with b mod F, where deg(b) < deg(F)

   zz_pXMultiplier(const zz_pXMultiplier&);
   zz_pXMultiplier& operator=(const zz_pXMultiplier&);

   ~zz_pXMultiplier();

   const zz_pX& val() const; // read-only access to b

};

void build(zz_pXMultiplier& B, const zz_pX& b, const zz_pXModulus& F);
// pre-computes information about b and stores it in B; deg(b) <
// deg(F)

void MulMod(zz_pX& x, const zz_pX& a, const zz_pXMultiplier& B,
                                      const zz_pXModulus& F);

zz_pX MulMod(const zz_pX& a, const zz_pXMultiplier& B,
             const zz_pXModulus& F);

// x = (a * b) % F; deg(a) < deg(F)

/**************************************************************************\

                             vectors of zz_pX's

\**************************************************************************/


typedef Vec<zz_pX> vec_zz_pX; // backward compatibility



/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.



\**************************************************************************/

void CompMod(zz_pX& x, const zz_pX& g, const zz_pX& h, const zz_pXModulus& F);
zz_pX CompMod(const zz_pX& g, const zz_pX& h, const zz_pXModulus& F);
// x = g(h) mod f; deg(h) < n

void Comp2Mod(zz_pX& x1, zz_pX& x2, const zz_pX& g1, const zz_pX& g2,
              const zz_pX& h, const zz_pXModulus& F);
// xi = gi(h) mod f (i=1,2), deg(h) < n.

void CompMod3(zz_pX& x1, zz_pX& x2, zz_pX& x3,
              const zz_pX& g1, const zz_pX& g2, const zz_pX& g3,
              const zz_pX& h, const zz_pXModulus& F);
// xi = gi(h) mod f (i=1..3), deg(h) < n


/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a zz_pXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct zz_pXArgument {
   vec_zz_pX H;
};

void build(zz_pXArgument& H, const zz_pX& h, const zz_pXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n

void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& H,
             const zz_pXModulus& F);

zz_pX CompMod(const zz_pX& g, const zz_pXArgument& H,
             const zz_pXModulus& F);


extern long zz_pXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// zz_pXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in zz_pXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(zz_p& x, const zz_pVector& a, const zz_pX& b);
zz_p project(const zz_pVector& a, const zz_pX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k,
                   const zz_pX& h, const zz_pXModulus& F);

vec_zz_p ProjectPowers(const vec_zz_p& a, long k,
                   const zz_pX& h, const zz_pXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.
// Input and output may have "high order" zeroes stripped.

void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k,
                   const zz_pXArgument& H, const zz_pXModulus& F);

vec_zz_p ProjectPowers(const vec_zz_p& a, long k,
                   const zz_pXArgument& H, const zz_pXModulus& F);

// same as above, but uses a pre-computed zz_pXArgument


void UpdateMap(vec_zz_p& x, const vec_zz_p& a,
               const zz_pXMultiplier& B, const zz_pXModulus& F);

vec_zz_p UpdateMap(const vec_zz_p& a,
               const zz_pXMultiplier& B, const zz_pXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Restriction: a.length() <= deg(F).
// This is "transposed" MulMod by B.
// Input vector may have "high order" zeroes striped.
// The output will always have high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

These routines should be used with prime p.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(zz_pX& h, const vec_zz_p& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m

void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m);
zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m);

void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F);
zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/p.

void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m);
zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m);

void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F);
zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F);
// same as above, but guarantees that result is correct

void IrredPoly(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m);
zz_pX IrredPoly(const zz_pX& g, const zz_pXModulus& F, long m);

void IrredPoly(zz_pX& h, const zz_pX& g, const zz_pXModulus& F);
zz_pX IrredPoly(const zz_pX& g, const zz_pXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).


/**************************************************************************\

                   Traces, norms, resultants

These routines should be used with prime p.

\**************************************************************************/


void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F);
zz_p TraceMod(const zz_pX& a, const zz_pXModulus& F);

void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f);
zz_p TraceMod(const zz_pX& a, const zz_pXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_zz_p& S, const zz_pX& f);
vec_zz_p TraceVec(const zz_pX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f);
zz_p NormMod(const zz_pX& a, const zz_pX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)


void resultant(zz_p& x, const zz_pX& a, const zz_pX& b);
zz_pX resultant(zz_p& x, const zz_pX& a, const zz_pX& b);
// x = resultant(a, b)


void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& f);
zz_pX CharPolyMod(const zz_pX& a, const zz_pX& f);
// g = charcteristic polynomial of (a mod f); 0 < deg(f), deg(g) <
// deg(f).  This routine works for arbitrary f.  For irreducible f,
// is it faster to use IrredPolyMod, and then exponentiate as
// necessary, since in this case the characterstic polynomial
// is a power of the minimal polynomial.


/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(zz_pX& x) // x = 0
void set(zz_pX& x); // x = 1

void zz_pX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

zz_pX::zz_pX(INIT_SIZE_TYPE, long n);
// zz_pX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const zz_pX& zero();
// zz_pX::zero() is a read-only reference to 0

void swap(zz_pX& x, zz_pX& y);
// swap x and y (via "pointer swapping")


zz_pX::zz_pX(long i, zz_p c);
zz_pX::zz_pX(long i, long c);
 // initialize to c*X^i, provided for backward compatibility
ntl-6.2.1/doc/lzz_pX.txt000644 000765 000024 00000064606 12377144460 015436 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: zz_pX SUMMARY: The class zz_pX implements polynomial arithmetic modulo p. Polynomial arithmetic is implemented using a combination of classical routines, Karatsuba, and FFT. \**************************************************************************/ #include "zz_p.h" #include "vec_zz_p.h" class zz_pX { public: zz_pX(); // initial value 0 zz_pX(const zz_pX& a); // copy explicit zz_pX(zz_p a); // promotion explicit zz_pX(long a); // promotion zz_pX& operator=(const zz_pX& a); // assignment zz_pX& operator=(zz_p a); zz_pX& operator=(long a); ~zz_pX(); // destructor zz_pX(INIT_MONO_TYPE, long i, zz_p c); zz_pX(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as zz_pX(INIT_MONO, i, c) zz_pX(INIT_MONO_TYPE, long i); // initialize to X^i, invoke as zz_pX(INIT_MONO, i) typedef zz_p coeff_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const zz_pX& a); // return deg(a); deg(0) == -1. const zz_p coeff(const zz_pX& a, long i); // returns the coefficient of X^i, or zero if i not in range const zz_p LeadCoeff(const zz_pX& a); // returns leading term of a, or zero if a == 0 const zz_p ConstTerm(const zz_pX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(zz_pX& x, long i, zz_p a); void SetCoeff(zz_pX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(zz_pX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(zz_pX& x); // x is set to the monomial X long IsX(const zz_pX& a); // test if x = X zz_p& zz_pX::operator[](long i); const zz_p& zz_pX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void zz_pX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void zz_pX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void zz_pX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const zz_pX& a, const zz_pX& b); long operator!=(const zz_pX& a, const zz_pX& b); long IsZero(const zz_pX& a); // test for 0 long IsOne(const zz_pX& a); // test for 1 // PROMOTIONS: operators ==, != promote {long, zz_p} to zz_pX on (a, b) /**************************************************************************\ Addition \**************************************************************************/ // operator notation: zz_pX operator+(const zz_pX& a, const zz_pX& b); zz_pX operator-(const zz_pX& a, const zz_pX& b); zz_pX operator-(const zz_pX& a); // unary - zz_pX& operator+=(zz_pX& x, const zz_pX& a); zz_pX& operator+=(zz_pX& x, zz_p a); zz_pX& operator+=(zz_pX& x, long a); zz_pX& operator-=(zz_pX& x, const zz_pX& a); zz_pX& operator-=(zz_pX& x, zz_p a); zz_pX& operator-=(zz_pX& x, long a); zz_pX& operator++(zz_pX& x); // prefix void operator++(zz_pX& x, int); // postfix zz_pX& operator--(zz_pX& x); // prefix void operator--(zz_pX& x, int); // postfix // procedural versions: void add(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a + b void sub(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a - b void negate(zz_pX& x, const zz_pX& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub promote {long, zz_p} // to zz_pX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: zz_pX operator*(const zz_pX& a, const zz_pX& b); zz_pX& operator*=(zz_pX& x, const zz_pX& a); zz_pX& operator*=(zz_pX& x, zz_p a); zz_pX& operator*=(zz_pX& x, long a); // procedural versions: void mul(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a * b void sqr(zz_pX& x, const zz_pX& a); // x = a^2 zz_pX sqr(const zz_pX& a); // PROMOTIONS: operator * and procedure mul promote {long, zz_p} to zz_pX // on (a, b). void power(zz_pX& x, const zz_pX& a, long e); // x = a^e (e >= 0) zz_pX power(const zz_pX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: zz_pX operator<<(const zz_pX& a, long n); zz_pX operator>>(const zz_pX& a, long n); zz_pX& operator<<=(zz_pX& x, long n); zz_pX& operator>>=(zz_pX& x, long n); // procedural versions: void LeftShift(zz_pX& x, const zz_pX& a, long n); zz_pX LeftShift(const zz_pX& a, long n); void RightShift(zz_pX& x, const zz_pX& a, long n); zz_pX RightShift(const zz_pX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: zz_pX operator/(const zz_pX& a, const zz_pX& b); zz_pX operator%(const zz_pX& a, const zz_pX& b); zz_pX& operator/=(zz_pX& x, const zz_pX& a); zz_pX& operator/=(zz_pX& x, zz_p a); zz_pX& operator/=(zz_pX& x, long a); zz_pX& operator%=(zz_pX& x, const zz_pX& b); // procedural versions: void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b); // q = a/b, r = a%b void div(zz_pX& q, const zz_pX& a, const zz_pX& b); // q = a/b void rem(zz_pX& r, const zz_pX& a, const zz_pX& b); // r = a%b long divide(zz_pX& q, const zz_pX& a, const zz_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const zz_pX& a, const zz_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 // PROMOTIONS: operator / and procedure div promote {long, zz_p} to zz_pX // on (a, b). /**************************************************************************\ GCD's These routines are intended for use when p is prime. \**************************************************************************/ void GCD(zz_pX& x, const zz_pX& a, const zz_pX& b); zz_pX GCD(const zz_pX& a, const zz_pX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b); // d = gcd(a,b), a s + b t = d // NOTE: A classical algorithm is used, switching over to a // "half-GCD" algorithm for large degree /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, amd a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary integers which are reduced modulo p, and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, zz_pX& x); ostream& operator<<(ostream& s, const zz_pX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(zz_pX& x, const zz_pX& a); zz_pX diff(const zz_pX& a); // x = derivative of a void MakeMonic(zz_pX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case. void reverse(zz_pX& x, const zz_pX& a, long hi); zz_pX reverse(const zz_pX& a, long hi); void reverse(zz_pX& x, const zz_pX& a); zz_pX reverse(const zz_pX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_zz_p& x, const zz_pX& a, long n); vec_zz_p VectorCopy(const zz_pX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(zz_pX& x, long n); zz_pX random_zz_pX(long n); // x = random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(zz_pX& x, const vec_zz_p& a); zz_pX BuildFromRoots(const vec_zz_p& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = // a.length() void eval(zz_p& b, const zz_pX& f, zz_p a); zz_p eval(const zz_pX& f, zz_p a); // b = f(a) void eval(vec_zz_p& b, const zz_pX& f, const vec_zz_p& a); vec_zz_p eval(const zz_pX& f, const vec_zz_p& a); // b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(zz_pX& f, const vec_zz_p& a, const vec_zz_p& b); zz_pX interpolate(const vec_zz_p& a, const vec_zz_p& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. p should // be prime. /**************************************************************************\ Arithmetic mod X^n It is required that n >= 0, otherwise an error is raised. \**************************************************************************/ void trunc(zz_pX& x, const zz_pX& a, long n); // x = a % X^n zz_pX trunc(const zz_pX& a, long n); void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n); zz_pX MulTrunc(const zz_pX& a, const zz_pX& b, long n); // x = a * b % X^n void SqrTrunc(zz_pX& x, const zz_pX& a, long n); zz_pX SqrTrunc(const zz_pX& a, long n); // x = a^2 % X^n void InvTrunc(zz_pX& x, const zz_pX& a, long n); zz_pX InvTrunc(const zz_pX& a, long n); // computes x = a^{-1} % X^n. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the zz_pXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pX& f); zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pX& f); // x = (a * b) % f void SqrMod(zz_pX& x, const zz_pX& a, const zz_pX& f); zz_pX SqrMod(const zz_pX& a, const zz_pX& f); // x = a^2 % f void MulByXMod(zz_pX& x, const zz_pX& a, const zz_pX& f); zz_pX MulByXMod(const zz_pX& a, const zz_pX& f); // x = (a * X) mod f void InvMod(zz_pX& x, const zz_pX& a, const zz_pX& f); zz_pX InvMod(const zz_pX& a, const zz_pX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(zz_pX& x, const zz_pX& a, const zz_pX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) // for modular exponentiation, see below /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build zz_pXModulus F for f. This pre-computes information about f that speeds up subsequent computations. Required: deg(f) > 0 and LeadCoeff(f) invertible. As an example, the following routine computes the product modulo f of a vector of polynomials. #include "zz_pX.h" void product(zz_pX& x, const vec_zz_pX& v, const zz_pX& f) { zz_pXModulus F(f); zz_pX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } Note that automatic conversions are provided so that a zz_pX can be used wherever a zz_pXModulus is required, and a zz_pXModulus can be used wherever a zz_pX is required. \**************************************************************************/ class zz_pXModulus { public: zz_pXModulus(); // initially in an unusable state ~zz_pXModulus(); zz_pXModulus(const zz_pXModulus&); // copy zz_pXModulus& operator=(const zz_pXModulus&); // assignment zz_pXModulus(const zz_pX& f); // initialize with f, deg(f) > 0 operator const zz_pX& () const; // read-only access to f, implicit conversion operator const zz_pX& val() const; // read-only access to f, explicit notation }; void build(zz_pXModulus& F, const zz_pX& f); // pre-computes information about f and stores it in F. // Note that the declaration zz_pXModulus F(f) is equivalent to // zz_pXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const zz_pXModulus& F); // return deg(f) void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pXModulus& F); zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); zz_pX SqrMod(const zz_pX& a, const zz_pXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(zz_pX& x, const zz_pX& a, const ZZ& e, const zz_pXModulus& F); zz_pX PowerMod(const zz_pX& a, const ZZ& e, const zz_pXModulus& F); void PowerMod(zz_pX& x, const zz_pX& a, long e, const zz_pXModulus& F); zz_pX PowerMod(const zz_pX& a, long e, const zz_pXModulus& F); // x = a^e % f; deg(a) < n (e may be negative) void PowerXMod(zz_pX& x, const ZZ& e, const zz_pXModulus& F); zz_pX PowerXMod(const ZZ& e, const zz_pXModulus& F); void PowerXMod(zz_pX& x, long e, const zz_pXModulus& F); zz_pX PowerXMod(long e, const zz_pXModulus& F); // x = X^e % f (e may be negative) void PowerXPlusAMod(zz_pX& x, const zz_p& a, const ZZ& e, const zz_pXModulus& F); zz_pX PowerXPlusAMod(const zz_p& a, const ZZ& e, const zz_pXModulus& F); void PowerXPlusAMod(zz_pX& x, const zz_p& a, long e, const zz_pXModulus& F); zz_pX PowerXPlusAMod(const zz_p& a, long e, const zz_pXModulus& F); // x = (X + a)^e % f (e may be negative) void rem(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); // x = a % f void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pXModulus& F); // q = a/f, r = a%f void div(zz_pX& q, const zz_pX& a, const zz_pXModulus& F); // q = a/f // operator notation: zz_pX operator/(const zz_pX& a, const zz_pXModulus& F); zz_pX operator%(const zz_pX& a, const zz_pXModulus& F); zz_pX& operator/=(zz_pX& x, const zz_pXModulus& F); zz_pX& operator%=(zz_pX& x, const zz_pXModulus& F); /**************************************************************************\ More Pre-Conditioning If you need to compute a * b % f for a fixed b, but for many a's, it is much more efficient to first build a zz_pXMultiplier B for b, and then use the MulMod routine below. Here is an example that multiplies each element of a vector by a fixed polynomial modulo f. #include "zz_pX.h" void mul(vec_zz_pX& v, const zz_pX& b, const zz_pX& f) { zz_pXModulus F(f); zz_pXMultiplier B(b, F); long i; for (i = 0; i < v.length(); i++) MulMod(v[i], v[i], B, F); } Note that a (trivial) conversion operator from zz_pXMultiplier to zz_pX is provided, so that a zz_pXMultiplier can be used in a context where a zz_pX is required. \**************************************************************************/ class zz_pXMultiplier { public: zz_pXMultiplier(); // initially zero zz_pXMultiplier(const zz_pX& b, const zz_pXModulus& F); // initializes with b mod F, where deg(b) < deg(F) zz_pXMultiplier(const zz_pXMultiplier&); zz_pXMultiplier& operator=(const zz_pXMultiplier&); ~zz_pXMultiplier(); const zz_pX& val() const; // read-only access to b }; void build(zz_pXMultiplier& B, const zz_pX& b, const zz_pXModulus& F); // pre-computes information about b and stores it in B; deg(b) < // deg(F) void MulMod(zz_pX& x, const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F); zz_pX MulMod(const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F); // x = (a * b) % F; deg(a) < deg(F) /**************************************************************************\ vectors of zz_pX's \**************************************************************************/ typedef Vec vec_zz_pX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(zz_pX& x, const zz_pX& g, const zz_pX& h, const zz_pXModulus& F); zz_pX CompMod(const zz_pX& g, const zz_pX& h, const zz_pXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(zz_pX& x1, zz_pX& x2, const zz_pX& g1, const zz_pX& g2, const zz_pX& h, const zz_pXModulus& F); // xi = gi(h) mod f (i=1,2), deg(h) < n. void CompMod3(zz_pX& x1, zz_pX& x2, zz_pX& x3, const zz_pX& g1, const zz_pX& g2, const zz_pX& g3, const zz_pX& h, const zz_pXModulus& F); // xi = gi(h) mod f (i=1..3), deg(h) < n /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a zz_pXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct zz_pXArgument { vec_zz_pX H; }; void build(zz_pXArgument& H, const zz_pX& h, const zz_pXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& H, const zz_pXModulus& F); zz_pX CompMod(const zz_pX& g, const zz_pXArgument& H, const zz_pXModulus& F); extern long zz_pXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // zz_pXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in zz_pXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(zz_p& x, const zz_pVector& a, const zz_pX& b); zz_p project(const zz_pVector& a, const zz_pX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F); vec_zz_p ProjectPowers(const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. // Input and output may have "high order" zeroes stripped. void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F); vec_zz_p ProjectPowers(const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F); // same as above, but uses a pre-computed zz_pXArgument void UpdateMap(vec_zz_p& x, const vec_zz_p& a, const zz_pXMultiplier& B, const zz_pXModulus& F); vec_zz_p UpdateMap(const vec_zz_p& a, const zz_pXMultiplier& B, const zz_pXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Restriction: a.length() <= deg(F). // This is "transposed" MulMod by B. // Input vector may have "high order" zeroes striped. // The output will always have high order zeroes stripped. /**************************************************************************\ Minimum Polynomials These routines should be used with prime p. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(zz_pX& h, const vec_zz_p& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m); void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F); zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/p. void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m); void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F); zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F); // same as above, but guarantees that result is correct void IrredPoly(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); zz_pX IrredPoly(const zz_pX& g, const zz_pXModulus& F, long m); void IrredPoly(zz_pX& h, const zz_pX& g, const zz_pXModulus& F); zz_pX IrredPoly(const zz_pX& g, const zz_pXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Traces, norms, resultants These routines should be used with prime p. \**************************************************************************/ void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F); zz_p TraceMod(const zz_pX& a, const zz_pXModulus& F); void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f); zz_p TraceMod(const zz_pX& a, const zz_pXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_zz_p& S, const zz_pX& f); vec_zz_p TraceVec(const zz_pX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f); zz_p NormMod(const zz_pX& a, const zz_pX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(zz_p& x, const zz_pX& a, const zz_pX& b); zz_pX resultant(zz_p& x, const zz_pX& a, const zz_pX& b); // x = resultant(a, b) void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& f); zz_pX CharPolyMod(const zz_pX& a, const zz_pX& f); // g = charcteristic polynomial of (a mod f); 0 < deg(f), deg(g) < // deg(f). This routine works for arbitrary f. For irreducible f, // is it faster to use IrredPolyMod, and then exponentiate as // necessary, since in this case the characterstic polynomial // is a power of the minimal polynomial. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(zz_pX& x) // x = 0 void set(zz_pX& x); // x = 1 void zz_pX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). zz_pX::zz_pX(INIT_SIZE_TYPE, long n); // zz_pX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const zz_pX& zero(); // zz_pX::zero() is a read-only reference to 0 void swap(zz_pX& x, zz_pX& y); // swap x and y (via "pointer swapping") zz_pX::zz_pX(long i, zz_p c); zz_pX::zz_pX(long i, long c); // initialize to c*X^i, provided for backward compatibility ntl-6.2.1/doc/lzz_pXFactoring.cpp.html000644 000765 000024 00000027622 12377144460 020176 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/lzz_pXFactoring.cpp.html

/**************************************************************************\

MODULE: zz_pXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over zz_p, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include "zz_pX.h"
#include "pair_zz_pX_long.h"


void SquareFreeDecomp(vec_pair_zz_pX_long& u, const zz_pX& f);
vec_pair_zz_pX_long SquareFreeDecomp(const zz_pX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a lest of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_zz_p& x, const zz_pX& f);
vec_zz_p FindRoots(const zz_pX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(zz_p& root, const zz_pX& f);
zz_p FindRoot(const zz_pX& f);

// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void SFBerlekamp(vec_zz_pX& factors, const zz_pX& f, long verbose=0);
vec_zz_pX  SFBerlekamp(const zz_pX& f, long verbose=0);

// Assumes f is square-free and monic.  returns list of factors of f.
// Uses "Berlekamp" approach, as described in detail in [Shoup,
// J. Symbolic Comp. 20:363-397, 1995].

void berlekamp(vec_pair_zz_pX_long& factors, const zz_pX& f,
               long verbose=0);
vec_pair_zz_pX_long berlekamp(const zz_pX& f, long verbose=0);

// returns a list of factors, with multiplicities.  f must be monic.
// Calls SFBerlekamp.



void NewDDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h,
         long verbose=0);

vec_pair_zz_pX_long NewDDF(const zz_pX& f, const zz_pX& h,
         long verbose=0);

// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^p mod f.  This routine implements the
// baby step/giant step algorithm of [Kaltofen and Shoup, STOC 1995],
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

void EDF(vec_zz_pX& factors, const zz_pX& f, const zz_pX& h,
         long d, long verbose=0);

vec_zz_pX EDF(const zz_pX& f, const zz_pX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  h = X^p mod f.  d =
// degree of irreducible factors of f.  This routine implements the
// algorithm of [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992]


void RootEDF(vec_zz_pX& factors, const zz_pX& f, long verbose=0);
vec_zz_pX RootEDF(const zz_pX& f, long verbose=0);

// EDF for d==1

void SFCanZass(vec_zz_pX& factors, const zz_pX& f, long verbose=0);
vec_zz_pX SFCanZass(const zz_pX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_zz_pX_long& factors, const zz_pX& f,
             long verbose=0);
vec_pair_zz_pX_long CanZass(const zz_pX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.


void mul(zz_pX& f, const vec_pair_zz_pX_long& v);
zz_pX mul(const vec_pair_zz_pX_long& v);


// multiplies polynomials, with multiplicities

/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const zz_pX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// p^{-iter}.  This implements an algorithm from [Shoup, J. Symbolic
// Comp. 17:371-391, 1994].


long DetIrredTest(const zz_pX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const zz_pX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(zz_pX& f, long n);
zz_pX BuildIrred_zz_pX(long n);

// Build a monic irreducible poly of degree n.

void BuildRandomIrred(zz_pX& f, const zz_pX& g);
zz_pX BuildRandomIrred(const zz_pX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.

long ComputeDegree(const zz_pX& h, const zz_pXModulus& F);

// f is assumed to be an "equal degree" polynomial.  h = X^p mod f.
// The common degree of the irreducible factors of f is computed This
// routine is useful in counting points on elliptic curves

long ProbComputeDegree(const zz_pX& h, const zz_pXModulus& F);

// same as above, but uses a slightly faster probabilistic algorithm.
// The return value may be 0 or may be too big, but for large p
// (relative to n), this happens with very low probability.

void TraceMap(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F,
              const zz_pX& h);

zz_pX TraceMap(const zz_pX& a, long d, const zz_pXModulus& F,
              const zz_pX& h);

// w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, and h =
// X^q mod f, q a power of p.  This routine implements an algorithm
// from [von zur Gathen and Shoup, Computational Complexity 2:187-224,
// 1992]

void PowerCompose(zz_pX& w, const zz_pX& h, long d, const zz_pXModulus& F);
zz_pX PowerCompose(const zz_pX& h, long d, const zz_pXModulus& F);


// w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q mod f, q
// a power of p.  This routine implements an algorithm from [von zur
// Gathen and Shoup, Computational Complexity 2:187-224, 1992]

ntl-6.2.1/doc/lzz_pXFactoring.txt000644 000765 000024 00000013750 12377144460 017265 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: zz_pXFactoring SUMMARY: Routines are provided for factorization of polynomials over zz_p, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include "zz_pX.h" #include "pair_zz_pX_long.h" void SquareFreeDecomp(vec_pair_zz_pX_long& u, const zz_pX& f); vec_pair_zz_pX_long SquareFreeDecomp(const zz_pX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a lest of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_zz_p& x, const zz_pX& f); vec_zz_p FindRoots(const zz_pX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(zz_p& root, const zz_pX& f); zz_p FindRoot(const zz_pX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void SFBerlekamp(vec_zz_pX& factors, const zz_pX& f, long verbose=0); vec_zz_pX SFBerlekamp(const zz_pX& f, long verbose=0); // Assumes f is square-free and monic. returns list of factors of f. // Uses "Berlekamp" approach, as described in detail in [Shoup, // J. Symbolic Comp. 20:363-397, 1995]. void berlekamp(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose=0); vec_pair_zz_pX_long berlekamp(const zz_pX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SFBerlekamp. void NewDDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h, long verbose=0); vec_pair_zz_pX_long NewDDF(const zz_pX& f, const zz_pX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^p mod f. This routine implements the // baby step/giant step algorithm of [Kaltofen and Shoup, STOC 1995], // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. void EDF(vec_zz_pX& factors, const zz_pX& f, const zz_pX& h, long d, long verbose=0); vec_zz_pX EDF(const zz_pX& f, const zz_pX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. h = X^p mod f. d = // degree of irreducible factors of f. This routine implements the // algorithm of [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992] void RootEDF(vec_zz_pX& factors, const zz_pX& f, long verbose=0); vec_zz_pX RootEDF(const zz_pX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_zz_pX& factors, const zz_pX& f, long verbose=0); vec_zz_pX SFCanZass(const zz_pX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose=0); vec_pair_zz_pX_long CanZass(const zz_pX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. void mul(zz_pX& f, const vec_pair_zz_pX_long& v); zz_pX mul(const vec_pair_zz_pX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const zz_pX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // p^{-iter}. This implements an algorithm from [Shoup, J. Symbolic // Comp. 17:371-391, 1994]. long DetIrredTest(const zz_pX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const zz_pX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(zz_pX& f, long n); zz_pX BuildIrred_zz_pX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(zz_pX& f, const zz_pX& g); zz_pX BuildRandomIrred(const zz_pX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. long ComputeDegree(const zz_pX& h, const zz_pXModulus& F); // f is assumed to be an "equal degree" polynomial. h = X^p mod f. // The common degree of the irreducible factors of f is computed This // routine is useful in counting points on elliptic curves long ProbComputeDegree(const zz_pX& h, const zz_pXModulus& F); // same as above, but uses a slightly faster probabilistic algorithm. // The return value may be 0 or may be too big, but for large p // (relative to n), this happens with very low probability. void TraceMap(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& h); zz_pX TraceMap(const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& h); // w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, and h = // X^q mod f, q a power of p. This routine implements an algorithm // from [von zur Gathen and Shoup, Computational Complexity 2:187-224, // 1992] void PowerCompose(zz_pX& w, const zz_pX& h, long d, const zz_pXModulus& F); zz_pX PowerCompose(const zz_pX& h, long d, const zz_pXModulus& F); // w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q mod f, q // a power of p. This routine implements an algorithm from [von zur // Gathen and Shoup, Computational Complexity 2:187-224, 1992] ntl-6.2.1/doc/mat_GF2.cpp.html000644 000765 000024 00000036333 12377144460 016271 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_GF2.cpp.html

/**************************************************************************\

MODULE: mat_GF2

SUMMARY:

The class mat_GF2 implements matrices over GF(2).
Each row is a vec_GF2 of the same length.

For a mat_GF2 M, one may access row i of M as M[i],
indexing from 0, or as M(i), indexing from 1.

Individual elements of M may be accessed as M[i][j],
indexing from 0, or M(i, j), indexing from 1.
Some restrictions apply (see vec_GF2.txt for details).
Alternatively, one may use methods get and put.

\**************************************************************************/


#include <NTL/vec_vec_GF2.h>

class mat_GF2 {
public:

   mat_GF2(); // initially 0 x 0

   mat_GF2(const mat_GF2& a);
   mat_GF2& operator=(const mat_GF2& a);
   ~mat_GF2();

   mat_GF2(INIT_SIZE_TYPE, long n, long m);
   // mat_T(INIT_SIZE, n, m) initializes an n x m matrix, 
   // clearing all bits.



   void SetDims(long n, long m);
   // M.SetDims(n, m) makes M have dimension n x m.  If the number of
   // columns (m) changes, previous storage is freed, and space for M
   // is reallocated and initialized; otherwise, more rows are
   // allocated as necessary (when number of rows increases),
   // excess rows are retained (when number of rows decreases),
   // and--importantly--the contents do not change.

   long NumRows() const;
   // M.NumRows() returns the number of rows of M

   long NumCols() const;
   // M.NumCols() returns the number of columns of M

   vec_GF2& operator[](long i);
   const vec_GF2& operator[](long i) const;
   // access row i, initial index 0.  Any attempt to change the length
   // of this row will raise an error.


   vec_GF2& operator()(long i);
   const vec_GF2& operator()(long i) const;
   // access row i, initial index 1.  Any attempt to change the length
   // of this row will raise an error.


   GF2 get(long i, long j) const;
   // returns entry (i, j), indexing from 0

   void put(long i, long j, GF2 a);
   void put(long i, long j, long a);
   // set entry (i, j) to a, indexing from 0

   // Here are the subscripting operations defined using
   // the "helper" classes subscript_GF2 and const_subscript_GF2.

   subscript_GF2 operator()(long i, long j);

   const_subscript_GF2 operator()(long i, long j) const;

   long position(const vec_GF2& a) const;
   // returns index of a in matrix, or -1 if not present;
   // equivalent to rep(*this).position(a);

   long position1(const vec_GF2& a) const;
   // returns index of a in matrix, or -1 if not present;
   // equivalent to rep(*this).position1(a);

   void kill(); // free space and make 0 x 0.

};

const vec_vec_GF2& rep(const mat_GF2& a);
// read-only access to underlying representation.

void swap(mat_GF2& X, mat_GF2& Y);
// swap X and Y (fast pointer swap)

void conv(mat_GF2& X, const vec_vec_GF2& A);
mat_GF2 to_mat_GF2(const vec_vec_GF2& A);
// convert a vector of vec_GF2's to a matrix

// equality testing:

long operator==(const mat_GF2& A, const mat_GF2& B);
long operator!=(const mat_GF2& A, const mat_GF2& B);

// Input/Output:
//    input format is the same as for a vector of vec_GF2s.

istream& operator>>(istream&, mat_GF2&);
ostream& operator<<(ostream&, const mat_GF2&);




// procedural arithmetic routines:

void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B);
// X = A + B

void sub(mat_GF2& X, const mat_GF2& A, const mat_GF2& B);
// X = A - B = A + B

void negate(mat_GF2& X, const mat_GF2& A);
// X = -A = A 

void mul(mat_GF2& X, const mat_GF2& A, const mat_GF2& B);
// X = A * B

void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b);
// x = A * b

void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B);
// x = a * B


void mul(mat_GF2& X, const mat_GF2& A, GF2 b);
void mul(mat_GF2& X, const mat_GF2& A, long b);
// X = A * b

void mul(mat_GF2& X, GF2 a, const mat_GF2& B);
void mul(mat_GF2& X, long a, const mat_GF2& B);
// X = a * B

void determinant(GF2& d, const mat_GF2& A);
GF2 determinant(const mat_GF2& A);
// d =  determinant of A

void transpose(mat_GF2& X, const mat_GF2& A);
mat_GF2 transpose(const mat_GF2& A);
// X = transpose of A

void solve(GF2& d, vec_GF2& x, const mat_GF2& A, const vec_GF2& b);
// A is an n x n matrix, b is a length n vector.  Computes d = det(A).  
// If d != 0, solves x*A = b. 

void inv(GF2& d, mat_GF2& X, const mat_GF2& A);
// A is an n x n matrix.  Computes d = det(A).  If d != 0,
// computes X = A^{-1}. 

void sqr(mat_GF2& X, const mat_GF2& A);
mat_GF2 sqr(const mat_GF2& A);
// X = A*A   

void inv(mat_GF2& X, const mat_GF2& A);
mat_GF2 inv(const mat_GF2& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_GF2& X, const mat_GF2& A, const ZZ& e);
mat_GF2 power(const mat_GF2& A, const ZZ& e);

void power(mat_GF2& X, const mat_GF2& A, long e);
mat_GF2 power(const mat_GF2& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).


void ident(mat_GF2& X, long n);
mat_GF2 ident_mat_GF2(long n);
// X = n x n identity matrix

long IsIdent(const mat_GF2& A, long n);
// test if A is n x n identity matrix


void diag(mat_GF2& X, long n, GF2 d);
mat_GF2 diag(long n, GF2 d);
// X = n x n diagonal matrix with diagonal element d

long IsDiag(const mat_GF2& A, long n, long d);
// test if X is an n x n diagonal matrix with diagonal element (d mod 2)


long gauss(mat_GF2& M);
long gauss(mat_GF2& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_GF2& X, const mat_GF2& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form


void kernel(mat_GF2& X, const mat_GF2& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.

// miscellaneous:


void clear(mat_GF2& X);
// X = 0 (dimension unchanged)

long IsZero(const mat_GF2& A);
// test if A is the zero matrix (any dimension)


// arithmetic operator notation:

mat_GF2 operator+(const mat_GF2& a, const mat_GF2& b);
mat_GF2 operator-(const mat_GF2& a, const mat_GF2& b);
mat_GF2 operator*(const mat_GF2& a, const mat_GF2& b);

mat_GF2 operator-(const mat_GF2& a);


// matrix/scalar multiplication:

mat_GF2 operator*(const mat_GF2& a, GF2 b);
mat_GF2 operator*(const mat_GF2& a, long b);

mat_GF2 operator*(GF2 a, const mat_GF2& b);
mat_GF2 operator*(long a, const mat_GF2& b);

// matrix/vector multiplication:

vec_GF2 operator*(const mat_GF2& a, const vec_GF2& b);

vec_GF2 operator*(const vec_GF2& a, const mat_GF2& b);


// assignment operator notation:

mat_GF2& operator+=(mat_GF2& x, const mat_GF2& a);
mat_GF2& operator-=(mat_GF2& x, const mat_GF2& a);
mat_GF2& operator*=(mat_GF2& x, const mat_GF2& a);

mat_GF2& operator*=(mat_GF2& x, GF2 a);
mat_GF2& operator*=(mat_GF2& x, long a);

vec_GF2& operator*=(vec_GF2& x, const mat_GF2& a);


ntl-6.2.1/doc/mat_GF2.txt000644 000765 000024 00000015467 12377144460 015370 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_GF2 SUMMARY: The class mat_GF2 implements matrices over GF(2). Each row is a vec_GF2 of the same length. For a mat_GF2 M, one may access row i of M as M[i], indexing from 0, or as M(i), indexing from 1. Individual elements of M may be accessed as M[i][j], indexing from 0, or M(i, j), indexing from 1. Some restrictions apply (see vec_GF2.txt for details). Alternatively, one may use methods get and put. \**************************************************************************/ #include class mat_GF2 { public: mat_GF2(); // initially 0 x 0 mat_GF2(const mat_GF2& a); mat_GF2& operator=(const mat_GF2& a); ~mat_GF2(); mat_GF2(INIT_SIZE_TYPE, long n, long m); // mat_T(INIT_SIZE, n, m) initializes an n x m matrix, // clearing all bits. void SetDims(long n, long m); // M.SetDims(n, m) makes M have dimension n x m. If the number of // columns (m) changes, previous storage is freed, and space for M // is reallocated and initialized; otherwise, more rows are // allocated as necessary (when number of rows increases), // excess rows are retained (when number of rows decreases), // and--importantly--the contents do not change. long NumRows() const; // M.NumRows() returns the number of rows of M long NumCols() const; // M.NumCols() returns the number of columns of M vec_GF2& operator[](long i); const vec_GF2& operator[](long i) const; // access row i, initial index 0. Any attempt to change the length // of this row will raise an error. vec_GF2& operator()(long i); const vec_GF2& operator()(long i) const; // access row i, initial index 1. Any attempt to change the length // of this row will raise an error. GF2 get(long i, long j) const; // returns entry (i, j), indexing from 0 void put(long i, long j, GF2 a); void put(long i, long j, long a); // set entry (i, j) to a, indexing from 0 // Here are the subscripting operations defined using // the "helper" classes subscript_GF2 and const_subscript_GF2. subscript_GF2 operator()(long i, long j); const_subscript_GF2 operator()(long i, long j) const; long position(const vec_GF2& a) const; // returns index of a in matrix, or -1 if not present; // equivalent to rep(*this).position(a); long position1(const vec_GF2& a) const; // returns index of a in matrix, or -1 if not present; // equivalent to rep(*this).position1(a); void kill(); // free space and make 0 x 0. }; const vec_vec_GF2& rep(const mat_GF2& a); // read-only access to underlying representation. void swap(mat_GF2& X, mat_GF2& Y); // swap X and Y (fast pointer swap) void conv(mat_GF2& X, const vec_vec_GF2& A); mat_GF2 to_mat_GF2(const vec_vec_GF2& A); // convert a vector of vec_GF2's to a matrix // equality testing: long operator==(const mat_GF2& A, const mat_GF2& B); long operator!=(const mat_GF2& A, const mat_GF2& B); // Input/Output: // input format is the same as for a vector of vec_GF2s. istream& operator>>(istream&, mat_GF2&); ostream& operator<<(ostream&, const mat_GF2&); // procedural arithmetic routines: void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); // X = A + B void sub(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); // X = A - B = A + B void negate(mat_GF2& X, const mat_GF2& A); // X = -A = A void mul(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); // X = A * B void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b); // x = A * b void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B); // x = a * B void mul(mat_GF2& X, const mat_GF2& A, GF2 b); void mul(mat_GF2& X, const mat_GF2& A, long b); // X = A * b void mul(mat_GF2& X, GF2 a, const mat_GF2& B); void mul(mat_GF2& X, long a, const mat_GF2& B); // X = a * B void determinant(GF2& d, const mat_GF2& A); GF2 determinant(const mat_GF2& A); // d = determinant of A void transpose(mat_GF2& X, const mat_GF2& A); mat_GF2 transpose(const mat_GF2& A); // X = transpose of A void solve(GF2& d, vec_GF2& x, const mat_GF2& A, const vec_GF2& b); // A is an n x n matrix, b is a length n vector. Computes d = det(A). // If d != 0, solves x*A = b. void inv(GF2& d, mat_GF2& X, const mat_GF2& A); // A is an n x n matrix. Computes d = det(A). If d != 0, // computes X = A^{-1}. void sqr(mat_GF2& X, const mat_GF2& A); mat_GF2 sqr(const mat_GF2& A); // X = A*A void inv(mat_GF2& X, const mat_GF2& A); mat_GF2 inv(const mat_GF2& A); // X = A^{-1}; error is raised if A is singular void power(mat_GF2& X, const mat_GF2& A, const ZZ& e); mat_GF2 power(const mat_GF2& A, const ZZ& e); void power(mat_GF2& X, const mat_GF2& A, long e); mat_GF2 power(const mat_GF2& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_GF2& X, long n); mat_GF2 ident_mat_GF2(long n); // X = n x n identity matrix long IsIdent(const mat_GF2& A, long n); // test if A is n x n identity matrix void diag(mat_GF2& X, long n, GF2 d); mat_GF2 diag(long n, GF2 d); // X = n x n diagonal matrix with diagonal element d long IsDiag(const mat_GF2& A, long n, long d); // test if X is an n x n diagonal matrix with diagonal element (d mod 2) long gauss(mat_GF2& M); long gauss(mat_GF2& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_GF2& X, const mat_GF2& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_GF2& X, const mat_GF2& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_GF2& X); // X = 0 (dimension unchanged) long IsZero(const mat_GF2& A); // test if A is the zero matrix (any dimension) // arithmetic operator notation: mat_GF2 operator+(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator-(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator*(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator-(const mat_GF2& a); // matrix/scalar multiplication: mat_GF2 operator*(const mat_GF2& a, GF2 b); mat_GF2 operator*(const mat_GF2& a, long b); mat_GF2 operator*(GF2 a, const mat_GF2& b); mat_GF2 operator*(long a, const mat_GF2& b); // matrix/vector multiplication: vec_GF2 operator*(const mat_GF2& a, const vec_GF2& b); vec_GF2 operator*(const vec_GF2& a, const mat_GF2& b); // assignment operator notation: mat_GF2& operator+=(mat_GF2& x, const mat_GF2& a); mat_GF2& operator-=(mat_GF2& x, const mat_GF2& a); mat_GF2& operator*=(mat_GF2& x, const mat_GF2& a); mat_GF2& operator*=(mat_GF2& x, GF2 a); mat_GF2& operator*=(mat_GF2& x, long a); vec_GF2& operator*=(vec_GF2& x, const mat_GF2& a); ntl-6.2.1/doc/mat_GF2E.cpp.html000644 000765 000024 00000024656 12377144460 016403 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_GF2E.cpp.html

/**************************************************************************\

MODULE: mat_GF2E

SUMMARY:

Defines the class mat_GF2E.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_GF2E.h>


typedef Mat<GF2E> mat_GF2E; // backward compatibility


void add(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B);
// X = A + B

void sub(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B);
// X = A - B = A + B

void negate(mat_GF2E& X, const mat_GF2E& A);
// X = - A  = A

void mul(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B);
// X = A * B

void mul(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b);
// x = A * b

void mul(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B);
// x = a * B

void mul(mat_GF2E& X, const mat_GF2E& A, const GF2E& b);
void mul(mat_GF2E& X, const mat_GF2E& A, GF2 b);
void mul(mat_GF2E& X, const mat_GF2E& A, long b);
// X = A * b

void mul(mat_GF2E& X, const GF2E& a, const mat_GF2E& B);
void mul(mat_GF2E& X, GF2 a, const mat_GF2E& B);
void mul(mat_GF2E& X, long a, const mat_GF2E& B);
// X = a * B



void determinant(GF2E& d, const mat_GF2E& A);
GF2E determinant(const mat_GF2E& a);
// d = determinant(A)


void transpose(mat_GF2E& X, const mat_GF2E& A);
mat_GF2E transpose(const mat_GF2E& A);
// X = transpose of A

void solve(GF2E& d, vec_GF2E& X,
           const mat_GF2E& A, const vec_GF2E& b);
// A is an n x n matrix, b is a length n vector.  Computes d =
// determinant(A).  If d != 0, solves x*A = b.

void inv(GF2E& d, mat_GF2E& X, const mat_GF2E& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_GF2E& X, const mat_GF2E& A);
mat_GF2E sqr(const mat_GF2E& A);
// X = A*A   

void inv(mat_GF2E& X, const mat_GF2E& A);
mat_GF2E inv(const mat_GF2E& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_GF2E& X, const mat_GF2E& A, const ZZ& e);
mat_GF2E power(const mat_GF2E& A, const ZZ& e);

void power(mat_GF2E& X, const mat_GF2E& A, long e);
mat_GF2E power(const mat_GF2E& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).


void ident(mat_GF2E& X, long n);
mat_GF2E ident_mat_GF2E(long n);
// X = n x n identity matrix

long IsIdent(const mat_GF2E& A, long n);
// test if A is the n x n identity matrix

void diag(mat_GF2E& X, long n, const GF2E& d);
mat_GF2E diag(long n, const GF2E& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_GF2E& A, long n, const GF2E& d);
// test if X is an  n x n diagonal matrix with d on diagonal




long gauss(mat_GF2E& M);
long gauss(mat_GF2E& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_GF2E& X, const mat_GF2E& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_GF2E& X, const mat_GF2E& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.




// miscellaneous:

void clear(mat_GF2E& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_GF2E& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_GF2E operator+(const mat_GF2E& a, const mat_GF2E& b);
mat_GF2E operator-(const mat_GF2E& a, const mat_GF2E& b);
mat_GF2E operator*(const mat_GF2E& a, const mat_GF2E& b);

mat_GF2E operator-(const mat_GF2E& a);


// matrix/scalar multiplication:

mat_GF2E operator*(const mat_GF2E& a, const GF2E& b);
mat_GF2E operator*(const mat_GF2E& a, GF2 b);
mat_GF2E operator*(const mat_GF2E& a, long b);

mat_GF2E operator*(const GF2E& a, const mat_GF2E& b);
mat_GF2E operator*(GF2 a, const mat_GF2E& b);
mat_GF2E operator*(long a, const mat_GF2E& b);

// matrix/vector multiplication:

vec_GF2E operator*(const mat_GF2E& a, const vec_GF2E& b);

vec_GF2E operator*(const vec_GF2E& a, const mat_GF2E& b);


// assignment operator notation:

mat_GF2E& operator+=(mat_GF2E& x, const mat_GF2E& a);
mat_GF2E& operator-=(mat_GF2E& x, const mat_GF2E& a);
mat_GF2E& operator*=(mat_GF2E& x, const mat_GF2E& a);

mat_GF2E& operator*=(mat_GF2E& x, const GF2E& a);
mat_GF2E& operator*=(mat_GF2E& x, GF2 a);
mat_GF2E& operator*=(mat_GF2E& x, long a);

vec_GF2E& operator*=(vec_GF2E& x, const mat_GF2E& a);


ntl-6.2.1/doc/mat_GF2E.txt000644 000765 000024 00000010514 12377144460 015461 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_GF2E SUMMARY: Defines the class mat_GF2E. \**************************************************************************/ #include #include typedef Mat mat_GF2E; // backward compatibility void add(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); // X = A + B void sub(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); // X = A - B = A + B void negate(mat_GF2E& X, const mat_GF2E& A); // X = - A = A void mul(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); // X = A * B void mul(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b); // x = A * b void mul(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B); // x = a * B void mul(mat_GF2E& X, const mat_GF2E& A, const GF2E& b); void mul(mat_GF2E& X, const mat_GF2E& A, GF2 b); void mul(mat_GF2E& X, const mat_GF2E& A, long b); // X = A * b void mul(mat_GF2E& X, const GF2E& a, const mat_GF2E& B); void mul(mat_GF2E& X, GF2 a, const mat_GF2E& B); void mul(mat_GF2E& X, long a, const mat_GF2E& B); // X = a * B void determinant(GF2E& d, const mat_GF2E& A); GF2E determinant(const mat_GF2E& a); // d = determinant(A) void transpose(mat_GF2E& X, const mat_GF2E& A); mat_GF2E transpose(const mat_GF2E& A); // X = transpose of A void solve(GF2E& d, vec_GF2E& X, const mat_GF2E& A, const vec_GF2E& b); // A is an n x n matrix, b is a length n vector. Computes d = // determinant(A). If d != 0, solves x*A = b. void inv(GF2E& d, mat_GF2E& X, const mat_GF2E& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_GF2E& X, const mat_GF2E& A); mat_GF2E sqr(const mat_GF2E& A); // X = A*A void inv(mat_GF2E& X, const mat_GF2E& A); mat_GF2E inv(const mat_GF2E& A); // X = A^{-1}; error is raised if A is singular void power(mat_GF2E& X, const mat_GF2E& A, const ZZ& e); mat_GF2E power(const mat_GF2E& A, const ZZ& e); void power(mat_GF2E& X, const mat_GF2E& A, long e); mat_GF2E power(const mat_GF2E& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_GF2E& X, long n); mat_GF2E ident_mat_GF2E(long n); // X = n x n identity matrix long IsIdent(const mat_GF2E& A, long n); // test if A is the n x n identity matrix void diag(mat_GF2E& X, long n, const GF2E& d); mat_GF2E diag(long n, const GF2E& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_GF2E& A, long n, const GF2E& d); // test if X is an n x n diagonal matrix with d on diagonal long gauss(mat_GF2E& M); long gauss(mat_GF2E& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_GF2E& X, const mat_GF2E& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_GF2E& X, const mat_GF2E& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_GF2E& a); // x = 0 (dimension unchanged) long IsZero(const mat_GF2E& a); // test if a is the zero matrix (any dimension) // operator notation: mat_GF2E operator+(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator-(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator*(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator-(const mat_GF2E& a); // matrix/scalar multiplication: mat_GF2E operator*(const mat_GF2E& a, const GF2E& b); mat_GF2E operator*(const mat_GF2E& a, GF2 b); mat_GF2E operator*(const mat_GF2E& a, long b); mat_GF2E operator*(const GF2E& a, const mat_GF2E& b); mat_GF2E operator*(GF2 a, const mat_GF2E& b); mat_GF2E operator*(long a, const mat_GF2E& b); // matrix/vector multiplication: vec_GF2E operator*(const mat_GF2E& a, const vec_GF2E& b); vec_GF2E operator*(const vec_GF2E& a, const mat_GF2E& b); // assignment operator notation: mat_GF2E& operator+=(mat_GF2E& x, const mat_GF2E& a); mat_GF2E& operator-=(mat_GF2E& x, const mat_GF2E& a); mat_GF2E& operator*=(mat_GF2E& x, const mat_GF2E& a); mat_GF2E& operator*=(mat_GF2E& x, const GF2E& a); mat_GF2E& operator*=(mat_GF2E& x, GF2 a); mat_GF2E& operator*=(mat_GF2E& x, long a); vec_GF2E& operator*=(vec_GF2E& x, const mat_GF2E& a); ntl-6.2.1/doc/mat_RR.cpp.html000644 000765 000024 00000021311 12377144460 016224 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_RR.cpp.html

/**************************************************************************\

MODULE: mat_RR

SUMMARY:

Defines the class mat_RR.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_RR.h>

typedef Mat<RR> mat_RR; // backward compatibility

void add(mat_RR& X, const mat_RR& A, const mat_RR& B);
// X = A + B

void sub(mat_RR& X, const mat_RR& A, const mat_RR& B);
// X = A - B

void negate(mat_RR& X, const mat_RR& A);
// X = - A

void mul(mat_RR& X, const mat_RR& A, const mat_RR& B);
// X = A * B

void mul(vec_RR& x, const mat_RR& A, const vec_RR& b);
// x = A * b

void mul(vec_RR& x, const vec_RR& a, const mat_RR& B);
// x = a * B

void mul(mat_RR& X, const mat_RR& A, const RR& b);
void mul(mat_RR& X, const mat_RR& A, double b);
// X = A * b

void mul(mat_RR& X, const RR& a, const mat_RR& B);
void mul(mat_RR& X, double a, const mat_RR& B);
// X = a * B


void determinant(RR& d, const mat_RR& A);
RR determinant(const mat_RR& A);
// d = determinant(A)


void transpose(mat_RR& X, const mat_RR& A);
mat_RR transpose(const mat_RR& A);
// X = transpose of A

void solve(RR& d, vec_RR& X,
           const mat_RR& A, const vec_RR& b);
// A is an n x n matrix, b is a length n vector.  Computes d =
// determinant(A).  If d != 0, solves x*A = b.

void inv(RR& d, mat_RR& X, const mat_RR& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_RR& X, const mat_RR& A);
mat_RR sqr(const mat_RR& A);
// X = A*A

void inv(mat_RR& X, const mat_RR& A);
mat_RR inv(const mat_RR& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_RR& X, const mat_RR& A, const ZZ& e);
mat_RR power(const mat_RR& A, const ZZ& e);

void power(mat_RR& X, const mat_RR& A, long e);
mat_RR power(const mat_RR& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

void ident(mat_RR& X, long n);
mat_RR ident_mat_RR(long n);
// X = n x n identity matrix

long IsIdent(const mat_RR& A, long n);
// test if A is the n x n identity matrix

void diag(mat_RR& X, long n, const RR& d);
mat_RR diag(long n, const RR& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_RR& A, long n, const RR& d);
// test if X is an  n x n diagonal matrix with d on diagonal





// miscellaneous:

void clear(mat_RR& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_RR& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_RR operator+(const mat_RR& a, const mat_RR& b);
mat_RR operator-(const mat_RR& a, const mat_RR& b);
mat_RR operator*(const mat_RR& a, const mat_RR& b);

mat_RR operator-(const mat_RR& a);


// matrix/scalar multiplication:

mat_RR operator*(const mat_RR& a, const RR& b);
mat_RR operator*(const mat_RR& a, double b);

mat_RR operator*(const RR& a, const mat_RR& b);
mat_RR operator*(double a, const mat_RR& b);


// matrix/vector multiplication:

vec_RR operator*(const mat_RR& a, const vec_RR& b);

vec_RR operator*(const vec_RR& a, const mat_RR& b);


// assignment operator notation:

mat_RR& operator+=(mat_RR& x, const mat_RR& a);
mat_RR& operator-=(mat_RR& x, const mat_RR& a);
mat_RR& operator*=(mat_RR& x, const mat_RR& a);

mat_RR& operator*=(mat_RR& x, const RR& a);
mat_RR& operator*=(mat_RR& x, double a);

vec_RR& operator*=(vec_RR& x, const mat_RR& a);



ntl-6.2.1/doc/mat_RR.txt000644 000765 000024 00000006473 12377144460 015332 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_RR SUMMARY: Defines the class mat_RR. \**************************************************************************/ #include #include typedef Mat mat_RR; // backward compatibility void add(mat_RR& X, const mat_RR& A, const mat_RR& B); // X = A + B void sub(mat_RR& X, const mat_RR& A, const mat_RR& B); // X = A - B void negate(mat_RR& X, const mat_RR& A); // X = - A void mul(mat_RR& X, const mat_RR& A, const mat_RR& B); // X = A * B void mul(vec_RR& x, const mat_RR& A, const vec_RR& b); // x = A * b void mul(vec_RR& x, const vec_RR& a, const mat_RR& B); // x = a * B void mul(mat_RR& X, const mat_RR& A, const RR& b); void mul(mat_RR& X, const mat_RR& A, double b); // X = A * b void mul(mat_RR& X, const RR& a, const mat_RR& B); void mul(mat_RR& X, double a, const mat_RR& B); // X = a * B void determinant(RR& d, const mat_RR& A); RR determinant(const mat_RR& A); // d = determinant(A) void transpose(mat_RR& X, const mat_RR& A); mat_RR transpose(const mat_RR& A); // X = transpose of A void solve(RR& d, vec_RR& X, const mat_RR& A, const vec_RR& b); // A is an n x n matrix, b is a length n vector. Computes d = // determinant(A). If d != 0, solves x*A = b. void inv(RR& d, mat_RR& X, const mat_RR& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_RR& X, const mat_RR& A); mat_RR sqr(const mat_RR& A); // X = A*A void inv(mat_RR& X, const mat_RR& A); mat_RR inv(const mat_RR& A); // X = A^{-1}; error is raised if A is singular void power(mat_RR& X, const mat_RR& A, const ZZ& e); mat_RR power(const mat_RR& A, const ZZ& e); void power(mat_RR& X, const mat_RR& A, long e); mat_RR power(const mat_RR& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_RR& X, long n); mat_RR ident_mat_RR(long n); // X = n x n identity matrix long IsIdent(const mat_RR& A, long n); // test if A is the n x n identity matrix void diag(mat_RR& X, long n, const RR& d); mat_RR diag(long n, const RR& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_RR& A, long n, const RR& d); // test if X is an n x n diagonal matrix with d on diagonal // miscellaneous: void clear(mat_RR& a); // x = 0 (dimension unchanged) long IsZero(const mat_RR& a); // test if a is the zero matrix (any dimension) // operator notation: mat_RR operator+(const mat_RR& a, const mat_RR& b); mat_RR operator-(const mat_RR& a, const mat_RR& b); mat_RR operator*(const mat_RR& a, const mat_RR& b); mat_RR operator-(const mat_RR& a); // matrix/scalar multiplication: mat_RR operator*(const mat_RR& a, const RR& b); mat_RR operator*(const mat_RR& a, double b); mat_RR operator*(const RR& a, const mat_RR& b); mat_RR operator*(double a, const mat_RR& b); // matrix/vector multiplication: vec_RR operator*(const mat_RR& a, const vec_RR& b); vec_RR operator*(const vec_RR& a, const mat_RR& b); // assignment operator notation: mat_RR& operator+=(mat_RR& x, const mat_RR& a); mat_RR& operator-=(mat_RR& x, const mat_RR& a); mat_RR& operator*=(mat_RR& x, const mat_RR& a); mat_RR& operator*=(mat_RR& x, const RR& a); mat_RR& operator*=(mat_RR& x, double a); vec_RR& operator*=(vec_RR& x, const mat_RR& a); ntl-6.2.1/doc/mat_ZZ.cpp.html000644 000765 000024 00000026145 12377144460 016256 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_ZZ.cpp.html

/**************************************************************************\

MODULE: mat_ZZ

SUMMARY:

Defines the class mat_ZZ.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_ZZ.h>

typedef Mat<ZZ> mat_ZZ; // backward compatibility

void add(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B);
// X = A + B

void sub(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B);
// X = A - B

void negate(mat_ZZ& X, const mat_ZZ& A);
// X = - A

void mul(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B);
// X = A * B

void mul(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b);
// x = A * b

void mul(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B);
// x = a * B

void mul(mat_ZZ& X, const mat_ZZ& A, const ZZ& b);
void mul(mat_ZZ& X, const mat_ZZ& A, long b);
// X = A * b

void mul(mat_ZZ& X, const ZZ& a, const mat_ZZ& B);
void mul(mat_ZZ& X, long a, const mat_ZZ& B);
// X = a * B



void determinant(ZZ& d, const mat_ZZ& A, long deterministic=0);
ZZ determinant(const mat_ZZ& a, long deterministic=0);
// d = determinant(A).  If !deterministic, a randomized strategy may
// be used that errs with probability at most 2^{-80}.



void solve(ZZ& d, vec_ZZ& x,
           const mat_ZZ& A, const vec_ZZ& b,
           long deterministic=0)
// computes d = determinant(A) and solves x*A = b*d if d != 0; A must
// be a square matrix and have compatible dimensions with b.  If
// !deterministic, the computation of d may use a randomized strategy
// that errs with probability 2^{-80}.



void solve1(ZZ& d, vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b);
// A must be a square matrix.
// If A is singular, this routine sets d = 0 and returns.
// Otherwise, it computes d, x such that x*A == b*d, 
// such that d > 0 and minimal.
// Note that d is a positive divisor of the determinant,
// and is not in general equal to the determinant.
// The routine is deterministic, and uses a Hensel lifting strategy.

// For backward compatability, there is also a routine called
// HenselSolve1 that simply calls solve1.


void inv(ZZ& d, mat_ZZ& X, const mat_ZZ& A, long deterministic=0);
// computes d = determinant(A) and solves X*A = I*d if d != 0; A must
// be a square matrix.  If !deterministic, the computation of d may
// use a randomized strategy that errs with probability 2^{-80}.


// NOTE:  See LLL.txt for routines that compute the kernel and
// image of an integer matrix.

// NOTE: See HNF.txt for a routine that computes Hermite Normal Forms.

void sqr(mat_ZZ& X, const mat_ZZ& A);
mat_ZZ sqr(const mat_ZZ& A);
// X = A*A   

void inv(mat_ZZ& X, const mat_ZZ& A);
mat_ZZ inv(const mat_ZZ& A);
// X = A^{-1}; error is raised if |det(A)| != 1.

void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e);
mat_ZZ power(const mat_ZZ& A, const ZZ& e);

void power(mat_ZZ& X, const mat_ZZ& A, long e);
mat_ZZ power(const mat_ZZ& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).



void ident(mat_ZZ& X, long n);
mat_ZZ ident_mat_ZZ(long n);
// X = n x n identity matrix

long IsIdent(const mat_ZZ& A, long n);
// test if A is the n x n identity matrix

void diag(mat_ZZ& X, long n, const ZZ& d);
mat_ZZ diag(long n, const ZZ& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_ZZ& A, long n, const ZZ& d);
// test if X is an  n x n diagonal matrix with d on diagonal


void transpose(mat_ZZ& X, const mat_ZZ& A);
mat_ZZ transpose(const mat_ZZ& A);
// X = transpose of A


long CRT(mat_ZZ& a, ZZ& prod, const mat_zz_p& A);
// Incremental Chinese Remaindering: If p is the current zz_p modulus with
// (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p,
// with coefficients in the interval (-p*prod/2, p*prod/2]; 
// Sets a := a', prod := p*prod, and returns 1 if a's value changed.



// miscellaneous:

void clear(mat_ZZ& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_ZZ& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_ZZ operator+(const mat_ZZ& a, const mat_ZZ& b);
mat_ZZ operator-(const mat_ZZ& a, const mat_ZZ& b);
mat_ZZ operator*(const mat_ZZ& a, const mat_ZZ& b);

mat_ZZ operator-(const mat_ZZ& a);


// matrix/scalar multiplication:

mat_ZZ operator*(const mat_ZZ& a, const ZZ& b);
mat_ZZ operator*(const mat_ZZ& a, long b);

mat_ZZ operator*(const ZZ& a, const mat_ZZ& b);
mat_ZZ operator*(long a, const mat_ZZ& b);

// matrix/vector multiplication:

vec_ZZ operator*(const mat_ZZ& a, const vec_ZZ& b);

vec_ZZ operator*(const vec_ZZ& a, const mat_ZZ& b);



// assignment operator notation:

mat_ZZ& operator+=(mat_ZZ& x, const mat_ZZ& a);
mat_ZZ& operator-=(mat_ZZ& x, const mat_ZZ& a);
mat_ZZ& operator*=(mat_ZZ& x, const mat_ZZ& a);

mat_ZZ& operator*=(mat_ZZ& x, const ZZ& a);
mat_ZZ& operator*=(mat_ZZ& x, long a);

vec_ZZ& operator*=(vec_ZZ& x, const mat_ZZ& a);


ntl-6.2.1/doc/mat_ZZ.txt000644 000765 000024 00000011366 12377144460 015347 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_ZZ SUMMARY: Defines the class mat_ZZ. \**************************************************************************/ #include #include typedef Mat mat_ZZ; // backward compatibility void add(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); // X = A + B void sub(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); // X = A - B void negate(mat_ZZ& X, const mat_ZZ& A); // X = - A void mul(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); // X = A * B void mul(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b); // x = A * b void mul(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B); // x = a * B void mul(mat_ZZ& X, const mat_ZZ& A, const ZZ& b); void mul(mat_ZZ& X, const mat_ZZ& A, long b); // X = A * b void mul(mat_ZZ& X, const ZZ& a, const mat_ZZ& B); void mul(mat_ZZ& X, long a, const mat_ZZ& B); // X = a * B void determinant(ZZ& d, const mat_ZZ& A, long deterministic=0); ZZ determinant(const mat_ZZ& a, long deterministic=0); // d = determinant(A). If !deterministic, a randomized strategy may // be used that errs with probability at most 2^{-80}. void solve(ZZ& d, vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b, long deterministic=0) // computes d = determinant(A) and solves x*A = b*d if d != 0; A must // be a square matrix and have compatible dimensions with b. If // !deterministic, the computation of d may use a randomized strategy // that errs with probability 2^{-80}. void solve1(ZZ& d, vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b); // A must be a square matrix. // If A is singular, this routine sets d = 0 and returns. // Otherwise, it computes d, x such that x*A == b*d, // such that d > 0 and minimal. // Note that d is a positive divisor of the determinant, // and is not in general equal to the determinant. // The routine is deterministic, and uses a Hensel lifting strategy. // For backward compatability, there is also a routine called // HenselSolve1 that simply calls solve1. void inv(ZZ& d, mat_ZZ& X, const mat_ZZ& A, long deterministic=0); // computes d = determinant(A) and solves X*A = I*d if d != 0; A must // be a square matrix. If !deterministic, the computation of d may // use a randomized strategy that errs with probability 2^{-80}. // NOTE: See LLL.txt for routines that compute the kernel and // image of an integer matrix. // NOTE: See HNF.txt for a routine that computes Hermite Normal Forms. void sqr(mat_ZZ& X, const mat_ZZ& A); mat_ZZ sqr(const mat_ZZ& A); // X = A*A void inv(mat_ZZ& X, const mat_ZZ& A); mat_ZZ inv(const mat_ZZ& A); // X = A^{-1}; error is raised if |det(A)| != 1. void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e); mat_ZZ power(const mat_ZZ& A, const ZZ& e); void power(mat_ZZ& X, const mat_ZZ& A, long e); mat_ZZ power(const mat_ZZ& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_ZZ& X, long n); mat_ZZ ident_mat_ZZ(long n); // X = n x n identity matrix long IsIdent(const mat_ZZ& A, long n); // test if A is the n x n identity matrix void diag(mat_ZZ& X, long n, const ZZ& d); mat_ZZ diag(long n, const ZZ& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_ZZ& A, long n, const ZZ& d); // test if X is an n x n diagonal matrix with d on diagonal void transpose(mat_ZZ& X, const mat_ZZ& A); mat_ZZ transpose(const mat_ZZ& A); // X = transpose of A long CRT(mat_ZZ& a, ZZ& prod, const mat_zz_p& A); // Incremental Chinese Remaindering: If p is the current zz_p modulus with // (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p, // with coefficients in the interval (-p*prod/2, p*prod/2]; // Sets a := a', prod := p*prod, and returns 1 if a's value changed. // miscellaneous: void clear(mat_ZZ& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ operator+(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator-(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator*(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator-(const mat_ZZ& a); // matrix/scalar multiplication: mat_ZZ operator*(const mat_ZZ& a, const ZZ& b); mat_ZZ operator*(const mat_ZZ& a, long b); mat_ZZ operator*(const ZZ& a, const mat_ZZ& b); mat_ZZ operator*(long a, const mat_ZZ& b); // matrix/vector multiplication: vec_ZZ operator*(const mat_ZZ& a, const vec_ZZ& b); vec_ZZ operator*(const vec_ZZ& a, const mat_ZZ& b); // assignment operator notation: mat_ZZ& operator+=(mat_ZZ& x, const mat_ZZ& a); mat_ZZ& operator-=(mat_ZZ& x, const mat_ZZ& a); mat_ZZ& operator*=(mat_ZZ& x, const mat_ZZ& a); mat_ZZ& operator*=(mat_ZZ& x, const ZZ& a); mat_ZZ& operator*=(mat_ZZ& x, long a); vec_ZZ& operator*=(vec_ZZ& x, const mat_ZZ& a); ntl-6.2.1/doc/mat_ZZ_p.cpp.html000644 000765 000024 00000023626 12377144460 016576 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_ZZ_p.cpp.html

/**************************************************************************\

MODULE: mat_ZZ_p

SUMMARY:

Defines the class mat_ZZ_p.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_ZZ_p.h>


typedef mat_ZZ_p mat_ZZ_p; // backward compatibility

void add(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B);
// X = A + B

void sub(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B);
// X = A - B

void negate(mat_ZZ_p& X, const mat_ZZ_p& A);
// X = - A

void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B);
// X = A * B

void mul(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b);
// x = A * b

void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B);
// x = a * B

void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ_p& b);
void mul(mat_ZZ_p& X, const mat_ZZ_p& A, long b);
// X = A * b

void mul(mat_ZZ_p& X, const ZZ_p& a, const mat_ZZ_p& B);
void mul(mat_ZZ_p& X, long a, const mat_ZZ_p& B);
// X = a * B


void determinant(ZZ_p& d, const mat_ZZ_p& A);
ZZ_p determinant(const mat_ZZ_p& a);
// d = determinant(A)


void transpose(mat_ZZ_p& X, const mat_ZZ_p& A);
mat_ZZ_p transpose(const mat_ZZ_p& A);
// X = transpose of A

void solve(ZZ_p& d, vec_ZZ_p& X,
           const mat_ZZ_p& A, const vec_ZZ_p& b);
// A is an n x n matrix, b is a length n vector.  Computes d =
// determinant(A).  If d != 0, solves x*A = b.

void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_ZZ_p& X, const mat_ZZ_p& A);
mat_ZZ_p sqr(const mat_ZZ_p& A);
// X = A*A   

void inv(mat_ZZ_p& X, const mat_ZZ_p& A);
mat_ZZ_p inv(const mat_ZZ_p& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ& e);
mat_ZZ_p power(const mat_ZZ_p& A, const ZZ& e);

void power(mat_ZZ_p& X, const mat_ZZ_p& A, long e);
mat_ZZ_p power(const mat_ZZ_p& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

void ident(mat_ZZ_p& X, long n);
mat_ZZ_p ident_mat_ZZ_p(long n);
// X = n x n identity matrix

long IsIdent(const mat_ZZ_p& A, long n);
// test if A is the n x n identity matrix

void diag(mat_ZZ_p& X, long n, const ZZ_p& d);
mat_ZZ_p diag(long n, const ZZ_p& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_ZZ_p& A, long n, const ZZ_p& d);
// test if X is an  n x n diagonal matrix with d on diagonal




long gauss(mat_ZZ_p& M);
long gauss(mat_ZZ_p& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_ZZ_p& X, const mat_ZZ_p& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_ZZ_p& X, const mat_ZZ_p& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.



// miscellaneous:

void clear(mat_ZZ_p& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_ZZ_p& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_ZZ_p operator+(const mat_ZZ_p& a, const mat_ZZ_p& b);
mat_ZZ_p operator-(const mat_ZZ_p& a, const mat_ZZ_p& b);
mat_ZZ_p operator*(const mat_ZZ_p& a, const mat_ZZ_p& b);

mat_ZZ_p operator-(const mat_ZZ_p& a);


// matrix/scalar multiplication:

mat_ZZ_p operator*(const mat_ZZ_p& a, const ZZ_p& b);
mat_ZZ_p operator*(const mat_ZZ_p& a, long b);

mat_ZZ_p operator*(const ZZ_p& a, const mat_ZZ_p& b);
mat_ZZ_p operator*(long a, const mat_ZZ_p& b);

// matrix/vector multiplication:

vec_ZZ_p operator*(const mat_ZZ_p& a, const vec_ZZ_p& b);

vec_ZZ_p operator*(const vec_ZZ_p& a, const mat_ZZ_p& b);


// assignment operator notation:

mat_ZZ_p& operator+=(mat_ZZ_p& x, const mat_ZZ_p& a);
mat_ZZ_p& operator-=(mat_ZZ_p& x, const mat_ZZ_p& a);
mat_ZZ_p& operator*=(mat_ZZ_p& x, const mat_ZZ_p& a);

mat_ZZ_p& operator*=(mat_ZZ_p& x, const ZZ_p& a);
mat_ZZ_p& operator*=(mat_ZZ_p& x, long a);

vec_ZZ_p& operator*=(vec_ZZ_p& x, const mat_ZZ_p& a);



ntl-6.2.1/doc/mat_ZZ_p.txt000644 000765 000024 00000010124 12377144460 015655 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_ZZ_p SUMMARY: Defines the class mat_ZZ_p. \**************************************************************************/ #include #include typedef mat_ZZ_p mat_ZZ_p; // backward compatibility void add(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); // X = A + B void sub(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); // X = A - B void negate(mat_ZZ_p& X, const mat_ZZ_p& A); // X = - A void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); // X = A * B void mul(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b); // x = A * b void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B); // x = a * B void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ_p& b); void mul(mat_ZZ_p& X, const mat_ZZ_p& A, long b); // X = A * b void mul(mat_ZZ_p& X, const ZZ_p& a, const mat_ZZ_p& B); void mul(mat_ZZ_p& X, long a, const mat_ZZ_p& B); // X = a * B void determinant(ZZ_p& d, const mat_ZZ_p& A); ZZ_p determinant(const mat_ZZ_p& a); // d = determinant(A) void transpose(mat_ZZ_p& X, const mat_ZZ_p& A); mat_ZZ_p transpose(const mat_ZZ_p& A); // X = transpose of A void solve(ZZ_p& d, vec_ZZ_p& X, const mat_ZZ_p& A, const vec_ZZ_p& b); // A is an n x n matrix, b is a length n vector. Computes d = // determinant(A). If d != 0, solves x*A = b. void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_ZZ_p& X, const mat_ZZ_p& A); mat_ZZ_p sqr(const mat_ZZ_p& A); // X = A*A void inv(mat_ZZ_p& X, const mat_ZZ_p& A); mat_ZZ_p inv(const mat_ZZ_p& A); // X = A^{-1}; error is raised if A is singular void power(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ& e); mat_ZZ_p power(const mat_ZZ_p& A, const ZZ& e); void power(mat_ZZ_p& X, const mat_ZZ_p& A, long e); mat_ZZ_p power(const mat_ZZ_p& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_ZZ_p& X, long n); mat_ZZ_p ident_mat_ZZ_p(long n); // X = n x n identity matrix long IsIdent(const mat_ZZ_p& A, long n); // test if A is the n x n identity matrix void diag(mat_ZZ_p& X, long n, const ZZ_p& d); mat_ZZ_p diag(long n, const ZZ_p& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_ZZ_p& A, long n, const ZZ_p& d); // test if X is an n x n diagonal matrix with d on diagonal long gauss(mat_ZZ_p& M); long gauss(mat_ZZ_p& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_ZZ_p& X, const mat_ZZ_p& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_ZZ_p& X, const mat_ZZ_p& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_ZZ_p& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ_p& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ_p operator+(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator-(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator*(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator-(const mat_ZZ_p& a); // matrix/scalar multiplication: mat_ZZ_p operator*(const mat_ZZ_p& a, const ZZ_p& b); mat_ZZ_p operator*(const mat_ZZ_p& a, long b); mat_ZZ_p operator*(const ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator*(long a, const mat_ZZ_p& b); // matrix/vector multiplication: vec_ZZ_p operator*(const mat_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator*(const vec_ZZ_p& a, const mat_ZZ_p& b); // assignment operator notation: mat_ZZ_p& operator+=(mat_ZZ_p& x, const mat_ZZ_p& a); mat_ZZ_p& operator-=(mat_ZZ_p& x, const mat_ZZ_p& a); mat_ZZ_p& operator*=(mat_ZZ_p& x, const mat_ZZ_p& a); mat_ZZ_p& operator*=(mat_ZZ_p& x, const ZZ_p& a); mat_ZZ_p& operator*=(mat_ZZ_p& x, long a); vec_ZZ_p& operator*=(vec_ZZ_p& x, const mat_ZZ_p& a); ntl-6.2.1/doc/mat_ZZ_pE.cpp.html000644 000765 000024 00000025344 12377144460 016702 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_ZZ_pE.cpp.html

/**************************************************************************\

MODULE: mat_ZZ_pE

SUMMARY:

Defines the class mat_ZZ_pE.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_ZZ_pE.h>


typedef Mat<ZZ_pE> mat_ZZ_pE; // backward compatibility

void add(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B);
// X = A + B

void sub(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B);
// X = A - B

void negate(mat_ZZ_pE& X, const mat_ZZ_pE& A);
// X = - A

void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B);
// X = A * B

void mul(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b);
// x = A * b

void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B);
// x = a * B

void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_pE& b);
void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_p& b);
void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, long b);
// X = A * b

void mul(mat_ZZ_pE& X, const ZZ_pE& a, const mat_ZZ_pE& B);
void mul(mat_ZZ_pE& X, const ZZ_p& a, const mat_ZZ_pE& B);
void mul(mat_ZZ_pE& X, long a, const mat_ZZ_pE& B);
// X = a * B


void determinant(ZZ_pE& d, const mat_ZZ_pE& A);
ZZ_pE determinant(const mat_ZZ_pE& a);
// d = determinant(A)


void transpose(mat_ZZ_pE& X, const mat_ZZ_pE& A);
mat_ZZ_pE transpose(const mat_ZZ_pE& A);
// X = transpose of A

void solve(ZZ_pE& d, vec_ZZ_pE& X,
           const mat_ZZ_pE& A, const vec_ZZ_pE& b);
// A is an n x n matrix, b is a length n vector.  Computes d =
// determinant(A).  If d != 0, solves x*A = b.

void inv(ZZ_pE& d, mat_ZZ_pE& X, const mat_ZZ_pE& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_ZZ_pE& X, const mat_ZZ_pE& A);
mat_ZZ_pE sqr(const mat_ZZ_pE& A);
// X = A*A   

void inv(mat_ZZ_pE& X, const mat_ZZ_pE& A);
mat_ZZ_pE inv(const mat_ZZ_pE& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ& e);
mat_ZZ_pE power(const mat_ZZ_pE& A, const ZZ& e);

void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, long e);
mat_ZZ_pE power(const mat_ZZ_pE& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

void ident(mat_ZZ_pE& X, long n);
mat_ZZ_pE ident_mat_ZZ_pE(long n);
// X = n x n identity matrix

long IsIdent(const mat_ZZ_pE& A, long n);
// test if A is the n x n identity matrix

void diag(mat_ZZ_pE& X, long n, const ZZ_pE& d);
mat_ZZ_pE diag(long n, const ZZ_pE& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_ZZ_pE& A, long n, const ZZ_pE& d);
// test if X is an  n x n diagonal matrix with d on diagonal




long gauss(mat_ZZ_pE& M);
long gauss(mat_ZZ_pE& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_ZZ_pE& X, const mat_ZZ_pE& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_ZZ_pE& X, const mat_ZZ_pE& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.



// miscellaneous:

void clear(mat_ZZ_pE& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_ZZ_pE& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_ZZ_pE operator+(const mat_ZZ_pE& a, const mat_ZZ_pE& b);
mat_ZZ_pE operator-(const mat_ZZ_pE& a, const mat_ZZ_pE& b);
mat_ZZ_pE operator*(const mat_ZZ_pE& a, const mat_ZZ_pE& b);

mat_ZZ_pE operator-(const mat_ZZ_pE& a);


// matrix/scalar multiplication:

mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_pE& b);
mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_p& b);
mat_ZZ_pE operator*(const mat_ZZ_pE& a, long b);

mat_ZZ_pE operator*(const ZZ_pE& a, const mat_ZZ_pE& b);
mat_ZZ_pE operator*(const ZZ_p& a, const mat_ZZ_pE& b);
mat_ZZ_pE operator*(long a, const mat_ZZ_pE& b);

// matrix/vector multiplication:

vec_ZZ_pE operator*(const mat_ZZ_pE& a, const vec_ZZ_pE& b);

vec_ZZ_pE operator*(const vec_ZZ_pE& a, const mat_ZZ_pE& b);


// assignment operator notation:

mat_ZZ_pE& operator+=(mat_ZZ_pE& x, const mat_ZZ_pE& a);
mat_ZZ_pE& operator-=(mat_ZZ_pE& x, const mat_ZZ_pE& a);
mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const mat_ZZ_pE& a);

mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_pE& a);
mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_p& a);
mat_ZZ_pE& operator*=(mat_ZZ_pE& x, long a);

vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const mat_ZZ_pE& a);



ntl-6.2.1/doc/mat_ZZ_pE.txt000644 000765 000024 00000010754 12377144460 015773 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_ZZ_pE SUMMARY: Defines the class mat_ZZ_pE. \**************************************************************************/ #include #include typedef Mat mat_ZZ_pE; // backward compatibility void add(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); // X = A + B void sub(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); // X = A - B void negate(mat_ZZ_pE& X, const mat_ZZ_pE& A); // X = - A void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); // X = A * B void mul(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b); // x = A * b void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B); // x = a * B void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_pE& b); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_p& b); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, long b); // X = A * b void mul(mat_ZZ_pE& X, const ZZ_pE& a, const mat_ZZ_pE& B); void mul(mat_ZZ_pE& X, const ZZ_p& a, const mat_ZZ_pE& B); void mul(mat_ZZ_pE& X, long a, const mat_ZZ_pE& B); // X = a * B void determinant(ZZ_pE& d, const mat_ZZ_pE& A); ZZ_pE determinant(const mat_ZZ_pE& a); // d = determinant(A) void transpose(mat_ZZ_pE& X, const mat_ZZ_pE& A); mat_ZZ_pE transpose(const mat_ZZ_pE& A); // X = transpose of A void solve(ZZ_pE& d, vec_ZZ_pE& X, const mat_ZZ_pE& A, const vec_ZZ_pE& b); // A is an n x n matrix, b is a length n vector. Computes d = // determinant(A). If d != 0, solves x*A = b. void inv(ZZ_pE& d, mat_ZZ_pE& X, const mat_ZZ_pE& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_ZZ_pE& X, const mat_ZZ_pE& A); mat_ZZ_pE sqr(const mat_ZZ_pE& A); // X = A*A void inv(mat_ZZ_pE& X, const mat_ZZ_pE& A); mat_ZZ_pE inv(const mat_ZZ_pE& A); // X = A^{-1}; error is raised if A is singular void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ& e); mat_ZZ_pE power(const mat_ZZ_pE& A, const ZZ& e); void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, long e); mat_ZZ_pE power(const mat_ZZ_pE& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_ZZ_pE& X, long n); mat_ZZ_pE ident_mat_ZZ_pE(long n); // X = n x n identity matrix long IsIdent(const mat_ZZ_pE& A, long n); // test if A is the n x n identity matrix void diag(mat_ZZ_pE& X, long n, const ZZ_pE& d); mat_ZZ_pE diag(long n, const ZZ_pE& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_ZZ_pE& A, long n, const ZZ_pE& d); // test if X is an n x n diagonal matrix with d on diagonal long gauss(mat_ZZ_pE& M); long gauss(mat_ZZ_pE& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_ZZ_pE& X, const mat_ZZ_pE& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_ZZ_pE& X, const mat_ZZ_pE& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_ZZ_pE& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ_pE& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ_pE operator+(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator-(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator*(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator-(const mat_ZZ_pE& a); // matrix/scalar multiplication: mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_pE& b); mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_p& b); mat_ZZ_pE operator*(const mat_ZZ_pE& a, long b); mat_ZZ_pE operator*(const ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator*(const ZZ_p& a, const mat_ZZ_pE& b); mat_ZZ_pE operator*(long a, const mat_ZZ_pE& b); // matrix/vector multiplication: vec_ZZ_pE operator*(const mat_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator*(const vec_ZZ_pE& a, const mat_ZZ_pE& b); // assignment operator notation: mat_ZZ_pE& operator+=(mat_ZZ_pE& x, const mat_ZZ_pE& a); mat_ZZ_pE& operator-=(mat_ZZ_pE& x, const mat_ZZ_pE& a); mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const mat_ZZ_pE& a); mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_pE& a); mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_p& a); mat_ZZ_pE& operator*=(mat_ZZ_pE& x, long a); vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const mat_ZZ_pE& a); ntl-6.2.1/doc/mat_lzz_p.cpp.html000644 000765 000024 00000022744 12377144460 017052 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_lzz_p.cpp.html

/**************************************************************************\

MODULE: mat_zz_p

SUMMARY:

Defines the class mat_zz_p.

\**************************************************************************/


#include <NTL/matrix.h>
#include "vec_vec_zz_p.h"


typedef Mat<zz_p> mat_zz_p; // backward compatibility

void add(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B);
// X = A + B

void sub(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B);
// X = A - B

void mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B);
// X = A * B

void mul(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b);
// x = A * b

void mul(vec_zz_p& x, const vec_zz_p& a, const mat_zz_p& B);
// x = a * B

void mul(mat_zz_p& X, const mat_zz_p& A, zz_p b);
void mul(mat_zz_p& X, const mat_zz_p& A, long b);
// X = A * b

void mul(mat_zz_p& X, zz_p a, const mat_zz_p& B);
void mul(mat_zz_p& X, long a, const mat_zz_p& B);
// X = a * B


void determinant(zz_p& d, const mat_zz_p& A);
zz_p determinant(const mat_zz_p& a);
// d = determinant(A)


void transpose(mat_zz_p& X, const mat_zz_p& A);
mat_zz_p transpose(const mat_zz_p& A);
// X = transpose of A

void solve(zz_p& d, vec_zz_p& X,
           const mat_zz_p& A, const vec_zz_p& b);
// A is an n x n matrix, b is a length n vector.  Computes d =
// determinant(A).  If d != 0, solves x*A = b.

void inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_zz_p& X, const mat_zz_p& A);
mat_zz_p sqr(const mat_zz_p& A);
// X = A*A   

void inv(mat_zz_p& X, const mat_zz_p& A);
mat_zz_p inv(const mat_zz_p& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e);
mat_zz_p power(const mat_zz_p& A, const ZZ& e);

void power(mat_zz_p& X, const mat_zz_p& A, long e);
mat_zz_p power(const mat_zz_p& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).


void ident(mat_zz_p& X, long n);
mat_zz_p ident_mat_zz_p(long n);
// X = n x n identity matrix

long IsIdent(const mat_zz_p& A, long n);
// test if A is the n x n identity matrix

void diag(mat_zz_p& X, long n, zz_p d);
mat_zz_p diag(long n, zz_p d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_zz_p& A, long n, zz_p d);
// test if X is an  n x n diagonal matrix with d on diagonal



long gauss(mat_zz_p& M);
long gauss(mat_zz_p& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_zz_p& X, const mat_zz_p& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_zz_p& X, const mat_zz_p& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.



// miscellaneous:

void clear(mat_zz_p& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_zz_p& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_zz_p operator+(const mat_zz_p& a, const mat_zz_p& b);
mat_zz_p operator-(const mat_zz_p& a, const mat_zz_p& b);
mat_zz_p operator*(const mat_zz_p& a, const mat_zz_p& b);

mat_zz_p operator-(const mat_zz_p& a);


// matrix/scalar multiplication:

mat_zz_p operator*(const mat_zz_p& a, zz_p b);
mat_zz_p operator*(const mat_zz_p& a, long b);

mat_zz_p operator*(zz_p a, const mat_zz_p& b);
mat_zz_p operator*(long a, const mat_zz_p& b);


// matrix/vector multiplication:

vec_zz_p operator*(const mat_zz_p& a, const vec_zz_p& b);

vec_zz_p operator*(const vec_zz_p& a, const mat_zz_p& b);


// assignment operator notation:

mat_zz_p& operator+=(mat_zz_p& x, const mat_zz_p& a);
mat_zz_p& operator-=(mat_zz_p& x, const mat_zz_p& a);
mat_zz_p& operator*=(mat_zz_p& x, const mat_zz_p& a);

mat_zz_p& operator*=(mat_zz_p& x, zz_p a);
mat_zz_p& operator*=(mat_zz_p& x, long a);

vec_zz_p& operator*=(vec_zz_p& x, const mat_zz_p& a);


ntl-6.2.1/doc/mat_lzz_p.txt000644 000765 000024 00000007737 12377144460 016151 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_zz_p SUMMARY: Defines the class mat_zz_p. \**************************************************************************/ #include #include "vec_vec_zz_p.h" typedef Mat mat_zz_p; // backward compatibility void add(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); // X = A + B void sub(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); // X = A - B void mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); // X = A * B void mul(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b); // x = A * b void mul(vec_zz_p& x, const vec_zz_p& a, const mat_zz_p& B); // x = a * B void mul(mat_zz_p& X, const mat_zz_p& A, zz_p b); void mul(mat_zz_p& X, const mat_zz_p& A, long b); // X = A * b void mul(mat_zz_p& X, zz_p a, const mat_zz_p& B); void mul(mat_zz_p& X, long a, const mat_zz_p& B); // X = a * B void determinant(zz_p& d, const mat_zz_p& A); zz_p determinant(const mat_zz_p& a); // d = determinant(A) void transpose(mat_zz_p& X, const mat_zz_p& A); mat_zz_p transpose(const mat_zz_p& A); // X = transpose of A void solve(zz_p& d, vec_zz_p& X, const mat_zz_p& A, const vec_zz_p& b); // A is an n x n matrix, b is a length n vector. Computes d = // determinant(A). If d != 0, solves x*A = b. void inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_zz_p& X, const mat_zz_p& A); mat_zz_p sqr(const mat_zz_p& A); // X = A*A void inv(mat_zz_p& X, const mat_zz_p& A); mat_zz_p inv(const mat_zz_p& A); // X = A^{-1}; error is raised if A is singular void power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e); mat_zz_p power(const mat_zz_p& A, const ZZ& e); void power(mat_zz_p& X, const mat_zz_p& A, long e); mat_zz_p power(const mat_zz_p& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_zz_p& X, long n); mat_zz_p ident_mat_zz_p(long n); // X = n x n identity matrix long IsIdent(const mat_zz_p& A, long n); // test if A is the n x n identity matrix void diag(mat_zz_p& X, long n, zz_p d); mat_zz_p diag(long n, zz_p d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_zz_p& A, long n, zz_p d); // test if X is an n x n diagonal matrix with d on diagonal long gauss(mat_zz_p& M); long gauss(mat_zz_p& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_zz_p& X, const mat_zz_p& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_zz_p& X, const mat_zz_p& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_zz_p& a); // x = 0 (dimension unchanged) long IsZero(const mat_zz_p& a); // test if a is the zero matrix (any dimension) // operator notation: mat_zz_p operator+(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator-(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator*(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator-(const mat_zz_p& a); // matrix/scalar multiplication: mat_zz_p operator*(const mat_zz_p& a, zz_p b); mat_zz_p operator*(const mat_zz_p& a, long b); mat_zz_p operator*(zz_p a, const mat_zz_p& b); mat_zz_p operator*(long a, const mat_zz_p& b); // matrix/vector multiplication: vec_zz_p operator*(const mat_zz_p& a, const vec_zz_p& b); vec_zz_p operator*(const vec_zz_p& a, const mat_zz_p& b); // assignment operator notation: mat_zz_p& operator+=(mat_zz_p& x, const mat_zz_p& a); mat_zz_p& operator-=(mat_zz_p& x, const mat_zz_p& a); mat_zz_p& operator*=(mat_zz_p& x, const mat_zz_p& a); mat_zz_p& operator*=(mat_zz_p& x, zz_p a); mat_zz_p& operator*=(mat_zz_p& x, long a); vec_zz_p& operator*=(vec_zz_p& x, const mat_zz_p& a); ntl-6.2.1/doc/mat_lzz_pE.cpp.html000644 000765 000024 00000025346 12377144460 017160 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_lzz_pE.cpp.html

/**************************************************************************\

MODULE: mat_zz_pE

SUMMARY:

Defines the class mat_zz_pE.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_lzz_pE.h>


typedef Mat<zz_pE> mat_zz_pE; // backward compatibility

void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B);
// X = A + B

void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B);
// X = A - B

void negate(mat_zz_pE& X, const mat_zz_pE& A);
// X = - A

void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B);
// X = A * B

void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b);
// x = A * b

void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B);
// x = a * B

void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b);
void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b);
void mul(mat_zz_pE& X, const mat_zz_pE& A, long b);
// X = A * b

void mul(mat_zz_pE& X, const zz_pE& a, const mat_zz_pE& B);
void mul(mat_zz_pE& X, const zz_p& a, const mat_zz_pE& B);
void mul(mat_zz_pE& X, long a, const mat_zz_pE& B);
// X = a * B


void determinant(zz_pE& d, const mat_zz_pE& A);
zz_pE determinant(const mat_zz_pE& a);
// d = determinant(A)


void transpose(mat_zz_pE& X, const mat_zz_pE& A);
mat_zz_pE transpose(const mat_zz_pE& A);
// X = transpose of A

void solve(zz_pE& d, vec_zz_pE& X,
           const mat_zz_pE& A, const vec_zz_pE& b);
// A is an n x n matrix, b is a length n vector.  Computes d =
// determinant(A).  If d != 0, solves x*A = b.

void inv(zz_pE& d, mat_zz_pE& X, const mat_zz_pE& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_zz_pE& X, const mat_zz_pE& A);
mat_zz_pE sqr(const mat_zz_pE& A);
// X = A*A   

void inv(mat_zz_pE& X, const mat_zz_pE& A);
mat_zz_pE inv(const mat_zz_pE& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e);
mat_zz_pE power(const mat_zz_pE& A, const ZZ& e);

void power(mat_zz_pE& X, const mat_zz_pE& A, long e);
mat_zz_pE power(const mat_zz_pE& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

void ident(mat_zz_pE& X, long n);
mat_zz_pE ident_mat_zz_pE(long n);
// X = n x n identity matrix

long IsIdent(const mat_zz_pE& A, long n);
// test if A is the n x n identity matrix

void diag(mat_zz_pE& X, long n, const zz_pE& d);
mat_zz_pE diag(long n, const zz_pE& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d);
// test if X is an  n x n diagonal matrix with d on diagonal




long gauss(mat_zz_pE& M);
long gauss(mat_zz_pE& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_zz_pE& X, const mat_zz_pE& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_zz_pE& X, const mat_zz_pE& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.



// miscellaneous:

void clear(mat_zz_pE& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_zz_pE& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b);
mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b);
mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b);

mat_zz_pE operator-(const mat_zz_pE& a);


// matrix/scalar multiplication:

mat_zz_pE operator*(const mat_zz_pE& a, const zz_pE& b);
mat_zz_pE operator*(const mat_zz_pE& a, const zz_p& b);
mat_zz_pE operator*(const mat_zz_pE& a, long b);

mat_zz_pE operator*(const zz_pE& a, const mat_zz_pE& b);
mat_zz_pE operator*(const zz_p& a, const mat_zz_pE& b);
mat_zz_pE operator*(long a, const mat_zz_pE& b);

// matrix/vector multiplication:

vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b);

vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b);


// assignment operator notation:

mat_zz_pE& operator+=(mat_zz_pE& x, const mat_zz_pE& a);
mat_zz_pE& operator-=(mat_zz_pE& x, const mat_zz_pE& a);
mat_zz_pE& operator*=(mat_zz_pE& x, const mat_zz_pE& a);

mat_zz_pE& operator*=(mat_zz_pE& x, const zz_pE& a);
mat_zz_pE& operator*=(mat_zz_pE& x, const zz_p& a);
mat_zz_pE& operator*=(mat_zz_pE& x, long a);

vec_zz_pE& operator*=(vec_zz_pE& x, const mat_zz_pE& a);



ntl-6.2.1/doc/mat_lzz_pE.txt000644 000765 000024 00000010755 12377144460 016250 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_zz_pE SUMMARY: Defines the class mat_zz_pE. \**************************************************************************/ #include #include typedef Mat mat_zz_pE; // backward compatibility void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); // X = A + B void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); // X = A - B void negate(mat_zz_pE& X, const mat_zz_pE& A); // X = - A void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); // X = A * B void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b); // x = A * b void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B); // x = a * B void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b); void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b); void mul(mat_zz_pE& X, const mat_zz_pE& A, long b); // X = A * b void mul(mat_zz_pE& X, const zz_pE& a, const mat_zz_pE& B); void mul(mat_zz_pE& X, const zz_p& a, const mat_zz_pE& B); void mul(mat_zz_pE& X, long a, const mat_zz_pE& B); // X = a * B void determinant(zz_pE& d, const mat_zz_pE& A); zz_pE determinant(const mat_zz_pE& a); // d = determinant(A) void transpose(mat_zz_pE& X, const mat_zz_pE& A); mat_zz_pE transpose(const mat_zz_pE& A); // X = transpose of A void solve(zz_pE& d, vec_zz_pE& X, const mat_zz_pE& A, const vec_zz_pE& b); // A is an n x n matrix, b is a length n vector. Computes d = // determinant(A). If d != 0, solves x*A = b. void inv(zz_pE& d, mat_zz_pE& X, const mat_zz_pE& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_zz_pE& X, const mat_zz_pE& A); mat_zz_pE sqr(const mat_zz_pE& A); // X = A*A void inv(mat_zz_pE& X, const mat_zz_pE& A); mat_zz_pE inv(const mat_zz_pE& A); // X = A^{-1}; error is raised if A is singular void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e); mat_zz_pE power(const mat_zz_pE& A, const ZZ& e); void power(mat_zz_pE& X, const mat_zz_pE& A, long e); mat_zz_pE power(const mat_zz_pE& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_zz_pE& X, long n); mat_zz_pE ident_mat_zz_pE(long n); // X = n x n identity matrix long IsIdent(const mat_zz_pE& A, long n); // test if A is the n x n identity matrix void diag(mat_zz_pE& X, long n, const zz_pE& d); mat_zz_pE diag(long n, const zz_pE& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d); // test if X is an n x n diagonal matrix with d on diagonal long gauss(mat_zz_pE& M); long gauss(mat_zz_pE& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_zz_pE& X, const mat_zz_pE& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_zz_pE& X, const mat_zz_pE& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_zz_pE& a); // x = 0 (dimension unchanged) long IsZero(const mat_zz_pE& a); // test if a is the zero matrix (any dimension) // operator notation: mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator-(const mat_zz_pE& a); // matrix/scalar multiplication: mat_zz_pE operator*(const mat_zz_pE& a, const zz_pE& b); mat_zz_pE operator*(const mat_zz_pE& a, const zz_p& b); mat_zz_pE operator*(const mat_zz_pE& a, long b); mat_zz_pE operator*(const zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator*(const zz_p& a, const mat_zz_pE& b); mat_zz_pE operator*(long a, const mat_zz_pE& b); // matrix/vector multiplication: vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b); // assignment operator notation: mat_zz_pE& operator+=(mat_zz_pE& x, const mat_zz_pE& a); mat_zz_pE& operator-=(mat_zz_pE& x, const mat_zz_pE& a); mat_zz_pE& operator*=(mat_zz_pE& x, const mat_zz_pE& a); mat_zz_pE& operator*=(mat_zz_pE& x, const zz_pE& a); mat_zz_pE& operator*=(mat_zz_pE& x, const zz_p& a); mat_zz_pE& operator*=(mat_zz_pE& x, long a); vec_zz_pE& operator*=(vec_zz_pE& x, const mat_zz_pE& a); ntl-6.2.1/doc/mat_poly_ZZ.cpp.html000644 000765 000024 00000003134 12377144460 017312 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_poly_ZZ.cpp.html

/**************************************************************************\

MODULE: mat_poly_ZZ

SUMMARY:

Routine for computing the characteristic polynomial of a matrix over ZZ.



\**************************************************************************/


#include <NTL/mat_ZZ.h>
#include <NTL/ZZX.h>

void CharPoly(ZZX& f, const mat_ZZ& M);
// f = characteristic polynomial of M


ntl-6.2.1/doc/mat_poly_ZZ.txt000644 000765 000024 00000000607 12377144460 016406 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_poly_ZZ SUMMARY: Routine for computing the characteristic polynomial of a matrix over ZZ. \**************************************************************************/ #include #include void CharPoly(ZZX& f, const mat_ZZ& M); // f = characteristic polynomial of M ntl-6.2.1/doc/mat_poly_ZZ_p.cpp.html000644 000765 000024 00000003157 12377144460 017636 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_poly_ZZ_p.cpp.html

/*****************************************************************************\

MODULE: mat_poly_ZZ_p

SUMMARY:

Routine for computing the characteristic polynomial of a matrix over ZZ_p.



\*****************************************************************************/


#include <NTL/mat_ZZ_p.h>
#include <NTL/ZZ_pX.h>

void CharPoly(ZZ_pX& f, const mat_ZZ_p& M);
// f = characteristic polynomial of M

ntl-6.2.1/doc/mat_poly_ZZ_p.txt000644 000765 000024 00000000630 12377144460 016721 0ustar00shoupstaff000000 000000 /*****************************************************************************\ MODULE: mat_poly_ZZ_p SUMMARY: Routine for computing the characteristic polynomial of a matrix over ZZ_p. \*****************************************************************************/ #include #include void CharPoly(ZZ_pX& f, const mat_ZZ_p& M); // f = characteristic polynomial of M ntl-6.2.1/doc/mat_poly_lzz_p.cpp.html000644 000765 000024 00000003153 12377144460 020106 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/mat_poly_lzz_p.cpp.html

/**************************************************************************\

MODULE: mat_poly_zz_p

SUMMARY:

Routine for computing the characteristic polynomial of a matrix over zz_p.



\**************************************************************************/


#include "mat_zz_p.h"
#include "zz_pX.h"

void CharPoly(zz_pX& f, const mat_zz_p& M);
// f = characteristic polynomial of M


ntl-6.2.1/doc/mat_poly_lzz_p.txt000644 000765 000024 00000000613 12377144460 017176 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: mat_poly_zz_p SUMMARY: Routine for computing the characteristic polynomial of a matrix over zz_p. \**************************************************************************/ #include "mat_zz_p.h" #include "zz_pX.h" void CharPoly(zz_pX& f, const mat_zz_p& M); // f = characteristic polynomial of M ntl-6.2.1/doc/matrix.cpp.html000644 000765 000024 00000022510 12377144460 016346 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/matrix.cpp.html

/**************************************************************************\

MODULE: matrix

SUMMARY:

Matrix templates.

The declaration 

   Mat<T> M;

creates a 0 x 0 matrix.  

We can make it have 10 rows and 20 columns like this:

   M.SetDims(10, 20);

A row can be accessed as M[i], indexing from 0, or as M(i), indexing from 1.
A matrix entry can be accessed as M[i][j], indexing from 0, or as
M(i, j), indexing from 1.

A matrix is represented as a Vec< Vec<T> >: a vector of rows, where
each row is a Vec<T>.  Any attempt to resize one of the rows so
as to create a non-rectangular matrix will result in a run-time 
error.

The dimensions of an existing matrix may be changed.  If the number of
columns does not change, then the matrix is just "resized" like a vector,
and no information is lost.  Otherwise, if the number of columns changes,
the matrix is completely destroyed, and a new matrix is created


\**************************************************************************/

template<class T>
class Mat {

   typedef typename Vec<T>::value_type value_type;
   typedef typename Vec<T>::reference reference;
   typedef typename Vec<T>::const_reference const_reference;


   Mat(); // initially 0 x 0

   Mat(const Mat<T>& a);
   Mat& operator=(const Mat<T>& a);
   ~Mat();

   Mat(INIT_SIZE_TYPE, long n, long m);
   // Mat(INIT_SIZE, n, m) initializes an n x m matrix, invoking
   // the default constructor for T to initialize entries.

   void SetDims(long n, long m);
   // M.SetDims(n, m) makes M have dimension n x m.  If the number of
   // columns (m) changes, previous storage is freed, and space for M
   // is reallocated and initialized; otherwise, more rows are
   // allocated as necessary (when number of rows increases), 
   // excess rows are retained (when number of rows decreases),
   // and--importantly--the contents do not change.

   void kill(); free storage and make 0 x 0

   long NumRows() const;
   // M.NumRows() returns the number of rows of M

   long NumCols() const;
   // M.NumCols() returns the number of columns of M

   Vec<T>& operator[](long i);
   const Vec<T>& operator[](long i) const;
   // access row i, initial index 0.  Any attempt to change the length
   // of this row will raise an error.

   Vec<T>& operator()(long i);
   const Vec<T>& operator()(long i) const;
   // access row i, initial index 1.  Any attempt to change the length
   // of this row will raise an error.

   reference operator()(long i, long j);
   const_reference operator()(long i, long j) const;
   // access element (i, j), both indices starting at 1

   const_reference get(long i, long j) const;
   // access element (i, j), both indices starting at 0

   void put(long i, long j, const T& a);
   // same as M[i].put(j, a)

   template <class U>
   void put(long i, long j, const U& a);
   // same as M[i].put(j, a)


   long position(const Vec<T>& a) const;
   // returns index of a in matrix, or -1 if not present;
   // equivalent to rep(*this).position(a).


   long position1(const Vec<T>& a) const;
   // returns index of a in matrix, or -1 if not present;
   // equivalent to rep(*this).position1(a).



};

template<class T>
const Vec< Vec<T> >& rep(const Mat<T>& a);
// read-only access to underlying representation

template<class T>
void swap(Mat<T>& X, Mat<T>& Y);
// swaps X and Y (by swapping pointers)

template<class T>
void MakeMatrix(Mat<T>& x, const vec_vec_T& a);
// copies a to x, checking that it is "rectangular"

/**************************************************************************\

                            Input/Output

\**************************************************************************/


template<class T>
istream& operator>>(istream&, Mat<T>&);

template<class T>
ostream& operator<<(ostream&, const Mat<T>&);

/**************************************************************************\

                              Equality Testing


\**************************************************************************/


template<class T>
long operator==(const Mat<T>& a, const Mat<T>& b);

template<class T>
long operator!=(const Mat<T>& a, const Mat<T>& b);

ntl-6.2.1/doc/matrix.txt000644 000765 000024 00000010100 12377144460 015430 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: matrix SUMMARY: Matrix templates. The declaration Mat M; creates a 0 x 0 matrix. We can make it have 10 rows and 20 columns like this: M.SetDims(10, 20); A row can be accessed as M[i], indexing from 0, or as M(i), indexing from 1. A matrix entry can be accessed as M[i][j], indexing from 0, or as M(i, j), indexing from 1. A matrix is represented as a Vec< Vec >: a vector of rows, where each row is a Vec. Any attempt to resize one of the rows so as to create a non-rectangular matrix will result in a run-time error. The dimensions of an existing matrix may be changed. If the number of columns does not change, then the matrix is just "resized" like a vector, and no information is lost. Otherwise, if the number of columns changes, the matrix is completely destroyed, and a new matrix is created \**************************************************************************/ template class Mat { typedef typename Vec::value_type value_type; typedef typename Vec::reference reference; typedef typename Vec::const_reference const_reference; Mat(); // initially 0 x 0 Mat(const Mat& a); Mat& operator=(const Mat& a); ~Mat(); Mat(INIT_SIZE_TYPE, long n, long m); // Mat(INIT_SIZE, n, m) initializes an n x m matrix, invoking // the default constructor for T to initialize entries. void SetDims(long n, long m); // M.SetDims(n, m) makes M have dimension n x m. If the number of // columns (m) changes, previous storage is freed, and space for M // is reallocated and initialized; otherwise, more rows are // allocated as necessary (when number of rows increases), // excess rows are retained (when number of rows decreases), // and--importantly--the contents do not change. void kill(); free storage and make 0 x 0 long NumRows() const; // M.NumRows() returns the number of rows of M long NumCols() const; // M.NumCols() returns the number of columns of M Vec& operator[](long i); const Vec& operator[](long i) const; // access row i, initial index 0. Any attempt to change the length // of this row will raise an error. Vec& operator()(long i); const Vec& operator()(long i) const; // access row i, initial index 1. Any attempt to change the length // of this row will raise an error. reference operator()(long i, long j); const_reference operator()(long i, long j) const; // access element (i, j), both indices starting at 1 const_reference get(long i, long j) const; // access element (i, j), both indices starting at 0 void put(long i, long j, const T& a); // same as M[i].put(j, a) template void put(long i, long j, const U& a); // same as M[i].put(j, a) long position(const Vec& a) const; // returns index of a in matrix, or -1 if not present; // equivalent to rep(*this).position(a). long position1(const Vec& a) const; // returns index of a in matrix, or -1 if not present; // equivalent to rep(*this).position1(a). }; template const Vec< Vec >& rep(const Mat& a); // read-only access to underlying representation template void swap(Mat& X, Mat& Y); // swaps X and Y (by swapping pointers) template void MakeMatrix(Mat& x, const vec_vec_T& a); // copies a to x, checking that it is "rectangular" /**************************************************************************\ Input/Output \**************************************************************************/ template istream& operator>>(istream&, Mat&); template ostream& operator<<(ostream&, const Mat&); /**************************************************************************\ Equality Testing \**************************************************************************/ template long operator==(const Mat& a, const Mat& b); template long operator!=(const Mat& a, const Mat& b); ntl-6.2.1/doc/names.txt000644 000765 000024 00000006531 12377144460 015244 0ustar00shoupstaff000000 000000 Here is a list of the macro names that have changed. As you can see, most of these are anyway undocumented, and you probably never knew they existed. Also changed, but not listed here, are the macros used to prevent double inclusion of ".h" files. Also, the identifiers like INIT_VAL, INIT_SIZE, INIT_FFT are no longer macros, but are defined to be constant objects of particular classes. Their names do not change. ZZ_ARITH_RIGHT_SHIFT -> NTL_ARITH_RIGHT_SHIFT ZZ_BITS_PER_INT -> NTL_BITS_PER_INT ZZ_BITS_PER_LONG -> NTL_BITS_PER_LONG ZZ_DOUBLES_LOW_HIGH -> NTL_DOUBLES_LOW_HIGH ZZ_DOUBLE_PRECISION -> NTL_DOUBLE_PRECISION ZZ_EXT_DOUBLE -> NTL_EXT_DOUBLE ZZ_FDOUBLE_PRECISION -> NTL_FDOUBLE_PRECISION ZZ_FRADIX -> NTL_FRADIX ZZ_FRADIX_INV -> NTL_FRADIX_INV ZZ_FetchHiLo -> NTL_FetchHiLo ZZ_FetchLo -> NTL_FetchLo ZZ_HI_WD -> NTL_HI_WD ZZ_LO_WD -> NTL_LO_WD ZZ_MAX_INT -> NTL_MAX_INT ZZ_MAX_LONG -> NTL_MAX_LONG ZZ_MIN_INT -> NTL_MIN_INT ZZ_MIN_LONG -> NTL_MIN_LONG ZZ_NBITS -> NTL_NBITS ZZ_NBITSH -> NTL_NBITSH ZZ_NBITS_MAX -> NTL_NBITS_MAX ZZ_NTL_SINGLE_MUL_OK -> NTL_SINGLE_MUL_OK ZZ_PRIME_BND -> NTL_PRIME_BND ZZ_RADIX -> NTL_RADIX ZZ_RADIXM -> NTL_RADIXM ZZ_RADIXROOT -> NTL_RADIXROOT ZZ_RADIXROOTM -> NTL_RADIXROOTM ntl_eq_matrix_decl -> NTL_eq_matrix_decl ntl_eq_matrix_impl -> NTL_eq_matrix_impl ntl_eq_vector_decl -> NTL_eq_vector_decl ntl_eq_vector_impl -> NTL_eq_vector_impl ntl_io_matrix_decl -> NTL_io_matrix_decl ntl_io_matrix_impl -> NTL_io_matrix_impl ntl_io_vector_decl -> NTL_io_vector_decl ntl_io_vector_impl -> NTL_io_vector_impl ntl_matrix_decl -> NTL_matrix_decl ntl_matrix_impl -> NTL_matrix_impl ntl_pair_decl -> NTL_pair_decl ntl_pair_eq_decl -> NTL_pair_eq_decl ntl_pair_eq_impl -> NTL_pair_eq_impl ntl_pair_impl -> NTL_pair_impl ntl_pair_io_decl -> NTL_pair_io_decl ntl_pair_io_impl -> NTL_pair_io_impl ntl_vector_decl -> NTL_vector_decl ntl_vector_default -> NTL_vector_default ntl_vector_impl -> NTL_vector_impl ntl_vector_impl_plain -> NTL_vector_impl_plain BB_HALF_MUL_CODE -> NTL_BB_HALF_MUL_CODE BB_MUL_CODE -> NTL_BB_MUL_CODE BB_REV_CODE -> NTL_BB_REV_CODE BB_SQR_CODE -> NTL_BB_SQR_CODE FFTFudge -> NTL_FFTFudge FFTMaxRoot -> NTL_FFTMaxRoot FFTMaxRootBnd -> NTL_FFTMaxRootBnd QUAD_FLOAT_SPLIT -> NTL_QUAD_FLOAT_SPLIT WV_NTL_RANGE_CHECK_CODE -> NTL_WV_RANGE_CHECK_CODE WordVectorExpansionRatio -> NTL_WordVectorExpansionRatio WordVectorInputBlock -> NTL_WordVectorInputBlock WordVectorMinAlloc -> NTL_WordVectorMinAlloc XD_BOUND -> NTL_XD_BOUND XD_BOUND_INV -> NTL_XD_BOUND_INV XD_HBOUND -> NTL_XD_HBOUND XD_HBOUND_INV -> NTL_XD_HBOUND_INV ZZ_pRegister -> NTL_ZZ_pRegister ZZ_pX_BERMASS_CROSSOVER -> NTL_ZZ_pX_BERMASS_CROSSOVER ZZ_pX_DIV_CROSSOVER -> NTL_ZZ_pX_DIV_CROSSOVER ZZ_pX_FFT_CROSSOVER -> NTL_ZZ_pX_FFT_CROSSOVER ZZ_pX_GCD_CROSSOVER -> NTL_ZZ_pX_GCD_CROSSOVER ZZ_pX_HalfGCD_CROSSOVER -> NTL_ZZ_pX_HalfGCD_CROSSOVER ZZ_pX_NEWTON_CROSSOVER -> NTL_ZZ_pX_NEWTON_CROSSOVER ZZ_pX_TRACE_CROSSOVER -> NTL_ZZ_pX_TRACE_CROSSOVER zz_pRegister -> NTL_zz_pRegister zz_pX_BERMASS_CROSSOVER -> NTL_zz_pX_BERMASS_CROSSOVER zz_pX_DIV_CROSSOVER -> NTL_zz_pX_DIV_CROSSOVER zz_pX_GCD_CROSSOVER -> NTL_zz_pX_GCD_CROSSOVER zz_pX_HalfGCD_CROSSOVER -> NTL_zz_pX_HalfGCD_CROSSOVER zz_pX_MOD_CROSSOVER -> NTL_zz_pX_MOD_CROSSOVER zz_pX_MUL_CROSSOVER -> NTL_zz_pX_MUL_CROSSOVER zz_pX_NEWTON_CROSSOVER -> NTL_zz_pX_NEWTON_CROSSOVER zz_pX_TRACE_CROSSOVER -> NTL_zz_pX_TRACE_CROSSOVER ntl-6.2.1/doc/pair.cpp.html000644 000765 000024 00000011061 12377144460 015774 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/pair.cpp.html
/**************************************************************************\

MODULE: pair

SUMMARY:

Pair templates.

The decalaration 

   Pair<S,T> p;

creates a pair object using the default constructors for S and T.  The
member p.a is the first component (of type S) and the member p.b is
the second component (of type T).


\**************************************************************************/



#include <NTL/tools.h>

template<class S, class T>
class Pair {
public:
   S a;
   T b;

   Pair();
   // default constructor...invokes default constructors for S and T

   Pair(const Pair<S,T>& x); // copy

   Pair& operator=(const Pair<S,T>& x); // assignment

   Pair(const S& x, const T& y);  // initialize with (x, y)

   ~Pair();
   // destructor...invokes destructors for S and T
};

template<class S, class T>
Pair<S,T> cons(const S& x, const T& y);
// returns Pair<S,T>(x, y)


/**************************************************************************\

                             Input/Output

The I/O format for a Pair is

   [a b]

\**************************************************************************/


template<class S, class T>
istream& operator>>(istream&, Pair<S,T>&);

template<class S, class T>
ostream& operator<<(ostream&, const Pair<S,T>&);


/**************************************************************************\

                              Equality Testing

\**************************************************************************/


template<class S, class T>
long operator==(const Pair<S,T>& x, const Pair<S,T>& y);

template<class S, class T>
long operator!=(const Pair<S,T>& x, const Pair<S,T>& y);


ntl-6.2.1/doc/pair.txt000644 000765 000024 00000003224 12377144460 015070 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: pair SUMMARY: Pair templates. The decalaration Pair p; creates a pair object using the default constructors for S and T. The member p.a is the first component (of type S) and the member p.b is the second component (of type T). \**************************************************************************/ #include template class Pair { public: S a; T b; Pair(); // default constructor...invokes default constructors for S and T Pair(const Pair& x); // copy Pair& operator=(const Pair& x); // assignment Pair(const S& x, const T& y); // initialize with (x, y) ~Pair(); // destructor...invokes destructors for S and T }; template Pair cons(const S& x, const T& y); // returns Pair(x, y) /**************************************************************************\ Input/Output The I/O format for a Pair is [a b] \**************************************************************************/ template istream& operator>>(istream&, Pair&); template ostream& operator<<(ostream&, const Pair&); /**************************************************************************\ Equality Testing \**************************************************************************/ template long operator==(const Pair& x, const Pair& y); template long operator!=(const Pair& x, const Pair& y); ntl-6.2.1/doc/quad_float.cpp.html000644 000765 000024 00000060066 12377144460 017171 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/quad_float.cpp.html


/**************************************************************************\

MODULE: quad_float

SUMMARY:

The class quad_float is used to represent quadruple precision numbers.
Thus, with standard IEEE floating point, you should get the equivalent
of about 106 bits of precision (but actually just a bit less).

The interface allows you to treat quad_floats more or less as if they were
"ordinary" floating point types.

See below for more implementation details.


\**************************************************************************/

#include <NTL/ZZ.h>


class quad_float {
public:

quad_float(); // = 0

quad_float(const quad_float& a);  // copy constructor

explicit quad_float(double a);  // promotion constructor


quad_float& operator=(const quad_float& a);  // assignment operator
quad_float& operator=(double a);

~quad_float();


static void SetOutputPrecision(long p);
// This sets the number of decimal digits to be output.  Default is
// 10.


static long OutputPrecision();
// returns current output precision.


};


/**************************************************************************\

                             Arithmetic Operations

\**************************************************************************/




quad_float operator +(const quad_float& x, const quad_float& y);
quad_float operator -(const quad_float& x, const quad_float& y);
quad_float operator *(const quad_float& x, const quad_float& y);
quad_float operator /(const quad_float& x, const quad_float& y);


// PROMOTIONS: operators +, -, *, / promote double to quad_float
// on (x, y).

quad_float operator -(const quad_float& x);

quad_float& operator += (quad_float& x, const quad_float& y);
quad_float& operator += (quad_float& x, double y);

quad_float& operator -= (quad_float& x, const quad_float& y);
quad_float& operator -= (quad_float& x, double y);

quad_float& operator *= (quad_float& x, const quad_float& y);
quad_float& operator *= (quad_float& x, double y);

quad_float& operator /= (quad_float& x, const quad_float& y);
quad_float& operator /= (quad_float& x, double y);

quad_float& operator++(quad_float& a); // prefix
void operator++(quad_float& a, int); // postfix

quad_float& operator--(quad_float& a); // prefix
void operator--(quad_float& a, int); // postfix



/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator> (const quad_float& x, const quad_float& y);
long operator>=(const quad_float& x, const quad_float& y);
long operator< (const quad_float& x, const quad_float& y);
long operator<=(const quad_float& x, const quad_float& y);
long operator==(const quad_float& x, const quad_float& y);
long operator!=(const quad_float& x, const quad_float& y);

long sign(const quad_float& x);  // sign of x, -1, 0, +1
long compare(const quad_float& x, const quad_float& y); // sign of x - y

// PROMOTIONS: operators >, ..., != and function compare
// promote double to quad_float on (x, y).


/**************************************************************************\

                               Input/Output
Input Syntax:

<number>: [ "-" ] <unsigned-number>
<unsigned-number>: <dotted-number> [ <e-part> ] | <e-part>
<dotted-number>: <digits> | <digits> "." <digits> | "." <digits> | <digits> "."
<digits>: <digit> <digits> | <digit>
<digit>: "0" | ... | "9"
<e-part>: ( "E" | "e" ) [ "+" | "-" ] <digits>

Examples of valid input:

17 1.5 0.5 .5  5.  -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10

Note that the number of decimal digits of precision that are used
for output can be set to any number p >= 1 by calling
the routine quad_float::SetOutputPrecision(p).  
The default value of p is 10.
The current value of p is returned by a call to quad_float::OutputPrecision().



\**************************************************************************/


istream& operator >> (istream& s, quad_float& x);
ostream& operator << (ostream& s, const quad_float& x);


/**************************************************************************\

                                  Miscellaneous

\**************************************************************************/



quad_float sqrt(const quad_float& x);
quad_float floor(const quad_float& x);
quad_float ceil(const quad_float& x);
quad_float trunc(const quad_float& x);
quad_float fabs(const quad_float& x);
quad_float exp(const quad_float& x);
quad_float log(const quad_float& x);


void power(quad_float& x, const quad_float& a, long e); // x = a^e
quad_float power(const quad_float& a, long e);

void power2(quad_float& x, long e); // x = 2^e
quad_float power2_quad_float(long e);

quad_float ldexp(const quad_float& x, long e);  // return x*2^e

long IsFinite(quad_float *x); // checks if x is "finite"   
                              // pointer is used for compatability with
                              // IsFinite(double*)


void random(quad_float& x);
quad_float random_quad_float();
// generate a random quad_float x with 0 <= x <= 1





/***********************************************************************\

IMPLEMENTATION DETAILS

A quad_float x is represented as a pair of doubles, x.hi and x.lo,
such that the number represented by x is x.hi + x.lo, where

   |x.lo| <= 0.5*ulp(x.hi),  (*)

and ulp(y) means "unit in the last place of y".  

For the software to work correctly, IEEE Standard Arithmetic is sufficient.  
That includes just about every modern computer; the only exception I'm
aware of is Intel x86 platforms running Linux (but you can still
use this platform--see below).

Also sufficient is any platform that implements arithmetic with correct 
rounding, i.e., given double floating point numbers a and b, a op b 
is computed exactly and then rounded to the nearest double.  
The tie-breaking rule is not important.

This is a rather wierd representation;  although it gives one
essentially twice the precision of an ordinary double, it is
not really the equivalent of quadratic precision (despite the name).
For example, the number 1 + 2^{-200} can be represented exactly as
a quad_float.  Also, there is no real notion of "machine precision".

Note that overflow/underflow for quad_floats does not follow any particularly
useful rules, even if the underlying floating point arithmetic is IEEE
compliant.  Generally, when an overflow/underflow occurs, the resulting value
is unpredicatble, although typically when overflow occurs in computing a value
x, the result is non-finite (i.e., IsFinite(&x) == 0).  Note, however, that
some care is taken to ensure that the ZZ to quad_float conversion routine
produces a non-finite value upon overflow.

THE INTEL x86 PROBLEM

Although just about every modern processor implements the IEEE
floating point standard, there still can be problems
on processors that support IEEE extended double precision.
The only processor I know of that supports this is the x86/Pentium.

While extended double precision may sound like a nice thing,
it is not.  Normal double precision has 53 bits of precision.
Extended has 64.  On x86s, the FP registers have 53 or 64 bits
of precision---this can be set at run-time by modifying
the cpu "control word" (something that can be done
only in assembly code).
However, doubles stored in memory always have only 53 bits.
Compilers may move values between memory and registers
whenever they want, which can effectively change the value
of a floating point number even though at the C/C++ level,
nothing has happened that should have changed the value.
Is that sick, or what?
Actually, the new C99 standard seems to outlaw such "spontaneous"
value changes; however, this behavior is not necessarily
universally implemented.

This is a real headache, and if one is not just a bit careful,
the quad_float code will break.  This breaking is not at all subtle,
and the program QuadTest will catch the problem if it exists.

You should not need to worry about any of this, because NTL automatically
detects and works around these problems as best it can, as described below.
It shouldn't make a mistake, but if it does, you will
catch it in the QuadTest program.
If things don't work quite right, you might try
setting NTL_FIX_X86 or NTL_NO_FIX_X86 flags in ntl_config.h,
but this should not be necessary.

Here are the details about how NTL fixes the problem.

The first and best way is to have the default setting of the control word
be 53 bits.  However, you are at the mercy of your platform
(compiler, OS, run-time libraries).  Windows does this,
and so the problem simply does not arise here, and NTL neither
detects nor fixes the problem.  Linux, however, does not do this,
which really sucks.  Can we talk these Linux people into changing this?

The second way to fix the problem is by having NTL 
fiddle with control word itself.  If you compile NTL using a GNU compiler
on an x86, this should happen automatically.
On the one hand, this is not a general, portable solution,
since it will only work if you use a GNU compiler, or at least one that
supports GNU 'asm' syntax.  
On the other hand, almost everybody who compiles C++ on x86/Linux
platforms uses GNU compilers (although there are some commercial
compilers out there that I don't know too much about).

The third way to fix the problem is to 'force' all intermediate
floating point results into memory.  This is not an 'ideal' fix,
since it is not fully equivalent to 53-bit precision (because of 
double rounding), but it works (although to be honest, I've never seen
a full proof of correctness in this case).
NTL's quad_float code does this by storing intermediate results
in local variables declared to be 'volatile'.
This is the solution to the problem that NTL uses if it detects
the problem and can't fix it using the GNU 'asm' hack mentioned above.
This solution should work on any platform that faithfully
implements 'volatile' according to the ANSI C standard.



BACKGROUND INFO

The code NTL uses algorithms designed by Knuth, Kahan, Dekker, and
Linnainmaa.  The original transcription to C++ was done by Douglas
Priest.  Enhancements and bug fixes were done by Keith Briggs
(http://epidem13.plantsci.cam.ac.uk/~kbriggs).  The NTL version is a
stripped down version of Briggs' code, with a couple of bug fixes and
portability improvements.  Briggs has continued to develop his
library;  see his web page above for the latest version and more information.

Here is a brief annotated bibliography (compiled by Priest) of papers 
dealing with DP and similar techniques, arranged chronologically.


Kahan, W., Further Remarks on Reducing Truncation Errors,
  {\it Comm.\ ACM\/} {\bf 8} (1965), 40.

M{\o}ller, O., Quasi Double Precision in Floating-Point Addition,
  {\it BIT\/} {\bf 5} (1965), 37--50.

  The two papers that first presented the idea of recovering the
  roundoff of a sum.

Dekker, T., A Floating-Point Technique for Extending the Available
  Precision, {\it Numer.\ Math.} {\bf 18} (1971), 224--242.

  The classic reference for DP algorithms for sum, product, quotient,
  and square root.

Pichat, M., Correction d'une Somme en Arithmetique \`a Virgule
  Flottante, {\it Numer.\ Math.} {\bf 19} (1972), 400--406.

  An iterative algorithm for computing a protracted sum to working
  precision by repeatedly applying the sum-and-roundoff method.

Linnainmaa, S., Analysis of Some Known Methods of Improving the Accuracy
  of Floating-Point Sums, {\it BIT\/} {\bf 14} (1974), 167--202.

  Comparison of Kahan and M{\o}ller algorithms with variations given
  by Knuth.

Bohlender, G., Floating-Point Computation of Functions with Maximum
  Accuracy, {\it IEEE Trans.\ Comput.} {\bf C-26} (1977), 621--632.

  Extended the analysis of Pichat's algorithm to compute a multi-word
  representation of the exact sum of n working precision numbers.
  This is the algorithm Kahan has called "distillation".

Linnainmaa, S., Software for Doubled-Precision Floating-Point Computations,
  {\it ACM Trans.\ Math.\ Soft.} {\bf 7} (1981), 272--283.

  Generalized the hypotheses of Dekker and showed how to take advantage
  of extended precision where available.

Leuprecht, H., and W.~Oberaigner, Parallel Algorithms for the Rounding-Exact
  Summation of Floating-Point Numbers, {\it Computing} {\bf 28} (1982), 89--104.

  Variations of distillation appropriate for parallel and vector
  architectures.

Kahan, W., Paradoxes in Concepts of Accuracy, lecture notes from Joint
  Seminar on Issues and Directions in Scientific Computation, Berkeley, 1989.

  Gives the more accurate DP sum I've shown above, discusses some
  examples.

Priest, D., Algorithms for Arbitrary Precision Floating Point Arithmetic,
  in P.~Kornerup and D.~Matula, Eds., {\it Proc.\ 10th Symposium on Com-
  puter Arithmetic}, IEEE Computer Society Press, Los Alamitos, Calif., 1991.

  Extends from DP to arbitrary precision; gives portable algorithms and
  general proofs.

Sorensen, D., and P.~Tang, On the Orthogonality of Eigenvectors Computed
  by Divide-and-Conquer Techniques, {\it SIAM J.\ Num.\ Anal.} {\bf 28}
  (1991), 1752--1775.

  Uses some DP arithmetic to retain orthogonality of eigenvectors
  computed by a parallel divide-and-conquer scheme.

Priest, D., On Properties of Floating Point Arithmetics: Numerical Stability
  and the Cost of Accurate Computations, Ph.D. dissertation, University
  of California at Berkeley, 1992.

  More examples, organizes proofs in terms of common properties of fp
  addition/subtraction, gives other summation algorithms.

Another relevant paper: 

X. S. Li, et al.
Design, implementation, and testing of extended and mixed 
precision BLAS.  ACM Trans. Math. Soft., 28:152-205, 2002.



\***********************************************************************/

ntl-6.2.1/doc/quad_float.txt000644 000765 000024 00000033001 12377144460 016250 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: quad_float SUMMARY: The class quad_float is used to represent quadruple precision numbers. Thus, with standard IEEE floating point, you should get the equivalent of about 106 bits of precision (but actually just a bit less). The interface allows you to treat quad_floats more or less as if they were "ordinary" floating point types. See below for more implementation details. \**************************************************************************/ #include class quad_float { public: quad_float(); // = 0 quad_float(const quad_float& a); // copy constructor explicit quad_float(double a); // promotion constructor quad_float& operator=(const quad_float& a); // assignment operator quad_float& operator=(double a); ~quad_float(); static void SetOutputPrecision(long p); // This sets the number of decimal digits to be output. Default is // 10. static long OutputPrecision(); // returns current output precision. }; /**************************************************************************\ Arithmetic Operations \**************************************************************************/ quad_float operator +(const quad_float& x, const quad_float& y); quad_float operator -(const quad_float& x, const quad_float& y); quad_float operator *(const quad_float& x, const quad_float& y); quad_float operator /(const quad_float& x, const quad_float& y); // PROMOTIONS: operators +, -, *, / promote double to quad_float // on (x, y). quad_float operator -(const quad_float& x); quad_float& operator += (quad_float& x, const quad_float& y); quad_float& operator += (quad_float& x, double y); quad_float& operator -= (quad_float& x, const quad_float& y); quad_float& operator -= (quad_float& x, double y); quad_float& operator *= (quad_float& x, const quad_float& y); quad_float& operator *= (quad_float& x, double y); quad_float& operator /= (quad_float& x, const quad_float& y); quad_float& operator /= (quad_float& x, double y); quad_float& operator++(quad_float& a); // prefix void operator++(quad_float& a, int); // postfix quad_float& operator--(quad_float& a); // prefix void operator--(quad_float& a, int); // postfix /**************************************************************************\ Comparison \**************************************************************************/ long operator> (const quad_float& x, const quad_float& y); long operator>=(const quad_float& x, const quad_float& y); long operator< (const quad_float& x, const quad_float& y); long operator<=(const quad_float& x, const quad_float& y); long operator==(const quad_float& x, const quad_float& y); long operator!=(const quad_float& x, const quad_float& y); long sign(const quad_float& x); // sign of x, -1, 0, +1 long compare(const quad_float& x, const quad_float& y); // sign of x - y // PROMOTIONS: operators >, ..., != and function compare // promote double to quad_float on (x, y). /**************************************************************************\ Input/Output Input Syntax: : [ "-" ] : [ ] | : | "." | "." | "." : | : "0" | ... | "9" : ( "E" | "e" ) [ "+" | "-" ] Examples of valid input: 17 1.5 0.5 .5 5. -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10 Note that the number of decimal digits of precision that are used for output can be set to any number p >= 1 by calling the routine quad_float::SetOutputPrecision(p). The default value of p is 10. The current value of p is returned by a call to quad_float::OutputPrecision(). \**************************************************************************/ istream& operator >> (istream& s, quad_float& x); ostream& operator << (ostream& s, const quad_float& x); /**************************************************************************\ Miscellaneous \**************************************************************************/ quad_float sqrt(const quad_float& x); quad_float floor(const quad_float& x); quad_float ceil(const quad_float& x); quad_float trunc(const quad_float& x); quad_float fabs(const quad_float& x); quad_float exp(const quad_float& x); quad_float log(const quad_float& x); void power(quad_float& x, const quad_float& a, long e); // x = a^e quad_float power(const quad_float& a, long e); void power2(quad_float& x, long e); // x = 2^e quad_float power2_quad_float(long e); quad_float ldexp(const quad_float& x, long e); // return x*2^e long IsFinite(quad_float *x); // checks if x is "finite" // pointer is used for compatability with // IsFinite(double*) void random(quad_float& x); quad_float random_quad_float(); // generate a random quad_float x with 0 <= x <= 1 /***********************************************************************\ IMPLEMENTATION DETAILS A quad_float x is represented as a pair of doubles, x.hi and x.lo, such that the number represented by x is x.hi + x.lo, where |x.lo| <= 0.5*ulp(x.hi), (*) and ulp(y) means "unit in the last place of y". For the software to work correctly, IEEE Standard Arithmetic is sufficient. That includes just about every modern computer; the only exception I'm aware of is Intel x86 platforms running Linux (but you can still use this platform--see below). Also sufficient is any platform that implements arithmetic with correct rounding, i.e., given double floating point numbers a and b, a op b is computed exactly and then rounded to the nearest double. The tie-breaking rule is not important. This is a rather wierd representation; although it gives one essentially twice the precision of an ordinary double, it is not really the equivalent of quadratic precision (despite the name). For example, the number 1 + 2^{-200} can be represented exactly as a quad_float. Also, there is no real notion of "machine precision". Note that overflow/underflow for quad_floats does not follow any particularly useful rules, even if the underlying floating point arithmetic is IEEE compliant. Generally, when an overflow/underflow occurs, the resulting value is unpredicatble, although typically when overflow occurs in computing a value x, the result is non-finite (i.e., IsFinite(&x) == 0). Note, however, that some care is taken to ensure that the ZZ to quad_float conversion routine produces a non-finite value upon overflow. THE INTEL x86 PROBLEM Although just about every modern processor implements the IEEE floating point standard, there still can be problems on processors that support IEEE extended double precision. The only processor I know of that supports this is the x86/Pentium. While extended double precision may sound like a nice thing, it is not. Normal double precision has 53 bits of precision. Extended has 64. On x86s, the FP registers have 53 or 64 bits of precision---this can be set at run-time by modifying the cpu "control word" (something that can be done only in assembly code). However, doubles stored in memory always have only 53 bits. Compilers may move values between memory and registers whenever they want, which can effectively change the value of a floating point number even though at the C/C++ level, nothing has happened that should have changed the value. Is that sick, or what? Actually, the new C99 standard seems to outlaw such "spontaneous" value changes; however, this behavior is not necessarily universally implemented. This is a real headache, and if one is not just a bit careful, the quad_float code will break. This breaking is not at all subtle, and the program QuadTest will catch the problem if it exists. You should not need to worry about any of this, because NTL automatically detects and works around these problems as best it can, as described below. It shouldn't make a mistake, but if it does, you will catch it in the QuadTest program. If things don't work quite right, you might try setting NTL_FIX_X86 or NTL_NO_FIX_X86 flags in ntl_config.h, but this should not be necessary. Here are the details about how NTL fixes the problem. The first and best way is to have the default setting of the control word be 53 bits. However, you are at the mercy of your platform (compiler, OS, run-time libraries). Windows does this, and so the problem simply does not arise here, and NTL neither detects nor fixes the problem. Linux, however, does not do this, which really sucks. Can we talk these Linux people into changing this? The second way to fix the problem is by having NTL fiddle with control word itself. If you compile NTL using a GNU compiler on an x86, this should happen automatically. On the one hand, this is not a general, portable solution, since it will only work if you use a GNU compiler, or at least one that supports GNU 'asm' syntax. On the other hand, almost everybody who compiles C++ on x86/Linux platforms uses GNU compilers (although there are some commercial compilers out there that I don't know too much about). The third way to fix the problem is to 'force' all intermediate floating point results into memory. This is not an 'ideal' fix, since it is not fully equivalent to 53-bit precision (because of double rounding), but it works (although to be honest, I've never seen a full proof of correctness in this case). NTL's quad_float code does this by storing intermediate results in local variables declared to be 'volatile'. This is the solution to the problem that NTL uses if it detects the problem and can't fix it using the GNU 'asm' hack mentioned above. This solution should work on any platform that faithfully implements 'volatile' according to the ANSI C standard. BACKGROUND INFO The code NTL uses algorithms designed by Knuth, Kahan, Dekker, and Linnainmaa. The original transcription to C++ was done by Douglas Priest. Enhancements and bug fixes were done by Keith Briggs (http://epidem13.plantsci.cam.ac.uk/~kbriggs). The NTL version is a stripped down version of Briggs' code, with a couple of bug fixes and portability improvements. Briggs has continued to develop his library; see his web page above for the latest version and more information. Here is a brief annotated bibliography (compiled by Priest) of papers dealing with DP and similar techniques, arranged chronologically. Kahan, W., Further Remarks on Reducing Truncation Errors, {\it Comm.\ ACM\/} {\bf 8} (1965), 40. M{\o}ller, O., Quasi Double Precision in Floating-Point Addition, {\it BIT\/} {\bf 5} (1965), 37--50. The two papers that first presented the idea of recovering the roundoff of a sum. Dekker, T., A Floating-Point Technique for Extending the Available Precision, {\it Numer.\ Math.} {\bf 18} (1971), 224--242. The classic reference for DP algorithms for sum, product, quotient, and square root. Pichat, M., Correction d'une Somme en Arithmetique \`a Virgule Flottante, {\it Numer.\ Math.} {\bf 19} (1972), 400--406. An iterative algorithm for computing a protracted sum to working precision by repeatedly applying the sum-and-roundoff method. Linnainmaa, S., Analysis of Some Known Methods of Improving the Accuracy of Floating-Point Sums, {\it BIT\/} {\bf 14} (1974), 167--202. Comparison of Kahan and M{\o}ller algorithms with variations given by Knuth. Bohlender, G., Floating-Point Computation of Functions with Maximum Accuracy, {\it IEEE Trans.\ Comput.} {\bf C-26} (1977), 621--632. Extended the analysis of Pichat's algorithm to compute a multi-word representation of the exact sum of n working precision numbers. This is the algorithm Kahan has called "distillation". Linnainmaa, S., Software for Doubled-Precision Floating-Point Computations, {\it ACM Trans.\ Math.\ Soft.} {\bf 7} (1981), 272--283. Generalized the hypotheses of Dekker and showed how to take advantage of extended precision where available. Leuprecht, H., and W.~Oberaigner, Parallel Algorithms for the Rounding-Exact Summation of Floating-Point Numbers, {\it Computing} {\bf 28} (1982), 89--104. Variations of distillation appropriate for parallel and vector architectures. Kahan, W., Paradoxes in Concepts of Accuracy, lecture notes from Joint Seminar on Issues and Directions in Scientific Computation, Berkeley, 1989. Gives the more accurate DP sum I've shown above, discusses some examples. Priest, D., Algorithms for Arbitrary Precision Floating Point Arithmetic, in P.~Kornerup and D.~Matula, Eds., {\it Proc.\ 10th Symposium on Com- puter Arithmetic}, IEEE Computer Society Press, Los Alamitos, Calif., 1991. Extends from DP to arbitrary precision; gives portable algorithms and general proofs. Sorensen, D., and P.~Tang, On the Orthogonality of Eigenvectors Computed by Divide-and-Conquer Techniques, {\it SIAM J.\ Num.\ Anal.} {\bf 28} (1991), 1752--1775. Uses some DP arithmetic to retain orthogonality of eigenvectors computed by a parallel divide-and-conquer scheme. Priest, D., On Properties of Floating Point Arithmetics: Numerical Stability and the Cost of Accurate Computations, Ph.D. dissertation, University of California at Berkeley, 1992. More examples, organizes proofs in terms of common properties of fp addition/subtraction, gives other summation algorithms. Another relevant paper: X. S. Li, et al. Design, implementation, and testing of extended and mixed precision BLAS. ACM Trans. Math. Soft., 28:152-205, 2002. \***********************************************************************/ ntl-6.2.1/doc/sedscript.txt000644 000765 000024 00000005367 12377144460 016147 0ustar00shoupstaff000000 000000 # This is a sed script to make most of the common syntactic # changes necessary to move from NTL 2.0 to 3.0. # If this file is in sedscript.txt (as it originally is) # the command # sed -f sedscript.txt < old.c > new.c # will convert old.c to new.c with the necesary changes. # # Please note that this script is niether "sound" or "complete", # but should still be useful. # rename some classes s/BB/GF2X/g s/BB_p/GF2E/g s/GF2Vector/vec_GF2/g s/GF2Matrix/mat_GF2/g # rename some functions s/ZZ_pInit(/ZZ_p::init(/g s/zz_pInit(/zz_p::init(/g s/zz_pFFTInit(/zz_p::FFTInit(/ s/GF2EInit(/GF2E::init(/g s/LowBits/trunc/g s/Long(/to_long(/g s/XDouble(/to_xdouble(/g s/Quad_float(/to_quad_float(/g s/trace(/TraceMod(/g s/norm(/NormMod(/g s/MinPoly(/MinPolyMod(/g s/IrredPoly(/IrredPolyMod(/g s/CharPoly(/CharPolyMod(/g # rename generic vector, pair, matrix macro instantations # these assume no embedded blanks s/vector_decl(\(.*\))/ntl_vector_decl(\1,vec_\1)/g s/vector_io_decl(\(.*\))/ntl_io_vector_decl(\1,vec_\1)/g s/vector_eq_decl(\(.*\))/ntl_eq_vector_decl(\1,vec_\1)/g # s/vector_impl(\(.*\))/ntl_vector_impl(\1,vec_\1)/g s/vector_impl_plain(\(.*\))/ntl_vector_impl_plain(\1,vec_\1)/g s/vector_io_impl(\(.*\))/ntl_io_vector_impl(\1,vec_\1)/g s/vector_eq_impl(\(.*\))/ntl_eq_vector_impl(\1,vec_\1)/g # s/matrix_decl(\(.*\))/ntl_matrix_decl(\1,vec_\1,vec_vec_\1,mat_\1)/g s/matrix_io_decl(\(.*\))/ntl_io_matrix_decl(\1,vec_\1,vec_vec_\1,mat_\1)/g s/matrix_eq_decl(\(.*\))/ntl_eq_matrix_decl(\1,vec_\1,vec_vec_\1,mat_\1)/g # s/matrix_impl(\(.*\))/ntl_matrix_impl(\1,vec_\1,vec_vec_\1,mat_\1)/g s/matrix_io_impl(\(.*\))/ntl_io_matrix_impl(\1,vec_\1,vec_vec_\1,mat_\1)/g s/matrix_eq_impl(\(.*\))/ntl_eq_matrix_impl(\1,vec_\1,vec_vec_\1,mat_\1)/g # s/pair_decl(\(.*\),\(.*\))/ntl_pair_decl(\1,\2,pair_\1_\2)/g s/pair_io_decl(\(.*\),\(.*\))/ntl_pair_io_decl(\1,\2,pair_\1_\2)/g s/pair_eq_decl(\(.*\),\(.*\))/ntl_pair_eq_decl(\1,\2,pair_\1_\2)/g # s/pair_impl(\(.*\),\(.*\))/ntl_pair_impl(\1,\2,pair_\1_\2)/g s/pair_io_impl(\(.*\),\(.*\))/ntl_pair_io_impl(\1,\2,pair_\1_\2)/g s/pair_eq_impl(\(.*\),\(.*\))/ntl_pair_eq_impl(\1,\2,pair_\1_\2)/g # rename type names for the generic types # these allow embedded blanks s/pair *( *\([^,() ]*\) *, *\([^() ]*\) *)/pair_\1_\2/g s/vector *( *\([^() ]*\) *)/vec_\1/g s/matrix *( *\([^() ]*\) *)/mat_\1/g # # repeat to handle one nesting level # s/pair *( *\([^,() ]*\) *, *\([^() ]*\) *)/pair_\1_\2/g s/vector *( *\([^() ]*\) *)/vec_\1/g s/matrix *( *\([^() ]*\) *)/mat_\1/g # # repeat to handle two nesting levels # s/pair *( *\([^,() ]*\) *, *\([^() ]*\) *)/pair_\1_\2/g s/vector *( *\([^() ]*\) *)/vec_\1/g s/matrix *( *\([^() ]*\) *)/mat_\1/g # rename header files for generic types s/vector\.h/ntl_vector\.h/ s/matrix\.h/ntl_matrix\.h/ s/pair\.h/ntl_pair\.h/ ntl-6.2.1/doc/tools.cpp.html000644 000765 000024 00000020127 12377144460 016204 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/tools.cpp.html

/**************************************************************************\

MODULE: tools

SUMMARY:

Some useful tools that are used throughout NTL.

\**************************************************************************/

#include <cstdlib>
#include <cmath>
#include <iostream>

#include <NTL/config.h>
#include <NTL/mach_desc.h>




double GetTime();
// returns number of seconds of CPU time used by this process;

void PrintTime(ostream& s, double t);
// prints the time t (in seconds) to s in the format
//     ss  or  mm:ss  or  hh:mm:ss,
// where the value t is first rounded to the nearest integer.

void Error(const char *s);
// print an error message and call abort

extern void (*ErrorCallback)();
// A pointer (initially NULL) to a callback function.
// This function will be called by the Error function,
// as well as other functions, before calling abort().
// Note that the callback function is expected to have
// C++ linkage, as it is called directly by a C++ function,
// even though the latter function may be called from a
// C function.

long IsWhiteSpace(long c);
// returns 1 if c is "wite space" (as defined by isspace is the
// standard library...usually blanks, tabs, newlines), and 0 otherwise.

long SkipWhiteSpace(istream& s);
// skips white space (as defined by IsWhiteSpace).
// Return value is 0 if end-of-file is reached; otherwise,
// return value is 1.

// This routine is useful in conjuction with input routines,
// like NTL's, that raise an error if an input item is
// ill-formed or missing.  

long IsEOFChar(long c);
// test if c == EOF


long CharToIntVal(long c);
// returns the hexidecimal value of c if c is '0'..'9', 'A'..'F', or 'a'..'f';
// otherwise, the return value is -1.

char IntValToChar(long x);
// returns the hexadecimal digit '0'..'9', 'a'..'f' representing x;
// an error is raised if x < 0 or x > 15.

long IsFinite(double *p);
// Returns 1 if *p is a "finite" floating point number.
// A pointer is used to ensure that the number is in memory,
// which on some architectures (notably x86/Pentium) can make a difference.

// some min/max and swap routines:

int min(int a, int b);
int max(int a, int b);

long min(long a, long b);
long max(long a, long b);

long min(int a, long b);
long max(int a, long b);

long min(long a, int b);
long max(long a, int b);

void swap(long& a, long& b);
void swap(int& a, int& b);


// defined here are all the conversion routines among the types 
// int, long, float, double.  See conversions.txt for complete details.



// The following platform-dependent macros are defined:

#define NTL_BITS_PER_LONG      (...)  /* bits in a long */
#define NTL_MAX_LONG           (...)  /* max value of a long */
#define NTL_MIN_LONG           (...)  /* min value of a long */

#define NTL_BITS_PER_INT       (...)  /* bits in a int */
#define NTL_MAX_INT            (...)  /* max value of a int */
#define NTL_MIN_INT            (...)  /* min value of a int */

#define NTL_DOUBLE_PRECISION   (...)  /* # of bits of precision in a double */
#define NTL_FDOUBLE_PRECISION  (...)  /* the double value 
                                        2^{NTL_DOUBLE_PRECISION-1} */

#define NTL_ARITH_RIGHT_SHIFT  (...)  /* 1 if signed right-shift is
                                        arithmetic; 0 otherwise */

#define NTL_EXT_DOUBLE         (...)  /* 1 if platform has "extended" doubles;
                                        0 otherwise */



ntl-6.2.1/doc/tools.txt000644 000765 000024 00000006557 12377144460 015311 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: tools SUMMARY: Some useful tools that are used throughout NTL. \**************************************************************************/ #include #include #include #include #include double GetTime(); // returns number of seconds of CPU time used by this process; void PrintTime(ostream& s, double t); // prints the time t (in seconds) to s in the format // ss or mm:ss or hh:mm:ss, // where the value t is first rounded to the nearest integer. void Error(const char *s); // print an error message and call abort extern void (*ErrorCallback)(); // A pointer (initially NULL) to a callback function. // This function will be called by the Error function, // as well as other functions, before calling abort(). // Note that the callback function is expected to have // C++ linkage, as it is called directly by a C++ function, // even though the latter function may be called from a // C function. long IsWhiteSpace(long c); // returns 1 if c is "wite space" (as defined by isspace is the // standard library...usually blanks, tabs, newlines), and 0 otherwise. long SkipWhiteSpace(istream& s); // skips white space (as defined by IsWhiteSpace). // Return value is 0 if end-of-file is reached; otherwise, // return value is 1. // This routine is useful in conjuction with input routines, // like NTL's, that raise an error if an input item is // ill-formed or missing. long IsEOFChar(long c); // test if c == EOF long CharToIntVal(long c); // returns the hexidecimal value of c if c is '0'..'9', 'A'..'F', or 'a'..'f'; // otherwise, the return value is -1. char IntValToChar(long x); // returns the hexadecimal digit '0'..'9', 'a'..'f' representing x; // an error is raised if x < 0 or x > 15. long IsFinite(double *p); // Returns 1 if *p is a "finite" floating point number. // A pointer is used to ensure that the number is in memory, // which on some architectures (notably x86/Pentium) can make a difference. // some min/max and swap routines: int min(int a, int b); int max(int a, int b); long min(long a, long b); long max(long a, long b); long min(int a, long b); long max(int a, long b); long min(long a, int b); long max(long a, int b); void swap(long& a, long& b); void swap(int& a, int& b); // defined here are all the conversion routines among the types // int, long, float, double. See conversions.txt for complete details. // The following platform-dependent macros are defined: #define NTL_BITS_PER_LONG (...) /* bits in a long */ #define NTL_MAX_LONG (...) /* max value of a long */ #define NTL_MIN_LONG (...) /* min value of a long */ #define NTL_BITS_PER_INT (...) /* bits in a int */ #define NTL_MAX_INT (...) /* max value of a int */ #define NTL_MIN_INT (...) /* min value of a int */ #define NTL_DOUBLE_PRECISION (...) /* # of bits of precision in a double */ #define NTL_FDOUBLE_PRECISION (...) /* the double value 2^{NTL_DOUBLE_PRECISION-1} */ #define NTL_ARITH_RIGHT_SHIFT (...) /* 1 if signed right-shift is arithmetic; 0 otherwise */ #define NTL_EXT_DOUBLE (...) /* 1 if platform has "extended" doubles; 0 otherwise */ ntl-6.2.1/doc/tour-ack.html000644 000765 000024 00000004125 12377144460 016010 0ustar00shoupstaff000000 000000 A Tour of NTL: Acknowledgements
[Previous] [Up] [Next]

A Tour of NTL: Acknowledgements


  • Thanks to Arjen Lenstra and Keith Briggs for letting me use their software. Arjen Lenstra wrote LIP, a long integer package, which formed the basis of NTL. Keith Briggs developed a quadratic precision package. NTL has incorporated parts of these two packages, although what is in NTL has been extensively re-written. Thanks also to Keith for many helpful comments and suggestions.
  • Thanks to Juergen Gerhard for pointing out the deficiency in the NTL-1.0 ZZX arithmetic, for contributing the Schoenhage/Strassen code to NTL 1.5, and for helping to track down some bugs.
  • Thanks to Phong Nguyen for putting the new LLL code (NTL 1.7) through a torture test of lattices arising from new lattice-based cryptosystems; this led to a number of significant improvements in the LLL code.
  • Thanks to Dan Boneh for encouraging me to improve NTL's programming interface.
  • Thanks to John Abbott, Mark van Hoeij, and Paul Zimmermann for sharing many of their ideas about polynomial factoring over ZZ with me, which led to a number of improvements in NTL's factorizer. Thanks also to Paul for numerous other suggestions and improvements.
  • Thanks to Joachim von zur Gathen and Erich Kaltofen for their collaboration and support over the years.
ntl-6.2.1/doc/tour-changes.html000644 000765 000024 00000134505 12377144460 016670 0ustar00shoupstaff000000 000000 A Tour of NTL: Summary of Changes
[Previous] [Up] [Next]

A Tour of NTL: Summary of Changes


2014.8.26: Changes between NTL 6.2 and 6.2.1

  • Fixed syntax problem in NTL/vector.h


2014.8.21: Changes between NTL 6.1 and 6.2

  • I added explicit constructors corresponding to promotions. For example:

       ZZ w = ZZ(1); // legal
       ZZ w(1);      // legal
       ZZ w{1};      // legal in C++11
       ZZ w = 1;     // not legal

    Also added new names for the "monomial constructors", e.g., ZZX(INIT_MONO, i, c) is now preferred to ZZX(i, c), although the old constructors are still there. There are also new constructors like ZZX(INIT_MONO, i) for making monic monomials.

  • An subtle but important change is that now objects from classes that represent residue class rings with a dynamically installed modulus, i.e.,
       ZZ_p, zz_p, ZZ_pE, lzz_pE, GF2E,
    
    may now be used a bit more flexibly.

    It is critical that such objects created under one modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations now include: the default and copy constructor, the destructor, and the assignment operator. In addition it is generally safe to read any object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). (In the past, it was generally unsafe to use the the default and copy constructors out of context, which also prevented vectors and polynomials of such objects from being copied out of context.)

    The implementations of Vec<ZZ_p> and Vec<GF2E> are still specialized to manage memory more efficiently than in the default implementation of Vec<T>. Contiguous elements in such an array are allocated in a contiguous region of memory. This reduces the number of calls to the memory allocator, and leads to greater locality of reference. A consequence of this implementation is that any calls to SetLength on such a vector will need to use information about the current modulus, and so such calls should only be done "in context". That said, it is still safe to construct a such a vector using the default or copy contructor, and to assign or append one to another "out of context".

  • For the classes ZZ_p, ZZ_pE, zz_pE, and GF2E, added explicit "allocation" and "no allocation" contructors (invoked with INIT_ALLOC and INIT_NO_ALLOC) and special member function allocate(). This allows one to explicitly determine exactly when space for such objects is allocated. By default, no space is allocated (this is different from prior versions of NTL), except for ZZ_p's that are a part of a Vec<ZZ_p> and GF2E's that are a part of a Vec<GF2E>

  • Added new classes ZZ_pPush, ZZ_pEPush, zz_pPush, zz_pEPush, GF2EPush. These allow one to conveniently backup and optionally install a new modulus in one step:

       { ZZ_pPush push(p); ... }

    will save the current modulus and install p as the new modulus; when the destructor for push is invoked, the old modulus will be re-installed.

  • Made the one-arg constructors for all the various "context" classes (e.g., ZZ_pContext) explicit.

  • As a general aid to generic programming, I've added a bunch of typedef's using consistent naming conventions to all of the main arithmetic classes. E.g., ZZ_p::poly_type is a typedef for ZZ_pX. There are a whole bunch of these. See the documentation for the individual classes for details.

  • Got rid of a few esoteric compilation modes:
    • All files are now C++ files, and should be compiled using a C++ compiler. In older versions, some files could be compiled either as C or C++.
    • The flag NTL_GMP_HACK is no longer supported. GMP may still be used using the NTL_GMP_LIP flag, which is still highly recommended for high-performance applcations.
    • The flags NTL_SINGLE_MUL and NTL_FAST_INT_MUL are no longer recognized. These were really outdated and esoteric.

  • I have started working towards making NTL thread safe. It is not as difficult as I thought it would be, but it is still a work in progress. So far I have identified all global variables, and either got rid of them, or tagged them as "thread local". So, although there are still some global variables, they will all eventually be "thread local". In particular, things like the current ZZ_p modulus will be a thread-local global variable.

    There are a few remaining trouble spots I've tagged: these mostly involve lazy initialization of tables; I have a plan for making this code thread safe using nearly lock-free coding techniques.

    I will hopefully get this done within the next 6-12 months. One thing that is slowing me down is the lack of availibility of C++11 features that I need to do some of this, but it will come.

    The main reason for getting rid of the esoteric compilation modes mentioned above is to make it easier to do this thread-safety work.


2014.03.13: Changes between NTL 6.0 and 6.1

  • Added support for "user defined" FFT primes for zz_p. See the functions

       static void zz_p::UserFFTInit(long p);
       zz_pContext::zz_pContext(INIT_USER_FFT_TYPE, long p);

    in the lzz_p module.


2013.02.15: Changes between NTL 5.5.2 and 6.0

  • Replaced the old template-like macros for vectors, matrices, and pairs with true template classes: Vec<T>, Mat<T>, and Pair<S,T>.

    For backwards compatibilty, all the names that were used in previous versions (e.g., vec_ZZ_p, mat_ZZ_p) have been replaced with appropriate typedefs.

    For many years, I resisted the temptation of using templates, because compiler support was very inconsistent. But that no longer seems to be the case.

    This change, while rather sweeping, should create very few, if any, incompatibilities with existing software. The biggest issue would be for software that uses the old template-like macros: such macro invocations can simply be replaced with appropriate typedefs.

  • Made the conversion interface more complete and uniform. Also, using template notation, one can and should now write conv<ZZ>(a) instead of to_ZZ(a) (for backward compatibility, all the old names to_XXX are still there, but many new conversions are not available under these old names).

    There are many new conversions provided. Moreover, whenever there is a conversion from a ring R to a ring S, there is a corresponding, coefficiet-wise conversion from the polynomial ring R[X] to the polynomial ring S[X].

    In addition, using the template mechanism, there are generic conversions for vectors and matrices. For example, if there is a conversion from S to T, then there is automatically a corresponding component-wise conversion from Vec<S> to Vec<T>.

  • Introduced a more general mechanism for accessing GF2's in packed structures via indexing (see the class ref_GF2 in the GF2 module).

  • Employed ideas from David Harvey to make the single-precision FFT faster (about twice as fast in many cases). This speeds up many higher-level operations.

  • Fixed all known bugs.


2009.08.14: Changes between NTL 5.5.1 and 5.5.2

  • New routines MulAddTo and MulSubFrom for computing x += a*b and x -= a*b, where x and a are ZZ's and b is a ZZ or a long. In the case where b is a long, this may be much faster than writing mul(t, a, b); add(x, x, t). See ZZ.txt for details. These new routines are used in a number of places in NTL to get faster algorithms (for example, the LLL routine).
  • Fixed a relatively benign indexing bug in GF2EX discovered by Berend-Benjamin Tams using the valgrind tool.


2009.05.05: Changes between NTL 5.5 and 5.5.1

  • If using GMP (via either NTL_GMP_LIP or NTL_GMP_HACK), then the new version (4.3.0) of GMP implements the XGCD functionality differently, so that the coefficients do not always agree with those returned by the classical extended Euclidean algorithm. This version of NTL corrects the coefficients, so that the "classical" coefficients are always produced, regardless of GMP's implementation. This version of NTL also works around a bug in GMP 4.3.0's XGCD code (although that bug should be fixed in GMP 4.3.1).
  • The configure script has been slightly modified: there is a new configuration variable DEF_PREFIX, whose value can be used to set PREFIX, GMP_PREFIX, and GF2X_PREFIX in one stroke. Also, the (somewhat esoteric) configure variables GMP_LIBDIR, GMP_INCDIR, GF2X_LIBDIR, and GF2X_INCDIR have slightly different meanings now.


2009.04.08: Changes between NTL 5.4.2 and 5.5

  • Added the ability to generate a shared library (with help from Tim Abbott). Details.
  • Fixed some standardization issues (with help from Tim Abbot): default location of installed documentation files now conforms to standards; use of EOF now conforms to standards.
  • Added a callback mechanism to NTL's error reporting function. See ErrorCallback in tools.txt.
  • Added support for the gf2x library for speeding up arithmetic in GF2X (with help from Emmanuel Thomé). Details.
  • In conjuction with the above, I also changed the GF2X so that it works better with very large polynomials: large blocks of memory are released, recursive HalfGCD algorithms are used for large polynomials.
  • Fixed a bug in void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F) (reported by Luca De Feo).
  • Fixed a performance issue in various versions of SetCoeff (reported by Luca De Feo).
  • Fixed the declaration of mat_zz_p transpose(const mat_zz_p& a) (reported by Benoit Lacelle).


2008.03.05: Changes between NTL 5.4.1 and 5.4.2

  • Fixed a bug in the sub(ZZ_pEX, ZZ_pE, ZZ_pEX) and sub(zz_pEX, zz_pE, zz_pEX) routines (reported by Charanjit Jutla). Under certain circumstances, these could outout wrong answers.


2007.05.09: Changes between NTL 5.4 and 5.4.1

  • Fixed rounding bug in expm1 (reported by Paul Zimmermann).
  • Fixed memory leak in several LLL routines (reported by Friedrich Bahr).
  • Fixed infinite loop in several LLL routines (this only occurred on machines, like x86, with double rounding).
  • Improved GF2X timing tests (suggested by Paul Zimmermann).


2005.03.24: Changes between NTL 5.3.2 and 5.4

  • By default, NTL now compiles in ISO mode (using namespaces, etc.). You can always revert to traditional mode by unsetting the flag NTL_STD_CXX (either pass NTL_STD_CXX=off to the configure script, or manually edit the config.h file).

  • Some bug fixes:
    • The sqrt and log1p routines for the RR class would produce incorrectly rounded results in certain circumstances (although this only affected the relative error of the result very marginally).
    • The SqrRootPrec routine for the RR class could not be called, because it was defined incorrectly.

    Thanks to Paul Zimmermann for finding (and fixing) these bugs! Paul has also validated NTL's RR class by cross-checking it with the MPFR library.

  • Some performance enhancements:
    • Added a new MulModPrecon inline function for computing (a * b) % n for single precision numbers, when b and n are fixed for several computations. On some platforms this can be twice as fast or more than the old MulMod2 routine. This indirectly affects a lot of computations that are done via homomorphic imaging (polynomial multiplication over zz_p, ZZ_p, and ZZ, matrix computations over zz_p and ZZ).
    • Rewrote the small prime FFT to take advantage of the new MulModPrecon, and to be more cache friendly.
    • Improved the performance of the GF2X multiplication routine. On some platforms, it can be twice as fast as the old one. Thanks (again) to Paul Zimmermann for suggesting some of these improvements and supplying some of the code.

  • Miscellany:
    • Rewrote several of the installation scripts in Perl (the old shell scripts were getting too messy to maintain). However, the syntax for all of the command-line interfaces remains identical.


2004.05.21: Changes between NTL 5.3.1 and 5.3.2

  • Some bug fixes.

  • Re-wrote SqrRootMod to make it run faster.


2002.12.17: Changes between NTL 5.3 and 5.3.1

  • Fixed a bug affecting the BuildIrred routines for ZZ_pEX and zz_pEX.


2002.07.05: Changes between NTL 5.2 and 5.3

  • Minimized and isolated constructs that do not adhere to C/C++ standards, and added flags NTL_CLEAN_INT and NTL_CLEAN_PTR which force stricter compliance with these standards [more details].

  • Added functions IsWhiteSpace, CharToIntVal, and IntValToChar to the tools module [more details].

  • Added methods allocated, position1 to generic vector classes [more details].

  • Added method allocated to the class vec_GF2 [more details].

  • Added conversion routines from unsigned int/long to int, long, float, and double [more details].

  • Added routines AddPrec, SubPrec, etc., to the RR module, and declared the practice of directly assigning to the variable RR::prec obsolete [more details].

  • Fixed a number of minor bugs.


2001.07.19: Changes between NTL 5.1a and 5.2

  • Implemented Mark van Hoeij's new algorithm for factorining polynomials with rational coefficients. This new algorithm is much more efficient than the previous algorithm used by NTL, and is the default (one can switch back to the old algorithm with a run-time switch).

    [documentation]

    [performance measurements]

  • Added routines LLL_plus that are just like the all-integer LLL routines, except that they return the exact values of the squared lengths of the Gramm-Schmidt basis vectors. This is useful in implementing van Hoeij's algorithm. [more details].

  • Made a small change to quad_float.c to make it compile under gcc version 3.0 without errors. This is the one place in NTL where I resort to just a little assmebly code (but only on x86/Linux platforms), and wouldn't you know it, this is the one place where gcc 3.0 had problems.

  • Made a small change to the procedure for generating a distribution, so that now all files in the "tar" file comprising the distribution come without any annoyingly excessive access control restrictions.

  • Changed the version numbering scheme so that it is now closer to "standard practice". This is version "5.2". Any small bug fixes to this version will be named "5.2.1", "5.2.2", etc. Also, macros are now defined so that the numerical components of the version number are available to the programmer. [more details].


2001.06.08: Changes between NTL 5.0c and 5.1a

Some minor fixes and additions.

Completely backward compatible.

  • Added a routine LatticeSolve() for finding integer solutions to linear systems of integer equations. [more details]

  • Modified the stragey used by the LLL() and image() routines in the LLL package to deal with linear dependencies. The new strategy guarantees better worst-case bounds on the sizes of intermediate values. I'm not sure if it will have any serious practical impact, though.

  • Added some "partial ISO modes" so that one can use some of the features of Standard C++, even if ones compiler does not yet support all of the features. [more details]

  • Bug fix: routine determnant() in mat_GF2.h was not visible to the linker because of a typo in mat_GF2.c.

  • Made a "smarter" script for selecting the GetTime() function. This fixes an installation problem on Cygwin/Windows 95 platforms. I hope it doesn't create more problems than it solves, though.

  • Added some extra documentation for installation under Windows/MS Visual C++. [more details]

  • Changed some names like c_lip.c to c_lip_impl.h. This should avoid some potential installation problems.

  • Throw away first 256-bytes of arc4 streams to improve quality of the pseudo-random number generator. This may change the precise behavior of some programs.

  • Other minor, internal modifications.


2001.02.19: Changes between NTL 5.0b and 5.0c

Fixed a naming problem in the Windows distribution. The Unix distribution is unaffected.


2001.02.19: Changes between NTL 5.0a and 5.0b

Fixed a typo in vec_ulong.c that causes a compile error on some platforms.


2001.02.19: Changes between NTL 4.3a and 5.0a

  • I've now re-structured NTL so that one can use either 'traditional' LIP or GMP as the primary long integer package. Doing this introduced some (minor) backward incompatabilies in the programming interface, so there is also a 'third way' -- you can use GMP as a supplemental long integer package (as in NTL 4.3), getting many (but not all) of the performance benefits of GMP, while maintaining complete backward compatability with the traditional long integer package. This 'third way' is not highly recommended -- it is only intended as a backward compatabilty hack.

    Even if you do not use GMP, you should read about using NTL with GMP so that you can write code that works with either the traditional or GMP long integer packages.

  • Added a ZZ to unsigned long conversion routine. [more details]
  • Added new vector classes vec_ulong (vectors of unsigned longs) and vec_vec_ulong. [more details]
  • Some minor bug fixes: under some unusual circumstances, a memory allocation error could be erroneously raised; I also added a patch that works around a bug in v3.0.1 of GMP.
  • Some internal cleansing, minimizing the use of non-standard constructs.


Changes between NTL 4.2a and 4.3a

This is backward compatible with previous versions.

  • Improved the performance of ZZ_pX arithmetic when using GMP. The GMP version is also more space efficient (the pre-computed tables are much smaller). These improvements are most marked for very large p (several thousand bits).

    The only thing unsatisfactory about this state of affairs is that vis a vis the GMP version, the pure LIP code is asymptotically slower by more than a constant factor, and is is also less space efficient. Perhaps I'll get around to rectifying this imbalance someday. To do this, I need a sub-quadratic division with remainder routine for LIP. At any rate, the differences only become seriously noticible when p has more than a few thousand bits.

  • Some other small adjustments here and there.


Changes between NTL 4.1a and 4.2a

This is backward compatible with previous versions.

  • Hacked the big integer code so that NTL uses GMP (the GNU Multi-Precision library). This is done in such a way as to get most of the benefits of GMP with a reasonable amount of effort, and while maintaining complete backward compatability and minimizing the risk of introducing bugs. Some arithmetic operations on some platforms may execute two to three times faster if using GMP. [more details]
  • Simplified the installation procedure on Unix systems by providing a simple configuration script so that setting various configuration variables can be done without editing the makefile and config.h file. [more details]
  • Added function GenGermainPrime to efficiently generate random Germain primes, i.e., primes p such that 2p+1 is also prime. [more details]
  • Added a function random to generate random quad_floats. [more details]
  • Added an ifdef in tools.h that allows one to suppress the declaration of min and max functions in NTL client programs; these were causing problems when writing 'Windows applications'.
  • Implemented a faster algorithm for initializing the ZZ_p auxilliary data structures.
  • Polished up a few other minor things in the code and documentation.


Changes between NTL 4.0a and 4.1a

This is backward compatible with previous versions.

  • Made some changes that should make NTL compile smoothly using any variation of the C++ language between traditional and ISO Standard. These changes do not affect the documented NTL interface or the behaviour of NTL.
  • Added a flag NTL_STD_CXX in the config.h file. Setting this flag causes all of NTL to be "wrapped" in namespace NTL, and that part of the standard library used by NTL is "wrapped" in namespace std. This should greatly help with the namespace pollution problem. Go here for more details.


Changes between NTL 3.9b and 4.0a

This is backward compatible with previous version.

  • Attached the GNU General Public License to NTL.
  • Fixed two bugs:
    • one in ReconstructRational which resulted in a crash on some inputs;
    • one in exp(RR) (and by implication in pow(RR,RR)), which led to wrong answers on 64-bit machines when computing exp(x) for x > 2^53.
  • Increased some inconvenient limiting bounds, including a restriction on the FFT.


Changes between NTL 3.9a and 3.9b

This is a minor revision of 3.9a.

  • Improved time and space efficiency of the HNF routine (see HNF.txt). The old version was based on the description in Henri Cohen's book, which was not really properly optimized.


Changes between NTL 3.8b and 3.9a

This is backward compatible with previous versions.

  • Modified the installation script somewhat, adding a configuration wizard that sets the flags in config.h "automagically". This works for the Unix version only.
  • Improved the xdouble input/output and ascii to xdouble conversion. The old version could be a bit flaky when reading/writing very large numbers. The new I/O routines also attain better accuracy.
  • Improved conversion routines between xdouble and ZZ/RR.
  • Improved the RR output routine. The new version should be more accurate and also completely platform independent.
  • Added the following routines to the RR package:
       {Trunc,Floor,Ceil,Round}ToZZ, round
       RoundToPrecision, MakeRR
       random
    
    See RR.txt for details.
  • Improved the accuracy of quad_float input/output, and the accuracy of conversion between quad_float and RR.
  • Made the timing function somewhat more robust.
  • Hacked the Unix installation script so that it works more smoothly with Cygnus tools under Windows.
  • Fixed a few other, small problems.


Changes between NTL 3.8a and 3.8b

This is a minor revision of 3.8a.

  • Fixed a bug, a memory leak in routine gauss for mat_ZZ_pE and mat_zz_pE.
  • Fixed a minor problem in config.h.
  • Tightened up some size checks, so that now some nice "size invariants" are guaranteed, e.g., for a ZZ n,

       NumBits(NumBits(n)) <= NTL_BITS_PER_LONG-4

    Similarly for the type GF2X. Of course, on most platforms, one will run out of memory before these bounds are exceeded, but they are nevertheless convenient.


Changes between NTL 3.7a and 3.8a

This is backward compatible with previous versions.

  • Added conversion routines from unsigned int and unsigned long to ZZ, RR, xdouble, and quad_float.
  • Added routines GF2XFromBytes and BytesFromGF2X for conversion between byte vectors and polynomials over GF(2), along with routines NumBits and NumBytes for such polynomials. See GF2X.txt for details.
  • Added a hack in the ZZX factorizer to exploit polynomials of the form g(x^k). This can be disabled by setting the variable ZZXFac_PowerHack to zero. See ZZXFactoring.txt for details.
  • Improved the hensel system solver solve1. See mat_ZZ.txt for details.
  • Changed documentation for RationalReconstruction to reflect the Wang, Guy, Davenport bounds. See ZZ.txt for details.
  • Improved the routine GenPrime a bit.
  • Some other small tweaks here and there. No real bug fixes.
  • Polished the documentation a bit, adding more examples.


Changes between NTL 3.6b and 3.7a

This is backward compatible with previous versions.

  • Added a "rational reconstruction" routine. See the routine ReconstructRational in ZZ.txt.
  • Added another routine for solving linear systems over ZZ that is based on Hensel lifting, rather than Chinese Remaindering. It can be significantly faster in some cases. See the routine solve1 in mat_ZZ.txt).
  • Some performace tuning, especially CRT and polynomial interpolation code.
  • Various documentation corrections.
  • Added more "overflow checks" here and there to ensure programs crash gracefully when certain things get too big.
  • Fixed a "benign" bug (i.e., it would never get triggered on any of today's machines).
  • Removed references to <malloc.h>, which were unnecessary, non-standard, and caused problems on some platforms.


Changes between NTL 3.6a and 3.6b

Bug fixes.


Changes between NTL 3.5a and 3.6a

This version is backward compatible with 3.5a.

  • A few small bug fixes and performance enhancements.
  • Changes to the ZZX factoring routines that in some cases yield dramatic performance improvements (more details).


Changes between NTL 3.1b and 3.5a

Please note. This version is NOT completely backward compatible.

Summary of changes:

  • Improved performance of the "all integer" LLL routine.
  • Put in a better pseudo-random number generator, and added ZZ/byte array conversions.
  • Improved performance of primality test, and added a more convenient routine GenPrime.
  • Overloaded NTL's vector placement "new" operator in a different way to avoid conflicts with standard C++ library.
  • Renamed many macros.
  • Renamed header files.
  • Made some changes to the packaging the installation procedure.

Renamed Macros. I renamed many macros defined in NTL header files.

The reason is that I want to minimize namespace pollution. Someday, NTL will be wrapped in a namespace, and when that happens the only remaining namespace pollution problems will be caused by macros. Eliminating all macros from NTL is not feasible. Instead, all NTL defined macros now begin with the prefix "NTL_", which reduces the namespace pollution to an ecceptable level. You will probably not be affected by this, unless you do some low level hacking using a macro like ZZ_NBITS (now called NTL_NBITS), or unless you create your own NTL vectors using a macro like ntl_vector_decl (now called NTL_vector_decl).

For a complete list of affected names, see names.txt.

Adapting to this name change should be painless, as there is a program to translate source files from the old naming convention to the new. The file "newnames.c", can be compiled as either a C or C++ program. The program is a "filter" that copies its input to its output, replacing all the old macro names by the new macro names.

In the WinNTL distribibution, "newnames.c" is called "newnames.cpp" and is located in the directory "newnames".

Renamed header files. The names of header files themeselves pollute another (extra-linguitsic) namespace. To alleviate this problem, the header files have been renamed. Instead of

   #include "foo.h"

one now should write

   #include <NTL/foo.h>

The only exceptions are the old header files "ntl_vector.h", "ntl_matrix.h", and "ntl_pair.h", which are now called <NTL/vector.h>, <NTL/matrix.h>, and <NTL/pair.h>.

Installation procedure. Now all NTL flags like NTL_LONG_LONG, NTL_AVOID_FLOAT, etc., can now be set by editing the special file "include/NTL/config.h". See details in that file. The reason for this change is that this allows all of these settings to be made when NTL is configured and built. Clients of NTL will then automatically use consistent settings. One should not set these flags on the compiler command line as previously.

Pentium/Linux people should no longer have to worry about the NTL_X86_FIX flag. NTL now psychically deduces the "right thing to do", although if its psychic abilities fail, you can override it with flags in "include/NTL/config.h".

The "packaging" in the Unix distribution is slightly different, but hopefully nicer. Among other things, the tar file now unpacks into a sub-directory of the current directory. See the unix installation section for more details. The Windows zip file now also unpacks into sub-directory.

My apologies. Although these changes are minor, they will cause some NTL users some inconvenience. I apologize for this. I really, really hope there are no more changes like this (see my roadmap of NTL's future).


Changes between NTL 3.1a and 3.1b

Defined functions div(GF2X,GF2X,GF2) and div(GF2X,GF2X,long), which had not been defined in earlier versions. Affected file: GF2X.c. Most programs never use this, and most linkers do not complain if these are missing (but some do).


Changes between NTL 3.0f and 3.1a

This version is backward compatible with previous versions.

  • Added floating point LLL routines based on Givens rotations, instead of classical Gramm-Schmidt orthogonalization. This is a more stable, but somewhat slower, method. See LLL.txt for details.
  • Added support for irreducible trinomials and pentanomials over GF(2). The GF2XModulus routines, and by extension, the GF2E routines, now exploit moduli of this special form. The new routine BuildSparseIrred in GF2XFactoring builds irreducibles of this form.
  • Also implemented a faster modular inversion routine for GF2X, and improved the performance of ZZ_pX multiplication for small degree polynomials.


Changes between NTL 3.0e and 3.0f

  • Fixed a bug (another one) affecting routines
       RandomBits, RandomBits_ZZ
    
    in module ZZ. Affected source file: lip.c.
  • Bug fix and performance tweak in ZZX factorizer. Affected source file: ZZXFactoring.c.


Changes between NTL 3.0 and 3.0e

  • Fixed a bug affecting routines
       RandomBits, RandomBits_ZZ, RandomBits_long
    
    in module ZZ. The only source files that are affected and require re-compilation are
       ZZ.c, lip.c
    
  • Note about names: 3.0a-c were "pre-releases", which makes the "first release" 3.0d, and hence this bug fix 3.0e.


Changes between NTL 2.0 and 3.0

  • Added functionality:

    • Added classes vec_GF2 and mat_GF2 for fast linear algebra over GF(2).
    • Added classes ZZ_pE, ZZ_pEX, zz_pE, zz_pEX, supporting polynomial arithmetic over extension rings/fields over prime fields.
    • Added John Abbott's pruning heuristic to the ZZX factoring routine.
    • Speeded up multiplication in zz_pX for small p (this also helps the ZZX factoring routine).
    • Added some some transcendental functions (e.g., exp, log, pi) to RR.
    • Added verbose mode and pruning to the XD and RR variants of LLL.

  • Improved programming interface: with this version, I've taken an the opportunity to give the programming interface a "professional facelift". In previous releases, I've tried to maintain backward compatability as much as possible, but to make the badly needed improvements to the interface that I've made with this release, this was not possible.

    NTL 3.0 is not backward compatable with NTL 2.0.

    I apologize to NTL users for this, but it is a bit of painful medicine that should only be necessary to take just this one time (but then as a C++ programmer, you must already be used to suffering ;-). Just about all of the incompatabilities are detectable by the compiler. See below for a detailed list of the changes and some tips on making the transition.

    The new interface is much more enjoyable to work with, and I don't foresee any changes to the interace in the future. Here is a broad overview of the changes:

    • Added functional/operator notation consistently throughout NTL, making it possible to write much more concise and readable code.
    • Got rid of automatic type conversions: these cause just too many problems. But I've overloaded all of the basic arithmetic operators and procedures so as to emulate a natural kind of "type promotion" logic. With these promotions, along with a full compliment of conversion functions, one hardly misses the automatic conversions.
    • Got rid of the macros
         vector(T), matrix(T), pair(T),
      
      which were causing too many name space problems.
    • Made assignment operators have the "correct" return type.
    • Introduced a more powerful and flexible mechanism for modulus changing.
    • Cleaned up numerous other minor problems.

Compatibility

Here is a detailed list of the changes to the programming interface.

  • The names of the classes
       BB, BB_p, BB_pX
    
    have been changed to
       GF2X, GF2E, GF2EX
    
  • There is also a class GF2 to represent GF(2). Many of the functions relating to BB, BB_p, BB_pX had argument and return-value types of type long that are now of the more appropriate type GF2. This change was needed so that the interface would be consistent with that of the new classes
       ZZ_pE, ZZ_pEX, zz_pE, zz_pEX.
    
  • The explicit conversion operator from GF2X (the new BB) to GF2EX (the new BB_pX) has different semantics: it now performs a coefficient lift, instead of creating a constant polynomial.
  • The conversion operator "<<" has been retired. Now instead of

       x << a; 

    one writes

       conv(x, a);

    Operator "<<" is now used for shift operations.

  • Every conversion routine now has a corresponding functional version which has the name to_T, where T is the result type. These new names replace old names that were less consistent. So instead of

       x = Long(a);

    one writes

       x = to_long(a);

  • The names of the routines
       ZZ_pInit, zz_pInit, zz_pFFTInit, GF2EInit
    
    have been changed to
       zz_p::init, zz_p::init, zz_p::FFTInit, GF2E::init
    
  • The names of the routines
       and, or, xor 
    
    for class ZZ have changed to
       bit_and, bit_or, bit_xor, 
    
    because the new C++ standard defines these as reserved words.
  • The function LowBits for ZZ is now called trunc.
  • Polynomial inversion mod X^n has changed from inv to InvTrunc.
  • Modular trace, norm, minimum polynomial and characteristic polynomial have changed from
       trace, norm, MinPoly, IrredPoly, CharPoly
    
    to
       TraceMod, NormMod, MinPolyMod, IrredPolyMod, CharPolyMod
    
  • For the class ZZX, the functions
       DivRem, div, rem, /, %, /=, %=
    
    have new semantics when dividing by non-monic polynomials. The old semantics are provided by new routines
       PseudoDivRem, PseudoDiv, PseudoRem.
    
  • The UpdateMap routines have slightly different semantics: in versions < 3.0, the output always had length n; now high-order zeroes are stripped.
  • The classes ZZ_pBak, zz_pBak, etc., have just slightly different semantics; I can't imagine any reasonable program detecting a difference.
  • The assignment operator and copy constructor for the class RR have different semantics: they now produce exact copies, instead of rounding to current precision.
  • All of the NTL compiler flags now start with NTL_ to avoid name space problems.
  • All of the files "zz_p.h", vec_zz_p.h", etc., have been eliminated. Use instead the names "lzz_p.h", "vec_lzz_p.h", etc.

Tips on making the transition

  • Apply this sed script to make most of the necessary syntactic changes.
  • Re-compile old NTL programs with the flag
       -DNTL_TRANSITION
    
    See flags.txt for details on how this will help your compiler detect remaining incompatabilities. In particular, any uses of operator << in its old role as a conversion operator will cause the compiler to raise an error. You can then convert all of these to the new notation.


Changes between NTL 1.7 and 2.0

  • Implementation of classes BB (polynomials over GF(2)) and BB_pX (polynomials over GF(2^n)).
  • A more consistent and natural interface, including arithmetic operators and a disciplined use of automatic conversion. So now one can write

       x = a * b + c;

    instead of

       mul(x, a, b);
       add(x, x, c);

    as one must in older versions of NTL. The operator notation leads to somewhat less efficient code, and one can always use the old notation in situations where efficiency is critical. Despite the new programming interface, care has been taken to ensure backward compitability; pre-existing programs that use NTL should still work.

  • Windows port.
  • Added compile-time flag that allows one to exploit "long long" data type if it exists (this especially helps on Pentium/Linux platforms).
  • Added compile-time flag to get better quad_float code on Pentium/Linux platforms.
  • A few bug fixes and performance tuning.


Changes between NTL 1.5 and NTL 1.7

  • Incorporation of Keith Briggs' quadratic precision package.
  • Much faster and more robust lattice basis reduction, including Schnorr-Horner "volume heuristic" for Block Korkin Zolotarev reductions, and a new quadratic precision LLL variant that is much more robust.
  • A few bug fixes.


Changes between NTL 1.0 and NTL 1.5

  • Implementation of Schnorr-Euchner algorithms for lattice basis reduction, including deep insertions and block Korkin Zolotarev reduction. These are significantly faster than the LLL algorithm in NTL 1.0.
  • Implementation of arbitrary-precision floating point.
  • Implementation of double precision with extended exponent range, which is useful for lattice basis reduction when the coefficients are large.
  • Faster polynomial multiplication over the integers, incorporating the Schoenhagge-Strassen method.
  • Compilation flags that increase performance on machines with poor floating-point performance.
  • Sundry performance tuning and a few bug fixes.
[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-ex1.html000644 000765 000024 00000056314 12377144460 015756 0ustar00shoupstaff000000 000000 A Tour of NTL: Examples: Big Integers
[Previous] [Up] [Next]

A Tour of NTL: Examples: Big Integers


The first example makes use of the class ZZ, which represents "big integers": signed, arbitrary length integers. This program reads two big integers a and b, and prints (a+1)*(b+1).

#include <NTL/ZZ.h>

using namespace std;
using namespace NTL;

int main()
{
   ZZ a, b, c; 

   cin >> a; 
   cin >> b; 
   c = (a+1)*(b+1);
   cout << c << "\n";
}

This program declares three variables a, b, and c of type ZZ. The values a and b are read from standard input. The value c is then computed as (a+1)*(b+1). Finally, the value of c is printed to the standard output.

Note that one can compute with ZZs much as with ordinary ints, in that most of the standard arithmetic and assignment operators can be used in a direct and natural way. The C++ compiler and the NTL library routines automatically take care of all the bookkeeping involved with memory management and temporary objects.

Note that by default, all of NTL's components are in the namespace NTL; with the "using directive"

   using namespace NTL;
in the above example, one can access these components directly. More details on namespaces and NTL here.


Here's a program that reads a list of integers from standard input and prints the sum of their squares.

#include <NTL/ZZ.h>


using namespace std;
using namespace NTL;


int main()
{
   ZZ acc, val;

   acc = 0;
   while (SkipWhiteSpace(cin)) {
      cin >> val;
      acc += val*val;
   }

   cout << acc << "\n";
}

The function SkipWhiteSpace is defined by NTL. It skips over white space, and returns 1 if there is something following it. This function is useful, because NTL's input operators raise an error if an input is missing or ill-formed. This is different from the standard I/O library, which does not raise an error. Personally, I find that not raising an error, or at least an exception, is a bad idea, since the caller of the I/O routine must constantly check the status of the input stream.


Here's a simple modular exponentiation routine for computing a^e mod n. NTL already provides a more sophisticated one, though.

ZZ PowerMod(const ZZ& a, const ZZ& e, const ZZ& n)
{
   if (e == 0return ZZ(1);

   long k = NumBits(e);

   ZZ res;
   res = 1;

   for (long i = k-1; i >= 0; i--) {
      res = (res*res) % n;
      if (bit(e, i) == 1) res = (res*a) % n;
   }

   if (e < 0)
      return InvMod(res, n);
   else
      return res;
}

Note that as an alternative, we could implement the inner loop as follows:

   res = SqrMod(res, n);
   if (bit(e, i) == 1) res = MulMod(res, a, n);

We could also write this as:

   SqrMod(res, res, n);
   if (bit(e, i) == 1) MulMod(res, res, a, n);

This illustrates an important point about NTL's programming interface. For every function in NTL, there is a procedural version that stores its result in its first argument. The reason for using the procedural variant is efficieny: on every iteration through the above loop, the functional form of SqrMod will cause a temporary ZZ object to be created and destroyed, whereas the procedural version will not create any temporaries. Where performance is critical, the procedural version is to be preferred. Although it is usually silly to get too worked up about performance, it may be reasonable to argue that modular exponentiation is an important enough routine that it should be as fast as possible.

Note that when the functional version of a function can be naturally named with an operator, this is done. So for example, NTL provides a 3-argument mul routine for ZZ multiplication, and a functional version whose name is operator *, and not mul.

While we are taking about temporaries, consider the first version of the inner loop. Execution of the statement

   res = (res*res) % n;

will result in the creation of two temporary objects, one for the product, and one for the result of the mod operation, whose value is copied into res. Of course, the compiler automatically generates the code for cleaning up temporaries and other local objects at the right time. The programmer does not have to worry about this.


This example is a bit more interesting. The following program prompts the user for an input, and applies a simple probabilistic primality test. Note that NTL already provides a slightly more sophisticated primality test.

#include <NTL/ZZ.h>

using namespace std;
using namespace NTL;

long witness(const ZZ& n, const ZZ& x)
{
   ZZ m, y, z;
   long j, k;

   if (x == 0return 0;

   // compute m, k such that n-1 = 2^k * m, m odd:

   k = 1;
   m = n/2;
   while (m % 2 == 0) {
      k++;
      m /= 2;
   }

   z = PowerMod(x, m, n); // z = x^m % n
   if (z == 1return 0;

   j = 0;
   do {
      y = z;
      z = (y*y) % n; 
      j++;
   } while (j < k && z != 1);

   return z != 1 || y != n-1;
}


long PrimeTest(const ZZ& n, long t)
{
   if (n <= 1return 0;

   // first, perform trial division by primes up to 2000

   PrimeSeq s;  // a class for quickly generating primes in sequence
   long p;

   p = s.next();  // first prime is always 2
   while (p && p < 2000) {
      if ((n % p) == 0return (n == p);
      p = s.next();  
   }

   // second, perform t Miller-Rabin tests

   ZZ x;
   long i;

   for (i = 0; i < t; i++) {
      x = RandomBnd(n); // random number between 0 and n-1

      if (witness(n, x)) 
         return 0;
   }

   return 1;
}

int main()
{
   ZZ n;

   cout << "n: ";
   cin >> n;

   if (PrimeTest(n, 10))
      cout << n << " is probably prime\n";
   else
      cout << n << " is composite\n";
}

Note that in NTL, there are typically a number of ways to compute the same thing. For example, consider the computation of m and k in function witness. We could have written it thusly:

   k = 1;
   m = n >> 1;
   while (!IsOdd(m)) {
      k++;
      m >>= 1;
   }

It turns out that this is actually not significantly more efficient than the original version, because the implementation optimizes multiplication and division by 2.

The following is more efficient:

   k = 1;
   while (bit(n, k) == 0) k++;
   m = n >> k;

As it happens, there is a built-in NTL routine that does just what we want:

   m = n-1;
   k = MakeOdd(m);


Having seen a number of examples involving ZZs, let's look at the ZZ interface in a bit more detail.

Constructors, assignment, and conversions

When you declare an object of type ZZ, the default constructor initializes to the value 0. As we have already seen, there is an assignment operator that allows one to copy the value of one ZZ to another. Note that these copies (like almost all copies in NTL) are "deep", i.e., the actual data is copied, and not just a pointer. Of course, if the amount of space allocated by the destination of the assignment is insufficient to hold the value of the source, space is automatically re-allocated.

One can also assign a value of type long to a ZZ:

   ZZ x;
   x = 1;

Note that one cannot write

   ZZ x = 1;  // error

to initialize a ZZ. Instead, one could write

   ZZ x = ZZ(1);
   ZZ y(1);
   ZZ z{1}; // C++11 only

Using the comstructor that allows one to explicitly construct a ZZ from a long.

Alternatively, one could write this as:

   ZZ x = conv<ZZ>(1);

This is an example of one of NTL's conversion routines. For very large constants, one can write:

   ZZ x = conv<ZZ>("99999999999999999999");

These examples illustrate conversion rountines in their functional forms.

   ZZ x;
   conv(x, 1);
   conv(x, "99999999999999999999");

Functionality

All of the basic arithmetic operators are supported, including comparison, arithmetic, shift, and bit-wise logical operations. One can mix ZZs and longs in any expresion in a natural way. NTL does not support implicit type conversion; rather, for basic operations, it simply overloads the operators or functions in a way to achieve a kind of "promotion logic": if one input is a ZZ and the other is a long (or something that implicitly converts to a long, like an int), the long input is effectively converted to a ZZ. Moreover, wherever possible, the implementation does this as efficiently as possible, and usually avoids the creation of a temporary ZZ.

There are also procedural versions for all the basic arithmetic operations:

   add, sub, negate, mul, sqr, div, rem, DivRem, 
   LeftShift, RightShift,
   bit_and, bit_or, bit_xor

There are many other routines. Here is a brief summary:

  • GCD -- computes greatest common divisor of two integers
  • XGCD -- extended Euclidean algorithm
  • AddMod, SubMod, NegateMod, MulMod, SqrMod, InvMod, PowerMod -- routines for modular arithmetic, including inversion and exponentiation
  • NumBits -- length of binary representation
  • bit -- extract a bit
  • ZZFromBytes, BytesFromZZ -- convert between octet strings and ZZs
  • RandomBnd, RandomBits, RandomLen -- routines for generating pseudo-random numbers
  • GenPrime, ProbPrime -- routines for generating primes and testing primality
  • power -- (non-modular) exponentiation
  • SqrRoot -- integer part of square root
  • Jacobi, SqrRootMod -- Jacobi symbol and modular square root

Most of these functions also have pure long versions as well, and as usual, there are both functional and procedural variants.

There are other functions as well. See ZZ.txt for complete details. Also see tools.txt for some basic services provided by NTL.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-ex2.html000644 000765 000024 00000030243 12377144460 015750 0ustar00shoupstaff000000 000000 A Tour of NTL: Examples: Vectors and Matrices
[Previous] [Up] [Next]

A Tour of NTL: Examples: Vectors and Matrices


The following routine sums up the numbers in a vector of ZZ's.

#include <NTL/ZZ.h>
#include <NTL/vector.h>

using namespace std;
using namespace NTL;

ZZ sum(const Vec<ZZ>& v)
{
   ZZ acc;

   acc = 0;

   for (long i = 0; i < v.length(); i++)
      acc += v[i];

   return acc;
}

The class Vec<ZZ> is a dynamic-length array of ZZs; more generally, NTL provides a template class Vec<T> for dynamic-length vectors over any type T. Some history is in order here. NTL predates the STL and the vector template found in modern C++. Older versions of NTL (prior to v6) did not use templates, but instead defined generic vectors using macros. By convention, NTL named these vec_T. For backward compatibility, NTL now provides typedefs all these "legacy" vector types.

Vectors in NTL are indexed from 0, but in many situations it is convenient or more natural to index from 1. The generic vector class allows for this; the above example could be written as follows.

#include <NTL/ZZ.h>
#include <NTL/vector.h>

using namespace std;
using namespace NTL;

ZZ sum(ZZ& s, const Vec<ZZ>& v)
{
   ZZ acc;

   acc = 0;

   for (long i = 1; i <= v.length(); i++)
      acc += v(i); 

   return acc;
}

Note that by default, NTL does not perform range checks on vector indices. However, there is a compile-time flag that activates range checking. Therefore, it is good practice to always assume that range checking may be activated, and to not access elements that are out of range.


The following example illustrates vector I/O, as well as changing the length of a vector. This program reads a Vec<ZZ>, and then creates and prints a "palindrome".

#include <NTL/ZZ.h>
#include <NTL/vector.h>

using namespace std;
using namespace NTL;

int main()
{
   Vec<ZZ> v;
   cin >> v;

   long n = v.length();
   v.SetLength(2*n);

   long i;
   for (i = 0 ; i < n; i++)
      v[n+i] = v[n-1-i];

   cout << v <&lt "\n";
}

Notice that changing the length of a vector does not change its contents.

When we compile and run this program, if we type in

   [1 -2 3]
as input, the output is
   [1 -2 3 3 -2 1]

See vector.txt for complete details of NTL's generic vector mechanism. Also note that for several fundamental vector types, such as Vec<ZZ>.txt, there is a corresponding header file <NTL/vec_ZZ.h> that defines a number of basic arithmetic operations, as well as provides the typedef typedef vec_ZZ for backward compatibilty. See vec_ZZ.txt for complete details on the arithmetic operations for Vec<ZZ>'s provided by NTL.


There is also basic support for matrices in NTL. In general, the class Mat<T> is a special kind of Vec< Vec< T > >, where each row is a vector of the same length. Row i of matrix M can be accessed as M[i] (indexing from 0) or as M(i) (indexing from 1). Column j of row i can be accessed as M[i][j] or M(i)(j); for notational convenience, the latter is equivalent to M(i,j).

Here is a matrix multiplication routine, which in fact is already provided by NTL.

#include <NTL/ZZ.h>
#include <NTL/matrix.h>

using namespace std;
using namespace NTL;

void mul(Mat<ZZ>& X, const Mat<ZZ>& A, const Mat<ZZ>& B)
{
   long n = A.NumRows();
   long l = A.NumCols();
   long m = B.NumCols();

   if (l != B.NumRows())
      Error("matrix mul: dimension mismatch");

   X.SetDims(n, m); // make X have n rows and m columns

   long i, j, k;
   ZZ acc, tmp;

   for (i = 1; i <= n; i++) {
      for (j = 1; j <= m; j++) {
         acc = 0;
         for(k = 1; k <= l; k++) {
            mul(tmp, A(i,k), B(k,j));
            add(acc, acc, tmp);
         }
         X(i,j) = acc;
      }
   }
}

In case of a dimension mismatch, the routine calls the Error function, which is a part of NTL and which simply prints the message and aborts. That is generally how NTL deals with errors.

This routine will not work properly if X aliases A or B. The actual matrix multiplication routine in NTL takes care of this. In fact, all of NTL's routines allow outputs to alias inputs.

To call NTL's built-in multiplication routine (declared in <NTL/mat_ZZ.h>), one can write

   mul(X, A, B);
or one can also use the operator notation
   X = A * B;

NTL provides several matrix types. See matrix.txt for complete details on NTL's generic matrix mechanism. Also see mat_ZZ.txt for complete details on the arithmetic operations for Mat<ZZ>'s provideed by NTL (including basic linear algebra). Also see LLL.txt for details on routines for lattice basis reduction (as well as routines for finding the kernel and image of a matrix).

One thing you may have noticed by now is that NTL code generally avoids the type int, preferring instead to use long. This seems to go against what most "style" books preach, but nevertheless seems to make the most sense in today's world. Although int was originally meant to represent the "natural" word size, this seems to no longer be the case. On 32-bit machines, int and long are the same, but on 64-bit machines, they are often different, with int's having 32 bits and long's having 64 bits. Indeed, there is a standard, called "LP64", which is being adopted by all Unix-like systems, and which specifies that on 64-bit machines, int's have 32 bits, and long's and pointers have 64 bits. Moreover, on such 64-bit machines, the "natural" word size is usually 64-bits; indeed, it is often more expensive to manipulate 32-bit integers. Thus, for simplicity, efficiency, and safety, NTL uses long for all integer values. If you are used to writing int all the time, it takes a little while to get used to this.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-ex3.html000644 000765 000024 00000026472 12377144460 015762 0ustar00shoupstaff000000 000000 A Tour of NTL: Examples: Polynomials
[Previous] [Up] [Next]

A Tour of NTL: Examples: Polynomials


NTL provides extensive support for very fast polynomial arithmetic. In fact, this was the main motivation for creating NTL in the first place, because existing computer algebra systems and software libraries had very slow polynomial arithmetic. The class ZZX represents univariate polynomials with integer coefficients. The following program reads a polynomial, factors it, and prints the factorization.

#include <NTL/ZZXFactoring.h>

using namespace std;
using namespace NTL;

int main()
{
   ZZX f;

   cin >> f;

   Vec< Pair< ZZX, long > > factors;
   ZZ c;

   factor(c, factors, f);

   cout << c << "\n";
   cout << factors << "\n";
}

When this program is compiled an run on input

   [2 10 14 6]
which represents the polynomial 2 + 10*X + 14*x^2 +6*X^3, the output is
   2
   [[[1 3] 1] [[1 1] 2]]
The first line of output is the content of the polynomial, which is 2 in this case as each coefficient of the input polynomial is divisible by 2. The second line is a vector of pairs, the first member of each pair is an irreducible factor of the input, and the second is the exponent to which is appears in the factorization. Thus, all of the above simply means that
2 + 10*X + 14*x^2 +6*X^3 = 2 * (1 + 3*X) * (1 + X)^2 

Admittedly, I/O in NTL is not exactly user friendly, but then NTL has no pretensions about being an interactive computer algebra system: it is a library for programmers.

In this example, the type Vec< Pair< ZZX, long > > is an NTL vector whose base type is Pair< ZZX, long >. The type Pair< ZZX, long > is the instantiation of a template "pair" type defined by NTL. See pair.txt for more details.


Here is another example. The following program prints out the first 100 cyclotomic polynomials.


#include <NTL/ZZX.h>

using namespace std;
using namespace NTL;

int main()
{
   Vec<ZZX> phi(INIT_SIZE, 100);  

   for (long i = 1; i <= 100; i++) {
      ZZX t;
      t = 1;

      for (long j = 1; j <= i-1; j++)
         if (i % j == 0)
            t *= phi(j);

      phi(i) = (ZZX(INIT_MONO, i) - 1)/t;  

      cout << phi(i) << "\n";
   }
}

To illustrate more of the NTL interface, let's look at alternative ways this routine could have been written.

First, instead of

   Vec<ZZX> phi(INIT_SIZE, 100);  

one can write

   Vec<ZZX> phi;
   phi.SetLength(100);

Second, instead of

            t *= phi(j);

one can write this as

            mul(t, t, phi(j));

or

            t = t * phi(j);

Also, one can write phi[j-1] in place of phi(j).

Third, instead of

      phi(i) = (ZZX(INIT_MONO, i) - 1)/t;  

one can write

      ZZX t1;
      SetCoeff(t1, i);
      SetCoeff(t1, 0, -1);
      div(phi(i), t1, t);

Alternatively, one could directly access the coefficient vector as follows:

      ZZX t1;
      t1.SetLength(i+1); // all vector elements are initialized to zero
      t1[i] = 1;
      t1[0] = -1;
      t1.normalize();  // not necessary here, but good practice in general
      div(phi(i), t1, t);

Generally, you can freely access the coefficient vector of a polynomial, as above. However, after fiddling with this vector, you should "normalize" the polynomial, so that the leading coefficient is non-zero: this is an invariant which all routines that work with polynomials expect to hold. Of course, if you can avoid directly accessing the coefficient vector, you should do so. You can always use the SetCoeff routine above to set or change coefficients, and you can always read the value of a coefficient using the routine coeff, e.g.,

   ... f[i] == 1 ...

is equivalent to

   ... coeff(f, i) == 1 ...

except that in the latter case, a read-only reference to zero is returned if the index i is out of range. There are also special-purpose read-only access routines LeadCoeff(f) and ConstTerm(f).

NTL provides a full compliment of arithmetic operations for polynomials over the integers, in both operator and procedural form. All of the basic operations support a "promotion logic" similar to that for ZZ, except that inputs of both types long and ZZ are promoted to ZZX. See ZZX.txt for details, and see ZZXFactoring.txt for details on the polynomial factoring routines.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-ex4.html000644 000765 000024 00000061637 12377144460 015765 0ustar00shoupstaff000000 000000 A Tour of NTL: Examples: Modular Arithmetic
[Previous] [Up] [Next]

A Tour of NTL: Examples: Modular Arithmetic


NTL also supports modular integer arithmetic. The class ZZ_p represents the integers mod p. Despite the notation, p need not in general be prime, except in situations where this is mathematically required. The classes Vec<ZZ_p> (a.k.a., vec_ZZ_p), Mat<ZZ_p> (a.k.a., mat_ZZ_p), and ZZ_pX represent vectors, matrices, and polynomials mod p, and work much the same way as the corresponding classes for ZZ.

Here is a program that reads a prime number p, and a polynomial f modulo p, and factors it.

#include <NTL/ZZ_pXFactoring.h>

using namespace std;
using namespace NTL;

int main()
{
   ZZ p;
   cin >> p;
   ZZ_p::init(p);

   ZZ_pX f;
   cin >> f;

   Vec< Pair< ZZ_pX, long > > factors;

   CanZass(factors, f);  // calls "Cantor/Zassenhaus" algorithm

   cout << factors << "\n";
    
}

As a program is running, NTL keeps track of a "current modulus" for the class ZZ_p, which can be initialized or changed using ZZ_p::init. This must be done before any variables are declared or computations are done that depend on this modulus.

Please note that for efficiency reasons, NTL does not make any attempt to ensure that variables declared under one modulus are not used under a different one. If that happens, the behavior of a program is completely unpredictable.


Here are two more examples that illustrate the ZZ_p-related classes. The first is a vector addition routine (already supplied by NTL):

#include <NTL/ZZ_p.h>

using namespace std;
using namespace NTL;

void add(Vec<ZZ_p>& x, const Vec<ZZ_p>& a, const Vec<ZZ_p>& b)
{
   long n = a.length();
   if (b.length() != n) Error("vector add: dimension mismatch");

   x.SetLength(n);
   long i;
   for (i = 0; i < n; i++)
      add(x[i], a[i], b[i]);
}

The second example is an inner product routine (also supplied by NTL):

#include <NTL/ZZ_p.h>

using namespace std;
using namespace NTL;

void InnerProduct(ZZ_p& x, const Vec<ZZ_p>& a, const Vec<ZZ_p>& b)
{
   long n = min(a.length(), b.length());
   long i;
   ZZ accum, t;

   accum = 0;
   for (i = 0; i < n; i++) {
      mul(t, rep(a[i]), rep(b[i]));
      add(accum, accum, t);
   }

   conv(x, accum);
}

This second example illustrates two things. First, it illustrates the use of function rep which returns a read-only reference to the representation of a ZZ_p as a ZZ between 0 and p-1. Second, it illustrates a useful algorithmic technique, whereby one computes over ZZ, reducing mod p only when necessary. This reduces the number of divisions that need to be performed significantly, leading to much faster execution.

The class ZZ_p supports all the basic arithmetic operations in both operator and procedural form. All of the basic operations support a "promotion logic", promoting long to ZZ_p.

Note that the class ZZ_p is mainly useful only when you want to work with vectors, matrices, or polynomials mod p. If you just want to do some simple modular arithemtic, it is probably easier to just work with ZZ's directly. This is especially true if you want to work with many different moduli: modulus switching is supported, but it is a bit awkward.

The class ZZ_pX supports all the basic arithmetic operations in both operator and procedural form. All of the basic operations support a "promotion logic", promoting both long and ZZ_p to ZZ_pX.

See ZZ_p.txt for details on ZZ_p; see ZZ_pX.txt for details on ZZ_pX; see ZZ_pXFactoring.txt for details on the routines for factoring polynomials over ZZ_p; see vec_ZZ_p.txt for details on mathematical operations on Vec<ZZ_p>'s; see mat_ZZ_p.txt for details on mathematical operations on Mat<ZZ_p>'s.


There is a mechanism for saving and restoring a modulus, which the following example illustrates. This routine takes as input an integer polynomial and a prime, and tests if the polynomial is irreducible modulo the prime.

#include <NTL/ZZX.h>
#include <NTL/ZZ_pXFactoring.h>

using namespace std;
using namespace NTL;

long IrredTestMod(const ZZX& f, const ZZ& p)
{
   ZZ_pPush push(p); // save current modulus and install p
                     // as current modulus

   return DetIrredTest(conv<ZZ_pX>(f));

   // old modulus is restored automatically when push is destroyed
   // upon return
}

The modulus switching mechanism is actually quite a bit more general and flexible than this example illustrates.

Noe the use of the conversion function conv<ZZ_pX>. We could also have used the equivalent procedural form:

   ZZ_pX f1;
   conv(f1, f);
   return DetIrredTest(f1);


Suppose in the above example that p is known in advance to be a small, single-precision prime. In this case, NTL provides a class zz_p, that acts just like ZZ_p, along with corresponding classes Vec<zz_p>, Mat<zz_p>, and zz_pX. The interfaces to all of the routines are generally identical to those for ZZ_p. However, the routines are much more efficient, in both time and space.

For small primes, the routine in the previous example could be coded as follows.

#include <NTL/ZZX.h>
#include <NTL/lzz_pXFactoring.h>

using namespace std;
using namespace NTL;

long IrredTestMod(const ZZX& f, long p)
{
   zz_pPush push(p);
   return DetIrredTest(conv<zz_pX>(f));
}


The following is a routine (essentially the same as implemented in NTL) for computing the GCD of polynomials with integer coefficients. It uses a "modular" approach: the GCDs are computed modulo small primes, and the results are combined using the Chinese Remainder Theorem (CRT). The small primes are specially chosen "FFT primes", which are of a special form that allows for particular fast polynomial arithmetic.

#include <NTL/ZZX.h>

using namespace std;
using namespace NTL;

void GCD(ZZX& d, const ZZX& a, const ZZX& b)
{
   if (a == 0) {
      d = b;
      if (LeadCoeff(d) < 0) negate(d, d);
      return;
   }

   if (b == 0) {
      d = a;
      if (LeadCoeff(d) < 0) negate(d, d);
      return;
   }

   ZZ c1, c2, c;
   ZZX f1, f2;

   content(c1, a);
   divide(f1, a, c1);

   content(c2, b);
   divide(f2, b, c2);

   GCD(c, c1, c2);

   ZZ ld;
   GCD(ld, LeadCoeff(f1), LeadCoeff(f2));

   ZZX g, res;

   ZZ prod;

   zz_pPush push(); // save current modulus, restore upon return

   long FirstTime = 1;

   long i;
   for (i = 0; ;i++) {
      zz_p::FFTInit(i);
      long p = zz_p::modulus();

      if (divide(LeadCoeff(f1), p) || divide(LeadCoeff(f2), p)) continue;

      zz_pX G, F1, F2;
      zz_p  LD;

      conv(F1, f1);
      conv(F2, f2);
      conv(LD, ld);

      GCD(G, F1, F2);
      mul(G, G, LD);


      if (deg(G) == 0) { 
         res = 1;
         break;
      }

      if (FirstTime || deg(G) < deg(g)) {
         prod = 1;
         g = 0;
         FirstTime = 0;
      }
      else if (deg(G) > deg(g)) {
         continue;
      }

      if (!CRT(g, prod, G)) {
         PrimitivePart(res, g);
         if (divide(f1, res) && divide(f2, res))
            break;
      }

   }

   mul(d, res, c);
   if (LeadCoeff(d) < 0) negate(d, d);
}

See lzz_p.txt for details on zz_p; see lzz_pX.txt for details on zz_pX; see lzz_pXFactoring.txt for details on the routines for factoring polynomials over zz_p; see vec_lzz_p.txt for details on vec_zz_p; see mat_lzz_p.txt for details on mat_zz_p.


NTL provides a number of "residue class" types with a dynamic modulus stored as a global variable: the types ZZ_p and zz_p, discussed above, as well as the types ZZ_pE, zz_pE, and GF2E, discussed later.

Some caution must be used so that a variable constructed under one modulus is not used "out of context", when a different modulus, or perhaps no modulus, is installed as the current modulus. While arithmetic operations should certainly be avoided, NTL does take care to allow for certain operations to be safely performed "out of context". These operations include default and copy constructors, as well as assignment.


Arithmetic mod 2 is such an important special case that NTL provides a class GF2, that acts just like ZZ_p when p == 2, along with corresponding classes Vec<GF2>, Mat<GF2>, and GF2X. The interfaces to all of the routines are generally identical to those for ZZ_p. However, the routines are much more efficient, in both time and space. Note that Vec<GF2> is an explicit specialization of the template class Vec<T>, with a special implementation that packs the coefficients into the bits of a machine word. You need to include the header file <NTL/vec_GF2.h> to use the class Vec<GF2>.

This example illustrates the GF2X and Mat<GF2> classes with a simple routine to test if a polynomial over GF(2) is irreducible using linear algebra. NTL's built-in irreducibility test is to be preferred, however.

#include <NTL/GF2X.h>
#include <NTL/mat_GF2.h>

using namespace std;
using namespace NTL;

long MatIrredTest(const GF2X& f)
{
   long n = deg(f);

   if (n <= 0return 0;
   if (n == 1return 1;

   if (GCD(f, diff(f)) != 1return 0;

   Mat<GF2> M;

   M.SetDims(n, n);

   GF2X x_squared = GF2X(INIT_MONO, 2);

   GF2X g;
   g = 1;

   for (long i = 0; i < n; i++) {
      VectorCopy(M[i], g, n);
      M[i][i] += 1;
      g = (g * x_squared) % f;
   }

   long rank = gauss(M);

   if (rank == n-1)
      return 1;
   else
      return 0;
}

Note that the statement

   g = (g * x_squared) % f;

could be replace d by the more efficient code sequence

   MulByXMod(g, g, f);
   MulByXMod(g, g, f);

but this would not significantly impact the overall running time, since it is the Gaussian elimination that dominates the running time.

See GF2.txt for details on GF2; see GF2X.txt for details on GF2X; see GF2XFactoring.txt for details on the routines for factoring polynomials over GF2; see vec_GF2.txt for details on vec_GF2; see mat_GF2.txt for details on mat_GF2.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-ex5.html000644 000765 000024 00000013066 12377144460 015757 0ustar00shoupstaff000000 000000 A Tour of NTL: Examples: Extension Rings and Fields
[Previous] [Up] [Next]

A Tour of NTL: Examples: Extension Rings and Fields


NTL also supports extension rings and fields over finite fields, and polynomial arithmetic over such extensions. Here is a little program that illustrates this.

#include <NTL/ZZ_pXFactoring.h>
#include <NTL/ZZ_pEX.h>

NTL_CLIENT

int main()
{
   ZZ_p::init(ZZ(17)); // define GF(17)

   ZZ_pX P;
   BuildIrred(P, 10); // generate an irreducible polynomial P
                      // of degree 10 over GF(17)

   ZZ_pE::init(P); // define GF(17^10)

   ZZ_pEX f, g, h;  // declare polynomials over GF(17^10)

   random(f, 20);  // f is a random, monic polynomial of degree 20
   SetCoeff(f, 20);

   random(h, 20); // h is a random polynomial of degree less than 20

   g = MinPolyMod(h, f); // compute the minimum polynomial of h modulo f

   if (g == 0) Error("oops (1)"); // check that g != 0

   if (CompMod(g, h, f) != 0// check that g(h) = 0 mod f
      Error("oops (2)");
}

This example illustrates building extension rings over ZZ_p. One can also use zz_p and GF2 as base classes; the syntax is exactly the same.

See ZZ_pE.txt for the basics of the extension ring ZZ_pE over ZZ_p. Also see ZZ_pEX.txt for polynomial arithmetic over ZZ_pE, and ZZ_pEXFactoring.txt for factoring routines over ZZ_pE. See vec_ZZ_pE.txt for vectors over ZZ_pE, and mat_ZZ_pE.txt for matrices over ZZ_pE.

See lzz_pE.txt for the basics of the extension ring zz_pE over zz_p. Also see lzz_pEX.txt for polynomial arithmetic over zz_pE, and lzz_pEXFactoring.txt for factoring routines over zz_pE. See vec_lzz_pE.txt for vectors over zz_pE, and mat_lzz_pE.txt for matrices over zz_pE.

See GF2E.txt for the basics of the extension ring GF2E over GF2. Also see GF2EX.txt for polynomial arithmetic over GF2E, and GF2EXFactoring.txt for factoring routines over GF2E. See vec_GF2E.txt for vectors over GF2E, and mat_GF2E.txt for matrices over GF2E.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-ex6.html000644 000765 000024 00000007416 12377144460 015762 0ustar00shoupstaff000000 000000 A Tour of NTL: Examples: Floating Point Classes
[Previous] [Up] [Next]

A Tour of NTL: Examples: Floating Point Classes


NTL also supports arbitrary precision floating point with the class RR. Additionally, it supports two specialized classes: quad_float, which gives a form of quadruple precision, but without an extended exponent range, and xdouble, which gives double precision, but with an extended exponent range. The advantage of the latter two classes is efficiency.

Here again is a program that reads a list of numbers from the input, and outputs the sum of their squares, using the class RR.

#include <NTL/RR.h>

int main()
{
   RR acc, val;

   acc = 0;
   while (SkipWhiteSpace(cin)) {
      cin >> val;
      acc += val*val;
   }

   cout << acc << "\n";
}

The precision used for the computation can be set by executing

   RR::SetPrecision(p);

which sets the effective precision to p bits. By default, p=150. All of the basic arithmetic operations compute their results by rounding to the nearest p-bit floating point number. The semantics of this are exactly the same as in the IEEE floating point standard (except that there are no special values, like "infinity" and "not a number").

The number of decimal digits of precision that are used when printing an RR can be set be executing

   RR::SetOutputPrecision(d);

which sets the output precision to d. By default, d=10.

See RR.txt for details.

By replacing the occurences of RR by either quad_float or xdouble, one gets an equivalent program using one of the other floating point classes. The output precision for these two classes can be controlled just as with RR. See quad_float.txt and xdouble.txt for details.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-examples.html000644 000765 000024 00000001672 12377144460 017074 0ustar00shoupstaff000000 000000 A Tour of NTL: Examples
[Previous] [Up] [Next]

A Tour of NTL: Examples


Perhaps the best way to introduce the basics of NTL is by way of example. Browse the following for a number of examples that illustrate some aspects of the functionality and programming interface of NTL.

  1. Big Integers
  2. Vectors and Matrices
  3. Polynomials
  4. Modular Arithmetic
  5. Extension Rings and Fields
  6. Floating Point Classes
ntl-6.2.1/doc/tour-gf2x.html000644 000765 000024 00000011034 12377144460 016115 0ustar00shoupstaff000000 000000 A Tour of NTL: Using NTL with the gf2x library
[Previous] [Up] [Next]

A Tour of NTL: Using NTL with the GF2X library


gf2x is a library for fast multiplication of polynomials over GF(2). The gf2x library was developed by Emmanuel Thomé, Paul Zimmermmann, Pierrick Gaudry, and Richard Brent. You can get more information about it, as well as the latest version from here.

Unlike NTL, which only imlements a version of Karatsuba multiplication, gf2x implements other algorithms that are faster for very large degree polynomials. If you use NTL if the gf2x library, then multiplication, division, GCD, and minimum polynomal calculations for the GF2X class will be faster for large degree polymials.

Downloading and building gf2x

Download gf2x from here. You will get a file gf2x-XXX.tar.gz.

Now do the following:

   % gunzip gf2x-XXX.tar.gz
   % tar xf gf2x-XXX.tar
   % cd gf2x-XXX
   % ./configure --prefix=$HOME/sw
   % make
   % make check
   % make install
This will build, test, and install gf2x in $HOME/sw. Of course, change $HOME/sw to whatever you want (the default is /usr/local). You will find the gf2x header files in $HOME/sw/include and the compiled binaries in $HOME/sw/lib.

You can also supply the option --disable-shared to the configure script, if you only want static libraries. However, if you ultimately want to build NTL as a shared library, then you must also buld gf2x as a shared library.

You must ensure that NTL and gf2x have the same ABI. gf2x's configuration script might need some help to select the right one. For example, you may have to pass

   ABI=64 CFLAGS="-m64 -O2"
to gf2x's configure script to force a 64-bit ABI.

Building and using NTL with gf2x

When building NTL with gf2x, you have to tell NTL that you want to use it. The easiest way to do this is by passing the argument NTL_GF2X_LIB=on to the NTL configuration script when you are installing NTL. Assuming you installed gf2x in $HOME/sw as above, and you also want to install NTL in $HOME/sw, you execute:

   % ./configure PREFIX=$HOME/sw NTL_GF2X_LIB=on  GF2X_PREFIX=$HOME/sw
You can write this more simply as
   % ./configure DEF_PREFIX=$HOME/sw NTL_GF2X_LIB=on 
Here, DEF_PREFIX is a variable that is used to specify the location of all software, and it defaults to /usr/local.

If you installed gf2x in /usr/local (or some other standard system directory where your compiler will look by default) then simply

   % ./configure PREFIX=$HOME/sw NTL_GF2X_LIB=on
does the job. Moreover, if NTL is also to be installed in /usr/local, then
   % ./configure NTL_GF2X_LIB=on
does the job.

Instead of passing arguments to the configure script, you can also just edit the config.h and makefile by hand. The documentation in these files should be self-explanatory.

When compiling programs that use NTL with gf2x, you need to link with the gf2x library. If gf2x is installed as above in $HOME/sw, rather than in a standard system directory, this just means adding -L$HOME/sw/lib -lgf2x to the compilation command. If you installed gf2x in a standard system directory, then just -lgf2x does the job. Note that -lgf2x must come after -lntl on the command line. Finally, if NTL and gf2x are installed as shared libraries, then you don't even need -lgf2x.


[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-gmp.html000644 000765 000024 00000021037 12377144460 016036 0ustar00shoupstaff000000 000000 A Tour of NTL: Using NTL with GMP
[Previous] [Up] [Next]

A Tour of NTL: Using NTL with GMP


GMP is the GNU Multi-Precision library. You can get more information about it, as well as the latest version from here.

Briefly, GMP is a library for long integer arithmetic. It has hand-crafted assembly routines for a wide variety of architectures. For basic operations, like integer multiplication, it can be two to three (and sometimes bit more) times faster than NTL's traditional long integer package. The speedup is most dramatic on x86 machines.

By default, NTL uses a long integer package derived from Arjen Lenstra's LIP package. However, for extra speed, it is recommended to use GMP. Building NTL with GMP takes a few extra minutes work, and you certainly do not need to use NTL with GMP if you don't want to. As far as I know, GMP is only available on Unix systems and on Windows systems using Cygwin tools.

Even if you do not use GMP, you should still read the section below on backward compatabilty so that you can write portable code and avoid deprecated constructs.

Downloading and building GMP

Download GMP from here. You will get a file gmp-XXX.tar.gz.

Now do the following:

   % gunzip gmp-XXX.tar.gz
   % tar xf gmp-XXX.tar
   % cd gmp-XXX
   % ./configure --prefix=$HOME/sw
   % make
   % make check
   % make install
This will build, test, and install GMP in $HOME/sw. Of course, change $HOME/sw to whatever you want (the default is /usr/local). You will find the GMP header files in $HOME/sw/include and the compiled binaries in $HOME/sw/lib.

You can also supply the option --disable-shared to the configure script, if you only want static libraries. However, if you ultimately want to build NTL as a shared library, then you must also buld GMP as a shared library.

You must ensure that NTL and GMP have the same ABI. Usually, GMP's configure script will automatically choose a 64-bit ABI if available.

Building and using NTL with GMP

When building NTL with GMP, you have to tell NTL that you want to use GMP as the long integer package, and where the include files and library are. The easiest way to do this is by passing the argument NTL_GMP_LIP=on to the NTL configuration script when you are installing NTL. Assuming you installed GMP in $HOME/sw as above, and you also want to install NTL in $HOME/sw, you execute:

   % ./configure PREFIX=$HOME/sw NTL_GMP_LIP=on  GMP_PREFIX=$HOME/sw
You can write this more simply as
   % ./configure DEF_PREFIX=$HOME/sw NTL_GMP_LIP=on 
Here, DEF_PREFIX is a variable that is used to specify the location of all software, and it defaults to /usr/local.

If you installed GMP in /usr/local (or some other standard system directory where your compiler will look by default) then simply

   % ./configure PREFIX=$HOME/sw NTL_GMP_LIP=on
does the job. Moreover, if NTL is also to be installed in /usr/local, then
   % ./configure NTL_GMP_LIP=on
does the job.

Instead of passing arguments to the configure script, you can also just edit the config.h and makefile by hand. The documentation in these files should be self-explanatory.

When compiling programs that use NTL with GMP, you need to link with the GMP library. If GMP is installed as above in $HOME/sw, rather than in a standard system directory, this just means adding -L$HOME/sw/lib -lgmp to the compilation command. If you installed GMP in a standard system directory, then just -lgmp does the job. Note that -lgmp must come after -lntl on the command line. Finally, if NTL is installed a shared libraries, then you don't even need -lgmp.

NTL has been tested and works correctly with GMP versions 3.1, 3.1.1, 4.1.4, and 5.1 (among others). It is not possible to use versions of GMP prior to 3.1 with NTL.

When using NTL with GMP, as a user of NTL, you do not need to know or understand anything about the the GMP library. So while there is detailed documentation available about how to use GMP, you do not have to read it. The programming interface to the long integer package completely hides implementation details.

Backward compatbility

With version 5.0 of NTL, some aspects of the programming interface are 'deprecated' so as to allow the use of another long integer package, such as GMP, as the long integer package.

Prior to version 5.0, the macro NTL_NBITS was defined, along with the macro NTL_RADIX defined to be (1L << NTL_NBITS). While these macros are still available when using NTL's traditional long integer package (i.e., when NTL_GMP_LIP is not set), they are not available when using the GMP as the long integer package (i.e., when NTL_GMP_LIP is set). Furthermore, when writing portable programs, one should avoid these macros.

Also, the static function long ZZ::digit(const ZZ &, long); is defined when using traditional long integer arithmetic, but is not available when using GMP as the long integer package, and in any case, its use should be avoided when writing portable programs.

Instead of the above macros, one should use the followng macros:

   NTL_ZZ_NBITS -- number of bits in a zzigit;
                   a ZZ is represented as a sequence of zzigits.

   NTL_SP_NBITS -- max number of bits in a "single-precision" number

   NTL_WSP_NBITS -- max number of bits in a "wide single-precision" number

The following relations hold:

   NTL_SP_NBITS <= NTL_WSP_NBITS <= NTL_ZZ_NBITS
   26 <= NTL_SP_NBITS <= min(NTL_BITS_PER_LONG-2, NTL_DOUBLE_PRECISION-3)
   NTL_WSP_NBITS <= NTL_BITS_PER_LONG-2

Note that NTL_ZZ_NBITS may be less than, equal to, or greater than NTL_BITS_PER_LONG -- no particular relationship should be assumed to hold. In particular, expressions like (1L << NTL_ZZ_BITS) might overflow.

"single-precision" numbers are meant to be used in conjunction with the single-precision modular arithmetic routines.

"wide single-precision" numbers are meant to be used in conjunction with the ZZ arithmetic routines for optimal efficiency.

Note that when using traditional long integer arithmetic, we have

    NTL_ZZ_NBITS = NTL_SP_NBITS = NTL_WSP_NBITS = NTL_NBITS.

The following auxilliary macros are also defined:

NTL_FRADIX -- double-precision value of 2^NTL_ZZ_NBITS
NTL_SP_BOUND -- (1L << NTL_SP_NBITS)
NTL_WSP_BOUND -- (1L << NTL_WSP_NBITS)

Note that for a ZZ n, n.size() returns the number of "zzigits" of n. This is supported with either traditional or GMP integer arithemtic. Note, however, that some old codes might write n.size() <= 1 as a way to test if NumBits(n) <= NTL_NBITS. This is no longer the right thing to do, if one wants portable code that works with either traditional or GMP long integer arithmetic. First, one has to decide whether one wants to test if NumBits(n) is bounded by NTL_ZZ_NBITS, NTL_SP_NBITS, or NTL_WSP_NBITS. In the first case, n.size() <= 1 is still the right way to test this. In the second case, write this as n.SinglePrecision(). In the third case, write this as n.WideSinglePrecision(). The routines SinglePrecision and WideSinglePrecision are new to NTL version 5.0.

Most "high level" applications that use NTL should not be affected by these changes to NTL's programming interface, and if they are, changing the programs should be quite easy.


[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-impl.html000644 000765 000024 00000030026 12377144460 016212 0ustar00shoupstaff000000 000000 A Tour of NTL: NTL Implementation and Portability
[Previous] [Up] [Next]

A Tour of NTL: NTL Implementation and Portability


NTL is designed to be portable, fast, and relatively easy to use and extend.

To make NTL portable, no assembly code is used (well, almost none, see below). This is highly desirable, as architectures are constantly changing and evolving, and maintaining assembly code is quite costly. By avoiding assembly code, NTL should remain usable, with virtually no maintenance, for many years.

Minimal platform requirements

When the configuration flags NTL_CLEAN_INT and NTL_CLEAN_PTR are both on (this is not the default, see below), NTL makes two requirements of its platform, neither of which are guaranteed by the C++ language definition, but are essentially universal:
  1. int and long quantities, respectively, are represented using a 2's complement representation whose width is equal to the width of unsigned int and unsigned long, respectively.
  2. Double precision floating point conforms to the IEEE floating point standard.

NTl makes very conservative requirements of the C/C++ compiler:

  • it is assumed that the C compiler conforms to the original ANSI C standard,
  • it is assumed that the C++ compiler supports all of the language features described in the second edition of Stroustrup's book, minus exceptions, templates, and derived types.

The NTL_CLEAN_INT flag

The configuration flag NTL_CLEAN_INT is currently off by default.

When this flag is off, NTL makes another requirement of its platform; namely, that arithmetic operations on the type long do not overflow, but simply "wrap around" modulo the word size. This behavior is not guaranteed by the C++ standard, and yet it is essentially universally implemented. In fact, most compilers will go out of their way to ensure this behavior, since it is a very reasonable behavior, and since many programs implicitly rely on this behavior.

Making this "wrap around" assumption can lead to slightly more efficient code on some platforms. It seems fairly unlikely that one would ever have to turn the NTL_CLEAN_INT flag on, but it seems a good idea to make this possible, and at the very least to identify and isolate the code that relies on this assumption.

Actually, with NTL_CLEAN_INT off, it is also assumed that right shifts of signed integers are consistent, in the sense that if it is sometimes an arithmetic shift, then it is always an arithmetic shift (the installation scripts check if right shift appears to be arithmetic, and if so, this assumption is made elsewhere).

It is hard to imagine that there is a platform existing today (or in the foreseeable future) where these assumptions are not meet. However, as of version 5.4 of NTL, all of the most performance-critical code now works almost as well with NTL_CLEAN_INT set as without. The differences are not very significant (maybe 10%). Therefore, there is hardly any reason to not set this flag. Also, note that the only code affected by this flag is the traditional long integer package (which, if you use GMP as the long integer package, is not involved), and the single-precision modular multiplication routines defined in ZZ.h.

The NTL_CLEAN_PTR flag

The configuration flag NTL_CLEAN_PTR is currently off by default.

When this flag is off, NTL makes another requirement of its platform; namely, that the address space is "flat", and in particular, that one can test if an object pointed to by a pointer p is located in a array of objects v[0..n-1] by testing if p >= v and p < v + n. The C++ standard does not guarantee that such a test will work; the only way to perform this test in a standard-conforming way is to iteratively test if p == v, p == v+1, etc.

This assumption of a "flat" address space is essentially universally valid, and making this assumption leads to some more efficient code. For this reason, the NTL_CLEAN_PTR is off by default, but one can always turn it on, and in fact, the overall performance penalty should be negligible for most applications.

Some floating point issues

NTL uses floating point arithmetic in a number of places, including a number of exact computations, where one might not expect to see floating point. Relying on floating point may seem prone to errors, but with the guarantees provided by the IEEE standard, one can prove the correctness of the NTL code that uses floating point.

Briefly, the IEEE floating point standard says that basic arithmetic operations on doubles should work as if the operation were performed with infinite precision, and then rounded to p bits, where p is the precision (typically, p = 53).

Throughout most of NTL, correctness follows from weaker assumptions, namely

  • basic arithmetic operations and conversion from integral types produce results with a relative error of 2^{-p + 1} (assuming no overflow),
  • multiplication by powers of 2 produce exact results (assuming no overflow),
  • basic arithmetic operations on integers represented as doubles and conversions from integral types to doubles produce exact results, provided the inputs and outputs are less than 2^p in absolute value,
  • if y/2 <= x <= 2y, then x-y is computed exactly.
Also, NTL allows the compiler to compute z = x/y as t = 1/y, z = t*x.

It is also generally assumed that the compiler does not do too much "regrouping" of arithmetic expressions involving floating point. Most compilers respect the implied grouping of floating point computations, and NTL goes out of its way to make its intentions clear: instead of x = (a + b) + c, if the grouping is truly important, this is written as t = a + b; x = t + c. Current standards do not allow, and most implementations will not perform, any regrouping of this, e.g., x = a + (b + c), since in floating point, addition and subtraction are not associative.

Unfortunately, some compilers do not do this correctly, unless you tell them. With Intel's C compiler icc, for example, you should compile NTL with the flag -fp-model source to enforce strict adherence to floating point standards. Also, you should be wary of compiling using an optimization level higher than the default -O2 -- this may break some floating point assumptions (and maybe some other assumptions as well).

One big problem with the IEEE standard is that it allows intermediate quantities to be computed in a higher precision than the standard double precision. This "looseness" in the standard is a substantial impediment to creating portable software. Most platforms today implement the "strict" IEEE standard, with no excess precision. One notable exception -- the 800 pound gorilla, so to speak -- is the Intel x86.

NTL goes out of its way to ensure that its code is correct with both "strict" and "loose" IEEE floating point. This is achieved in a portable fashion throughout NTL, except for the quad_float module, where some desperate hacks, including assembly code, may be used to try to work around problems created by "loose" IEEE floating point [more details]. But note that even if the quad_float package does not work correctly because of these problems, the only other routines that are affected are the LLL_QP routines in the LLL module -- the rest of NTL should work fine.

Mostly, NTL does not require that the IEEE floating point special quantities "infinity" and "not a number" are implemented correctly. This is certainly the case for core code where floating point arithmetic is used for exact (but fast) computations, as the numbers involved never get too big (or small). However, the behavior of certain explicit floating point computations (e.g., the xdouble and quad_float classes, and the floating point versions of LLL) will be much more predictable and reliable if "infinity" and "not a number" are implemented correctly.

Implementing long integer arithmetic

There are three basic strategies for implementing long integer arithmetic.

The default strategy is implemented in the traditional long integer arithmetic package. This package is derived from the LIP package originally developed by A. K. Lenstra, although it has evolved quite a bit within NTL. This package uses no assembly code and is very portable.

The alternative strategy is to use GMP in place of LIP. In this strategy, the representation of long integers is in a form compatible with GMP. This strategy typically yields the best performance, but requires that GMP is installed on your platform.

Go here for more details on the use of GMP with NTL.

Algorithms

NTL makes fairly consistent use of asymptotically fast algorithms.

Long integer multiplication is implemented using the classical algorithm, crossing over to Karatsuba for very big numbers. Long integer division is currently only implemented using the classical algorithm -- unless you use NTL with GMP (version 3 or later), which employs an algorithm that is about twice as slow as multiplication for very large numbers.

Polynomial multiplication and division is carried out using a combination of the classical algorithm, Karatsuba, the FFT using small primes, and the FFT using the Schoenhagge-Strassen approach. The choice of algorithm depends on the coefficient domain.

Many algorithms employed throughout NTL are inventions of the author (Victor Shoup) and his colleagues Joachim von zur Gathen and Erich Kaltofen, as well as John Abbott and Paul Zimmermann.

Some of NTL's imperfections

NTL is not a "perfect" library. Here are some limitations of NTL that a "perfect" library would not have:

  • NTL is currently not thread safe, but I am in the process of making it so. This will hopefully happen some time before summer 2015.

  • NTL provides only a very crude form of error handling: print an error message and abort. For most NTL users, this is quite sufficient. The alternative would be to have NTL throw exceptions. Writing code that handles exceptions correctly is quite difficult. The easy part is throwing and catching exceptions. The hard part is writing code through which an exception can be safely and correctly thrown. Retrofitting NTL to throw exceptions at this late date would be quite difficult and error prone, and I do not think that there is much demand for it.

  • NTL does not release all of its resources. There are some routines which for efficiency reasons will allocate some memory and never give it back to the system, so as to avoid re-allocations on subsequent calls. The amount of memory "stolen" by NTL in this way is fairly reasonable, and I have heard no complaints yet about its effects.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-intro.html000644 000765 000024 00000007021 12377144460 016403 0ustar00shoupstaff000000 000000 A Tour of NTL: Introduction
[Previous] [Up] [Next]

A Tour of NTL: Introduction


NTL is a high-performance, portable C++ library providing data structures and algorithms for arbitrary length integers; for vectors, matrices, and polynomials over the integers and over finite fields; and for arbitrary precision floating point arithmetic.

NTL provides high quality implementations of state-of-the-art algorithms for:

  • arbitrary length integer arithmetic and arbitrary precision floating point arithmetic;
  • polynomial arithmetic over the integers and finite fields including basic arithmetic, polynomial factorization, irreducibility testing, computation of minimal polynomials, traces, norms, and more;
  • lattice basis reduction, including very robust and fast implementations of Schnorr-Euchner, block Korkin-Zolotarev reduction, and the new Schnorr-Horner pruning heuristic for block Korkin-Zolotarev;
  • basic linear algebra over the integers, finite fields, and arbitrary precision floating point numbers.

NTL's polynomial arithmetic is one of the fastest available anywhere, and has been used to set "world records" for polynomial factorization and determining orders of elliptic curves.

NTL's lattice reduction code is also one of the best available anywhere, in terms of both speed and robustness, and one of the few implementations of block Korkin-Zolotarev reduction with the Schnorr-Horner pruning heuristic. It has been used to "crack" several cryptosystems.

NTL can be easily installed in a matter of minutes on just about any platform, including virtually any 32- or 64-bit machine running any flavor of Unix, as well as PCs running Windows 95, 98, or NT, and Macintoshes. NTL achieves this portability by avoiding esoteric C++ features, and by avoiding assembly code; it should therefore remain usable for years to come with little or no maintenance, even as processors and operating systems continue to change and evolve. However, NTL can be used in conjunction with GMP (the GNU Multi-Precision library) for enhanced performance. NTL can also be used in conjunction with the gf2x library for faster arithmetic of large degree polynomials over GF(2).

NTL provides a clean and consistent interface to a large variety of classes representing mathematical objects. It provides a good environment for easily and quickly implementing new number-theoretic algorithms, without sacrificing performance.

NTL is written and maintained by Victor Shoup with some contributions made by others (see Acknowledgements).

Legalistic Nonsense

NTL is free software, and may be used according to the terms of the GNU General Public License.

[the precise licensing information of NTL]

[more information about the GNU General Public License]

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-modules.html000644 000765 000024 00000043722 12377144460 016730 0ustar00shoupstaff000000 000000 A Tour of NTL: Summary of NTL's Main Modules
[Previous] [Up] [Next]

A Tour of NTL: Summary of NTL's Main Modules


NTL consists of a number of software modules. Generally speaking, for each module foo, there is

  • a header file <NTL/foo.h>, found in subdirectory include,
  • a documentation file foo.txt, found in subdirectory doc, and
  • a source file foo.c, found in subdirectory src.

Note that all of the header files for NTL modules include the header file <NTL/tools.h>, and by default, this header file includes the standard headers

  • <cstdlib>,
  • <cmath>, and
  • <iostream>.
Moreover, the standard library is wrapped in namespace std and NTL is wrapped in namespace NTL.

However, if you compiled NTL in traditional (non-ISO mode), then <NTL/tools.h> includes the traditional (pre-ISO) headers

  • <stdlib.h>,
  • <math.h>, and
  • <iostream.h>.
Moreover, all of names of the standard library and NTL are defined in the global namespace.

The documentation file takes the form of a header file, but stripped of implementation details and declarations of some of the more esoteric routines and data structures, and it contains more complete and usually clearer documentation than in the header file. Also, note that the documentation files do not explicitly mention anything about namespaces std and NTL.

There is a plethora of conversion routines. These are not documented in any of the individual documentation files, but rather, they are all briefly summarized in conversions.txt.

The following is a summary of the main NTL modules. The corresponding documentation file can be obtained by clicking on the module name. Note that the links below will take you to a "pretty printed" version of the correspinding .txt file.

GF2 class GF2: integers mod 2

GF2X class GF2X: polynomials over GF(2) (much more efficient than using zz_pX with p=2); includes routines for GCDs and minimal polynomials

GF2XFactoring routines for factoring polynomials over GF(2); also includes routines for testing for and constructing irreducible polynomials

GF2XVec class GF2XVec: fixed-length vectors of fixed-length GF2Xs; less flexible, but more efficient than vec_GF2X

GF2E class GF2E: polynomial extension field/ring over GF(2), implemented as GF(2)[X]/(P).

GF2EX class GF2EX class GF2EX: polynomials over GF2E; includes routines for modular polynomials arithmetic, modular composition, minimal and characteristic polynomials, and interpolation.

GF2EXFactoring routines for factoring polynomials over GF2E; also includes routines for testing for and constructing irreducible polynomials

HNF routines for computing the Hermite Normal Form of a lattice

LLL routines for performing lattice basis reduction, including very fast and robust implementations of the Schnorr-Euchner LLL and Block Korkin Zolotarev reduction algorithm, as well as an integer-only reduction algorithm. Also, there are routines here for computing the kernel and image of an integer matrix, as well as finding integer solutions to linear systems of equations over the integers.

RR class RR: arbitrary-precision floating point numbers.

ZZ class ZZ: arbitrary length integers; includes routines for GCDs, Jacobi symbols, modular arithmetic, and primality testing; also includes small prime generation routines and in-line routines for single-precision modular arithmetic

ZZVec class ZZVec: fixed-length vectors of fixed-length ZZs; less flexible, but more efficient than vec_ZZ

ZZX class ZZX: polynomials over ZZ; includes routines for GCDs, minimal and characteristic polynomials, norms and traces

ZZXFactoring routines for factoring univariate polynomials over ZZ

ZZ_p class ZZ_p: integers mod p

ZZ_pE class ZZ_pE: ring/field extension of ZZ_p

ZZ_pEX class ZZ_pEX: polynomials over ZZ_pE; includes routines for modular polynomials arithmetic, modular composition, minimal and characteristic polynomials, and interpolation.

ZZ_pEXFactoring routines for factoring polynomials over ZZ_pE; also includes routines for testing for and constructing irreducible polynomials

ZZ_pX class ZZ_pX: polynomials over ZZ_p; includes routines for modular polynomials arithmetic, modular composition, minimal and characteristic polynomials, and interpolation.

ZZ_pXFactoring routines for factoring polynomials over ZZ_p; also includes routines for testing for and constructing irreducible polynomials

lzz_p class zz_p: integers mod p, where p is single-precision

lzz_pE class zz_pE: ring/field extension of zz_p

lzz_pEX class zz_pEX: polynomials over zz_pE; provides the same functionality as class ZZ_pEX, but for single-precision p

lzz_pEXFactoring routines for factoring polynomials over zz_pE; provides the same functionality as class ZZ_pEX, but for single-precision p

lzz_pX class zz_pX: polynomials over zz_p; provides the same functionality as class ZZ_pX, but for single-precision p

lzz_pXFactoring routines for factoring polynomials over zz_p; provides the same functionality as class ZZ_pX, but for single-precision p

matrix template class for dynamic-size 2-dimensional arrays

mat_GF2 class mat_GF2: matrices over GF(2); includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_GF2E class mat_GF2E: matrices over GF2E; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_RR class mat_RR: matrices over RR; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, and solving nonsingular systems of linear equations.

mat_ZZ class mat_ZZ: matrices over ZZ; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, and solving nonsingular systems of linear equations. See also the LLL module for additional routines.

mat_ZZ_p class mat_ZZ_p: matrices over ZZ_p; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_ZZ_pE class mat_ZZ_pE: matrices over ZZ_pE; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_lzz_p class mat_zz_p: matrices over zz_p; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_lzz_pE class mat_zz_pE: matrices over zz_pE; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_poly_ZZ routine for computing the characteristic polynomial of a mat_ZZ

mat_poly_ZZ_p routine for computing the characteristic polynomial of a mat_ZZ_p

mat_poly_lzz_p routine for computing the characteristic polynomial of a mat_zz_p

pair template class for pairs

quad_float class quad_float: quadruple-precision floating point numbers.

tools some basic types and utility routines, including the timing function GetTime(), and several overloaded versions of min() and max()

vector template class for dynamic-size vectors

vec_GF2 class vec_GF2: vectors over GF(2), with arithmetic

vec_GF2E class vec_GF2E: vectors over GF2E, with arithmetic

vec_RR class vec_RR: vectors over RR, with arithmetic

vec_ZZ class vec_ZZ: vectors over ZZ, with arithmetic

vec_ZZ_p class vec_ZZ_p: vectors over ZZ_p, with arithmetic

vec_ZZ_pE class vec_ZZ_pE: vectors over ZZ_pE, with arithmetic

vec_lzz_p class vec_zz_p: vectors over zz_p, with arithmetic

vec_lzz_pE class vec_zz_pE: vectors over zz_pE, with arithmetic

version macros defining the NTL version number

xdouble class xdouble: double-precision floating point numbers with extended exponent range.

Some other types

In addition to the above, other generic vectors are declared, not explicitly documented elsewhere:

  • vec_GF2XVec
  • vec_ZZVec
  • vec_double
  • vec_long
  • vec_quad_float
  • vec_ulong
  • vec_vec_GF2
  • vec_vec_GF2E
  • vec_vec_RR
  • vec_vec_ZZ
  • vec_vec_ZZ_p
  • vec_vec_ZZ_pE
  • vec_vec_long
  • vec_vec_lzz_p
  • vec_vec_lzz_pE
  • vec_vec_ulong
  • vec_xdouble

These decalarations are found in ".h" files with corresponding names. These header files simply provide typedefs for the corresponding template types, mainly for backward compatibility, e.g., vec_double is a typedef for Vec<double>, and vec_vec_RR is a typedef for Vec< Vec<RR> >. No additional functionality is provided.

All of the header files for polynomial classes ZZ_pX, ZZX, etc., declare typedefs for the corresponding vectors of polynomials vec_ZZ_pX, vec_ZZX, etc.

There are also a number of generic pair classes defined, not explicitly documented elsewhere:

  • pair_GF2EX_long
  • pair_GF2X_long
  • pair_ZZX_long
  • pair_ZZ_pEX_long
  • pair_ZZ_pX_long
  • pair_lzz_pEX_long
  • pair_lzz_pX_long

These decalarations are found in ".h" files with corresponding names. Again, these files mainly exist for backward compatibilty, and provide typedefs for the corresponding template types, e.g., pair_GF2EX_long is a typedef for Pair<GF2EX,long>. These files also give typedefs for the corresponding vector types, e.g., vec_pair_GF2EX_long is a typedef for Vec< Pair<GF2EX,long> >. No additional functionality is provided.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-roadmap.html000644 000765 000024 00000007733 12377144460 016705 0ustar00shoupstaff000000 000000 A Tour of NTL: NTL past, present, and future
[Previous] [Up] [Next]

A Tour of NTL: NTL past, present, and future


Some History

Work on NTL started around 1990, when I wanted to implement some new algorithms for factoring polynomials over finite fields. I found that none of the available software was adequate for this task, mainly because the code for polynomial arithmetic in the available software was too slow. So I wrote my own. My starting point was Arjen Lenstra's LIP package for long integer arithmetic, which was written in C. It soon became clear that using C++ instead of C would be much more productive and less prone to errors, mainly because of C++'s constructors and destructors which allow memory management to be automated. Using C++ has other benefits as well, like function and operator overloading, which makes for more readable code.

One of the basic design principles of LIP was portability. I adopted this principle for NTL as well, for a number of reasons, not the least of which was that my computing environment kept changing whenever I changed jobs. Achieving portability is getting easier as standards, like IEEE floating point, get widely adopted, and as the definition of and implementations of the C++ language stabilize (which a few years ago was a huge headache, but is now only a big one, and in a few years will be a small one).

Since 1990, NTL has evolved in many ways, and it now provides a fairly polished and well-rounded programming interface.

When I started working on NTL, there really were not that many good, portable long integer packages around. Besides LIP, there was the BSD Unix MP library. The first version of GMP was released in the early 1990's. At that point in time, LIP seemed like the best starting point. LIP remains a reasonable long integer package, but in recent years, GMP has really become quite good: it seems well supported on many platforms, and is typically much faster than LIP.

I've now re-structured NTL so that one can use either 'traditional' LIP or GMP as the long integer package.

The Future of NTL

I hope that NTL remains stable in its current form. I plan to support NTL, fixing bugs and serious performance problems, but otherwise not to add significant new functionality or modify the programming interface.

I don't have time to add significant new functionality to NTL. However, there seems to be an ever-growing number of NTL users out there, and I encourage them to make their code available to others. These might be in the form of NTL "add ons", but there is the possibility of integrating new functionality or algorithmic improvements into NTL itself. One thing in particular that would be nice is support for bivariate polynomial arithmetic, including GCDs, resultants, and factoring, and for integer and all the various finite field coefficient rings. Another nice thing would be code for elliptic curves, including an elliptic curve point counting algorithm. Another nice thing would be something for factoring integers. Any one of these projects would be a nice master's thesis project, I think.

As you can well imagine, there is potentially no end to algorithms one could implement. That is why I have to stop somewhere. I think NTL has reached a point where it provides a reasonably well-rounded suite of algorithms for basic problems.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-stdcxx.html000644 000765 000024 00000067344 12377144460 016603 0ustar00shoupstaff000000 000000 A Tour of NTL: Traditional and ISO Modes
[Previous] [Up] [Next]

A Tour of NTL: Traditional and ISO Modes


As of version 4.1, NTL can be compiled and used in one of two modes: Traditional or ISO. As of NTL version 5.4, ISO mode is the default.

To revert to traditional mode, you can pass NTL_STD_CXX=off as an argument to the configuration script when installing NTL on a Unix or Unix-like system, which will unset the flag NTL_STD_CXX in the config.h file. Alternatively (and especially on non-Unix systems), you can unset this flag by hand by editing the the config.h file.

In Traditional mode, the NTL header files include the traditional C++ header files <stdlib.h>, <math.h>, and <iostream.h>. These files declare a number of names (functions, types, etc.) in the global namespace. Additionally, the NTL header files declare a number of names, also in the global namespace.

In ISO mode, three things change:

  1. NTL namespace: The NTL header files wrap all NTL names in a namespace, called NTL.

  2. New header files: The NTL header files include the new C++ header files <cstdlib>, <cmath>, and <iostream>. These new header files are essentially the same as the traditional ones, except that all the the names are declared in a namespace called std.

  3. Nothrow new: The NTL implementation files use the nothrow version of new.

If your complier is not up to date, but you want some of the benefits of Standard C++, you can set the partial standard flags to get any subset of the above three changes:

  1. NTL_PSTD_NNS: NTL namespace
  2. NTL_PSTD_NHF: New header files
  3. NTL_PSTD_NTN: Nothrow new
You can set these flags either by using the configuration script (only on Unix-like systems), or by editing the config.h file. For example, to just wrap NTL in a namepsace, just pass NTL_PSTD_NNS=on as an argument to the configuration script when installing NTL. However, make sure you also turn off the NTL_STD_CXX flag; otherwise, these have no effect.

Especially when combining NTL with other libraries, the NTL_PSTD_NNS flag may be particularly useful in avoiding name clashes, even if your compiler has just a rudimentary implementation of namespaces.

NTL will remain usable in Traditional mode indefinitely, assuming compilers maintain reasonable backward compatibilty with pre-standard C++ conventions for header files; however, if you want to program for the future, it is recommended to use ISO mode. The partial ISO modes are not highly recommended; they are mainly intended as a stop-gap measure while we wait for decent standard-conforming C++ compilers to become available.

A crash course on namespaces

As already mentioned, the main difference between Traditional and ISO mode is that in ISO mode, all names are wrapped in namespaces. Namespaces are a feature that was introduced in the new C++ standard. One can declare names (functions, types, etc.) inside a namespace. By default, such names are not visible outside the namespace without explicit qualification.

The main advantage of namespaces is that it solves the namespace pollution problem: if two libraries define the same name in two inconsistent ways, it is very difficult, if not impossible, to combine these two libraries in the same program.

The traditional way of avoiding such problems in languages like C is for a library designer to attach a prefix specific to that library to all names. This works, but makes for ugly code. The function overloading mechanism in C++ eases the problem a bit, but is still not a complete solution.

The new namespace feature in C++ provides a reasonably complete and elegant solution to the namespace pollution problem. It is one of the nicest and most important recent additions to the C++ language.

Here is a simple example to illustrate namespaces.


namespace N {
   void f(int);
   void g(int);
   int x;
}

int x;

void h()
{
   x = 1;    // the global x
   N::x = 0// the x in namespace N
   N::f(0);  // the f in namespace N
   g(1);     // error -- g is not visible here
}

All of this explicit qualification business can be a bit tedious. The easiest way to avoid this tedium is to use what is called a using directive, which effectively makes all names declared within a namespace visible in the global scope. Here is a variation on the previous example, with a using directive.

namespace N {
   void f(int);
   void g(int);
   int x;
}

int x;

using namespace N;

void h()
{
   x = 1;    // error -- ambiguous: the global x or the x in namespace N?
   ::x = 1;  // the global x
   N::x = 0// the x in namespace N
   N::f(0);  // the f in namespace N
   f(0);     // OK -- N::f(int) is visible here
   g(1);     // OK -- N::g(int) is visible here
}

Here is another example.


namespace N1 {
   int x;
   void f(int);
   void g(int);
}

namespace N2 {
   int x;
   int y;
   void f(double);
   void g(int);
}

using namespace N1;
using namespace N2;

void h()
{
   x = 1;     // error -- ambiguous: N1::x or N2::x?
   N1::x = 1// OK
   N2::x = 1// OK
   y = 1;     // OK  -- this is N2::y
   g(0);      // error -- ambiguous: N1::g(int) or N2::g(int)?
   f(0);      // OK -- N1::f(int), because it is the "best" match 
   f(0.0);    // OK  -- N2::f(double), because it is the "best" match
}

This example illustrates the interaction between using declarations and function overloading resolution. If several overloaded versions of a function are visible, it is not necessarily ambiguous: the usual overload resolution procedure is applied, and if there is a unique "best" match, then there is no ambiguity.

The examples presented here do not illustrate all of the features and nuances of namespaces. For this, you are referred to a C++ book.

Namespaces and NTL

In ISO mode, the standard library is "wrapped" in namespace std, and NTL is "wrapped" in namespace NTL. Thus, the header file <NTL/ZZ.h> in ISO mode looks something like this:

namespace NTL {

   // ...

   class ZZ { /* ... */ };

   // ...

   ZZ operator+(const ZZ& a, const ZZ& b);
   ZZ operator*(const ZZ& a, const ZZ& b);

   std::istream& operator>>(std::istream& s, ZZ& x);
   std::ostream& operator<<(std::ostream& s, const ZZ& a);

   // ...

  
}

Therefore, one must explicitly qualify all names, or use appropriate using directives. Here is how one could write the first example of the tour in ISO mode.

#include <NTL/ZZ.h>

int main()
{
   NTL::ZZ a, b, c; 

   std::cin >> a; 
   std::cin >> b; 
   c = (a+1)*(b+1);
   std::cout << c << "\n";
}

Notice how everything is explicitly qualified. Actually, the input/output operators << and >>, and the arithmetic operators + and * are not explicitly qualified, but rather, the compiler finds them through a gimmick called Koenig Lookup, which will look for functions (and operators) declared in namespace NTL, because the type of the argument (ZZ) is a class declared in that namespace.

Even with Koenig Lookup, explicit qualification can be a bit tedious. Here is the same example, this time with using directives.

#include <NTL/ZZ.h>

using namespace NTL;
using namespace std;

int main()
{
   ZZ a, b, c; 

   cin >> a; 
   cin >> b; 
   c = (a+1)*(b+1);
   cout << c << "\n";
}

To write NTL client code that will compile smoothly in either Traditional or ISO mode, one simply does the following:

#include <NTL/ZZ.h>

NTL_CLIENT

int main()
{
   ZZ a, b, c; 

   cin >> a; 
   cin >> b; 
   c = (a+1)*(b+1);
   cout << c << "\n";
}

Here, NTL_CLIENT is a macro defined by NTL that expands into zero, one, or two appropriate using directives, depending on the settings of NTL_STD_CXX, NTL_PSTD_NNS, and NTL_PSTD_NHF. Alternatively, instead of using the NTL_CLIENT macro, you can write:

#if (defined(NTL_PSTD_NNS) || defined(NTL_STD_CXX))
   using namespace NTL;
#endif

#if (defined(NTL_PSTD_NHF) || defined(NTL_STD_CXX))
   using namespace std;
#endif

Typically, when writing a program that uses NTL, you can simply insert the NTL_CLIENT as above, and forget about all this namespace nonsense. However, if you are combining libraries, you may have to disambiguate things from time to time.

The Standard C++ library is huge. If you just use <iostream>, you should not have any ambiguous names. However, there are some potential ambiguities in the STL (Standard Template Library) part of the library. One that I know of is the template class negate defined in <functional>, which conflicts with the NTL function negate. With namespaces, there should be no problem, unless the client code explicitly uses negate, in which case you will have to explicitly qualify negate to tell the compiler which negate you mean, either std::negate or NTL::negate.

NTL also explicitly defines various versions of min and max functions. Template versions of these functions are also defined in the standard library component <algorithm>. Because of the way the function overload resolution mechanism works, the "right" version of min or max should always be chosen, without any need for explicit qualification.

There may be other possible ambiguities between the standard library and NTL, but if they arise, they are easily fixed through explicit qualification.

Some global names

It is not quite true that all names declared in NTL header files are wrapped in namespace NTL. There are two classes of exceptions:

  • All names that start with the prefix "NTL_" are in fact macros. There are a number of documented and undocumented such macros. Note that any name with this prefix is a macro and all macros start with this prefix.

  • There are also a number of undocumented names that start with the prefix "_ntl_". These are not macros, but rather are names of functions, types, etc., that are declared in the global namespace. Any name with this prefix is in the global namespace, and all names in the global namespace start with this prefix. All functions with "C" linkage have this prefix.

Thus, NTL "owns" all names starting with "NTL_" or "_ntl_"; users of NTL should avoid names with these prefixes.

Further technicalities

Another thing to be aware of is that there are some small, annoying differences between the old standard C include files <stdlib.h> and <math.h>, and the new C++ include files <cstdlib> and <cmath>, above and beyond the namespace wrapping. Specifically, the new header files declare several overloaded versions of some functions. For example, in the old header files, there was one function

   int abs(int);

Now there are several, including:

   int abs(int);
   long abs(long);
   float abs(float);
   double abs(double);
   long double abs(long double);

Also, functions like log and sqrt are also overloaded. So instead of just

   double log(double);

there are

   float log(float);
   double log(double);
   long double log(long double);

This can lead to compile-time errors in some old codes, such as:

   double log_2 = log(2);

With the old header files, the int value 2 would have been converted to a double, and the function

   double log(double);

would have been called.

With the new header files, the compiler would raise an error, because the function call is now ambiguous.

Of course, the fix is trivial:

   double log_2 = log(2.0);

This will compile correctly with either old or new header files.

Don't you just love the ISO?

A note on documentation

The ".txt" files documenting NTL's modules still reflect NTL's Traditional mode. There should be no confusion in interpretting the meaning in ISO mode. Just remember: all of NTL is wrapped in namespace NTL, and the standard library is wrapped in namespace std.

Further changes in NTL version 4.1

The ISO Standard for C++ is not compatible with the language defined in the second edition of Stroustrup's C++ book. This is in fact quite annoying. Besides introducing namespaces, several modifications were made in version 4.1 that will allow NTL to be compiled smoothly under either the old or the new definition of the language (or any reasonable approximation thereof). These changes do not affect the (documented) NTL interface, and so version 4.1 should be backward compatible.

Here is a summary of the other changes:

  • Got rid of all friend functions. It turns out that new C++ and old C++ disagree quite strongly about the semantics of a friend function declaration. In getting rid of these, I also made a number of fields public which used to be private, but to prevent accidental misuse, I gave them strange names (e.g., the previously private member rep in class ZZ_p is now the public member _ZZ_p__rep).

    This change is effective in both Traditional and ISO modes.

    In my view, the ISO committee really committed an act of sabotage here. Now the friend mechanism is much more awkward than before, which makes the use of private members more awkward, which simply encourages programmers (like me) to avoid them altogether.

  • When NTL_STD_CXX or NTL_PSTD_NTN are set, all calls to new have been replaced by new(std::nothrow).

    The ISO committee also committed an act of sabotage when they changed the semantics of the memory allocation operator new. In old C++, a memory allocation error simply returned a null pointer; in new C++ an exception is thrown. The old semantics are available via new(std::nothrow).

    You may of course use NTL in Traditional mode with a compiler that implements the new semantics for new. In this case, if the memory allocation fails, an exception will be thrown, and assuming you don't catch it, you will simply get an error message that is less informative than the one NTL would have printed. Also, your compiler may have a backward compatatibilty flag to use the old new semantics.

  • Various and sundry other small changes, such as fixing occurrences of the the "log(2)" problem mentioned above.

Standard C++ and the Real World

The first C++ standard was set in 1998, with some revisions in 2003. As I write this update in 2013, I believe it is safe to say that most compileres released in the last few years do a pretty good job of implementing the standard.

However, a new revision to tne standard appeared in 2011. This new revision contains many new language and library features. Surely, it will be a number of years until support for all these new feautures will be uniformly available.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-struct.html000644 000765 000024 00000104747 12377144460 016611 0ustar00shoupstaff000000 000000 A Tour of NTL: Programming Interface
[Previous] [Up] [Next]

A Tour of NTL: Programming Interface


In this section, we give a general overview of the NTL's programming interface.

Basic Ring Classes

The basic ring classes are:

  • ZZ: big integers
  • ZZ_p: big integers modulo p
  • zz_p: integers mod "single precision" p
  • GF2: integers mod 2
  • ZZX: univariate polynomials over ZZ
  • ZZ_pX: univariate polynomials over ZZ_p
  • zz_pX: univariate polynomials over zz_p
  • GF2X: polynomials over GF2
  • ZZ_pE: ring/field extension over ZZ_p
  • zz_pE: ring/field extension over zz_p
  • GF2E: ring/field extension over GF2
  • ZZ_pEX: univariate polynomials over ZZ_pE
  • zz_pEX: univariate polynomials over zz_pE
  • GF2EX: univariate polynomials over GF2E

All these classes all support basic arithmetic operators

   +, -, (unary) -, +=, -=, ++, --, 
   *, *=, /, /=, %, %=.

However, the operations

   %, %=
only exist for integer and polynomial classes, and do not exist for classes
  ZZ_p, zz_p, GF2, ZZ_pE, zz_pE, GF2E.

The standard equality operators (== and !=) are provided for each class. In addition, the class ZZ supports the usual inequality operators.

The integer and polynomial classes also support "shift operators" for left and right shifting. For polynomial classes, this means multiplication or division by a power of X.

Floating Point Classes

In addition to the above ring classes, NTL also provides three different floating point classes:

  • xdouble: "double precision" floating point with extended exponent range (for very large numbers);
  • quad_float: "quasi" quadruple-precision floating point;
  • RR: aribitrary precision floating point.

Vectors and Matrices

There are also vectors and matrices over

   ZZ ZZ_p zz_p GF2 ZZ_pE zz_pE GF2E RR
which support the usual arithmetic operations.

Functional and Procedural forms

Generally, for any function defined by NTL, there is a functional form, and a procedural form. For example:

   ZZ x, a, n;
   x = InvMod(a, n);  // functional form
   InvMod(x, a, n);   // procedural form

This example illustrates the normal way these two forms differ syntactically. However, there are exceptions. First, if there is a operator that can play the role of the functional form, that is the notation used:

   ZZ x, a, b;
   x = a + b;    // functional form
   add(x, a, b); // procedural form

Second, if the functional form's name would be ambiguous, the return type is simply appended to its name:

   ZZ_p x;
   x = random_ZZ_p();  // functional form
   random(x);          // procedural form

Third, there are a number of conversion functions (see below), whose name in procedural form is conv, but whose name in functional form is conv<T>, where T is the return type:

   ZZ x;  
   double a;

   x = conv<ZZ>(a);  // functional form
   conv(x, a);       // procedural form

The use of the procedural form may be more efficient, since it will generally avoid the creation of a temporary object to store its result. However, it is generally silly to get too worked up about such efficiencies, and the functional form is usually preferable because the resulting code is usually easier to understand.

The above rules converning procedural and functional forms apply to essentially all of the arithmetic classes supported by NTL, with the exception of xdouble and quad_float. These two classes only support the functional/operator notation for arithmetic operations (but do support both forms for conversion).

Conversions and Promotions

As mentioned above, there are numerous explicit conversion routines, which come in both functional and procedural forms. A complete list of these can be found in conversions.txt. This is the only place these are documented; they do not appear in the other ".txt" files.

It is worth mentioning here, however, that generic conversion operators are provided for vectors and matrices, which act component-wise. For example, since there is a conversion from ZZ to RR, there is automatically a conversion from Vec<ZZ> to Vec<RR>.

Even though there are no implicity conversions, users of NTL can still have most of their benefits. This is because all of the basic arithmetic operations (in both their functional and procedural forms), comparison operators, and assignment are overloaded to get the effect of automatic "promotions". For example:

   ZZ x, a;

   x = a + 1;
   if (x < 0
      mul(x, 2, a);
   else
      x = -1;

These promotions are documented in the ".txt" files, usually using a kind of "short hand" notation. For example:

ZZ operator+(const ZZ& a, const ZZ& b);

// PROMOTIONS: operator + promotes long to ZZ on (a, b).

This means that in addition to the declared function, there are two other functions that are logically equivalent to the following:

ZZ operator+(long a, const ZZ& b) { return ZZ(a) + b; }
ZZ operator+(const ZZ& a, long b) { return a + ZZ(b); }

Note that this is not how NTL actually implements these functions. It is in generally more efficient to write

   x = y + 2;

than it is to write

   x = y + ZZ(2);

The former notation avoids the creation and destruction of a temporary ZZ object to hold the value 2.

Also, don't have any inhibitions about writing tests like

   if (x == 0) ...

and assignments like

   x = 1

These are all optimized, and do not execute significaltly slower than the "lower level" (and much less natural)

   if (IsZero(x)) ...

and

   set(x);

Some types have even more promotions. For example, the type ZZ_pX has promotions from long and ZZ_p. Thus, the add function for ZZ_pX takes the following argument types:

   (ZZ_pX, ZZ_pX), (ZZ_pX, ZZ_p), (ZZ_pX, long), (ZZ_p, ZZ_pX), (long, ZZ_pX)
Each of these functions effectively converts the argument to be promoted to a ZZ_pX.

Note that when promoting a pair of arguments, at least one of the arguments must be of the target type.

I have tried to be very consistent with these promotions so that one usually won't need to hunt through the documentation. For a given type, there is a natural, fixed set of types that promote to it. Here is the complete list:

   destination  source
   
   xdouble      double
   quad_float   double
   RR           double
   ZZ           long
   ZZ_p         long
   ZZ_pX        long, ZZ_p
   zz_p         long
   zz_pX        long, zz_p
   ZZX          long, ZZ
   GF2          long
   GF2X         long, GF2
   GF2E         long, GF2
   GF2EX        long, GF2, GF2E
   ZZ_pE        long, ZZ_p
   ZZ_pEX       long, ZZ_p, ZZ_pE
   zz_pE        long, zz_p
   zz_pEX       long, zz_p, zz_pE

All the promotions are documented, but here are a few general rules describing the available promotions:

  • All classes provide explicit constructors for promoted types. For example,

       ZZ w = ZZ(1);
       ZZ x(1);  // allowed
       ZZ y{1};  // allowed in C++11
       ZZ z = 1// not allowed

  • Promotions apply uniformly to both procedural and functional forms, as well as to the corresponding assignment operator forms. E.g.,

       x = x + 2;
       add(x, x, 2);
       x += 2;

  • The addition, subtraction, multiplication, equality and comparison routines always promote both arguments. E.g.,

       x = 2 + y;
       add(x, 2, y);
       if (3 > x || y == 5) ...

  • The assignment operator always promotes the right-hand side. E.g.,

       x = 2;

  • For non-integer, non-polynomial types, the division routine promotes both arguments. E.g.,

       RR x, y, z;
          ...
       x = 1.0/y;
       z = y/2.0;

    For integer or polynomial types, the division routine promotes the denominator only. E.g.,

       ZZ x, y;
          ...
       y = x/2;
    
  • Matrix by scalar and vector by scalar multiplication promote the scalar. E.g.,

       Vec<ZZ> v, w;
          ...
       v = w*2;
       v = 2*w;
       v *= 2;

  • The monomial constructors for polynomials and the corresponding SetCoeff routines promote the coefficient argument. E.g.,

       ZZX f;
       f = ZZX(INIT_MONO, 35);  // f == 5*X^3
       SetCoeff(f, 02);  // f == 5*x^3 + 2;

  • In module ZZ, the modular arithmetic routines, as well as the bit-wise and, or, and xor routines promote their arguments. There are also several other routines in module ZZ that have both ZZ and long versions, e.g., NumBits, bit, weight. Check the documentation in ZZ.cpp.html for complete details.

Some Conversion and Promotion Technicalities

Usually, conversions and promotions are semantically equivalent. There are three exceptions, however.

One exception is conversion of floating point double to ZZ. The safest way to do this is to apply an explicit conversion operator, and not to rely on promotions. For example, consider

   ZZ a; double x;

   a = a + x;

This is equivialent to

   a = a + long(x);

and to

   a = a + ZZ(x);

One could also use an explicit conversion function:

   a = a + conv<ZZ>(x);

This last version guarantees that there is no loss of precision, and also guarantees that the floor of x is computed. With the first version, one may lose precision when x is converted to a long, and also the direction of truncation for negative numbers is implementation dependent (usually truncating towards zero, instead of computing the floor).

The second exception is conversion of unsigned int or unsigned long to ZZ. Again, the safest way to do this is with an explicit conversion operator. As above, if one relies on promotions, the unsigned integer will be first converted to a signed long, which is most likely not what was intended.

The third exception can occur on 64-bit machines when converting a signed or unsigned long to one of NTL's extended precision floating-point types (RR or quad_float). These types only provide promotions from double, and converting a long to a double on a 64-bit machine can lead to a loss of precision. Again, if one uses the appropriate NTL conversion routine, no loss of precision will occur.

Another pitfall too avoid is initialzing ZZ's with integer constants that are too big. Consider the following:

   ZZ x;
   x = 1234567890123456789012;

This integer constant is too big, and this overflow condition may or may not cause your compiler to give you a warning or an error. The easiest way to introduce such large constants into your program is as follows:

   ZZ x;
   x = conv<ZZ>("1234567890123456789012");

Conversion functions are provided for converting C character strings to the types ZZ, RR, quad_float, and xdouble.

One should also be careful when converting to RR. All of these conversions round to the current working precision, which is usually, but not always, what one wants.

Aliasing

An important feature of NTL is that aliasing of input and output parameters is generally allowed. For example, if you write mul(x, a, b), then a or b may alias (have the same address as) x (or any object that x contains, e.g., scalar/vector or scalar/polynomial multiplication).

One exception to this rule: the generic conversions provided for vectors and matrices assume that their inputs do not alias their outputs.

Constructors, Destructors, and Memory Management

NTL generally takes care of managing the space occupied by large, dynamically sized objects, like objects of class ZZ or any of NTL's dynamic vectors. However, it is helpful to understand a little of what is happening behind the scenes.

Almost all classes are implemented as a pointer, and the default constructor just sets this pointer to 0. Space is allocated for the object as needed, and when the object's destructor is called, the space is freed.

Copies are "deep" rather than "shallow". This means the data itself is copied, and not just a pointer to the data. If the destination object does not have enough space to hold the source data, then the space held by the destination object is "grown". This is done using the C routine realloc(). Note, however, that if the source object is smaller than the destination object, the space held by the destination object is retained. This strategy usually yields reasonable behaviour; however, one can take explicit control of the situation if necessary, since almost all NTL classes have a method kill() which frees all space held by the object, and sets its state to the default initial state (a value 0 or a zero-length vector).

The only exception to the above is the class ZZ_pContext, and the analogous classes for zz_p, ZZ_pE, zz_pE, and GF2E. These objects are implemented as referenced-counted pointers, and copies are "shallow".

While we are discussing initialization, there is one technical point worth mentioning. It is safe to declare global objects of any NTL type as long as one uses only the default constructor. For example, the global declarations

   ZZ global_integer;
   Vec<ZZ_p> global_vector;

should always work, since their initialization only involves setting a pointer to 0. However, one should avoid initializing global objects with non-default constructors, and should avoid doing anything that would lead to non-trivial computations with NTL objects prior to the beginning of the execution of routine main(). The reasons for this are quite esoteric and can only be appreciated by a true C++ afficianado. Actually, most such initializations and computations probably will work, but it is somewhat platform dependant.

Normal people usually do none of these things, so all of this should not matter too much. There is, however, one possible exception to this. A programmer might want to have a global constant initialized like this:

   const quad_float Pi = conv<quad_float>("3.1415926535897932384626433832795029");

While this probably will work fine on most platforms, it may not be an entirely portable construction, since it will involve a non-trivial computation before execution of main() begins. A more portable strategy is to define a function returning a read-only reference:

   const quad_float& Pi()
   {
      static quad_float pi = 
         conv<quad_float>("3.1415926535897932384626433832795029");
      return pi;
   }

and then call the function Pi() to get a read-only reference to this constant value:

   area = Pi()*r*r;

The initialization will then take place the first time Pi() is called, which is presumably after main() starts, and so everything should work fine. This is a very simple and general strategy that most C++ experts recommend using whenever the initialization of a non-global object requires non-trivial computation.

Residue class rings and modulus switching

NTL provides a number of classes to represent residue class rings:

   ZZ_p, zz_p, GF2, ZZ_pE, lzz_pE, GF2E.
For each such class, except GF2, there is a global, current modulus.

We focus on the class ZZ_p, but similar comments apply to the other residue class types. For example, for ZZ_p, you can set the current modulus to p as follows:

   ZZ_p::init(p);

The current modulus must be initialized before any operations on ZZ_p's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus.

Here is what you do to save the current modulus, temporarily set it to p, and automatically restore it:

   { 
      ZZ_pPush push(p); 

      ...

   }

The constructor for push will save the current modulus, and install p as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm.

You could also do the following:

   {
      ZZ_pPush push(); // just backup current modulus

        ...

      ZZ_p::init(p1); // install p1 

        ...

      ZZ_p::init(p2); // install p2

      // reinstall original modulus as close of scope
   }

The ZZ_pPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see the class ZZ_pContext.

It is critical that ZZ_p objects created under one ZZ_p modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) ZZ_p modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition it is generally safe to read any ZZ_p object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior.

The implementations of Vec<ZZ_p>, Vec<GF2E>, and Vec<GF2> are specialized to manage memory more efficiently than in the default implementation of Vec<T>.

Contiguous elements in a Vec<ZZ_p> are allocated in a contiguous region of memory. This reduces the number of calls to the memory allocator, and leads to greater locality of reference. A consequence of this implementation is that any calls to SetLength on a Vec<ZZ_p> object will need to use information about the current modulus, and so such calls should only be done "in context". That said, it is still safe to construct a Vec<ZZ_p> using the default or copy contructor, and to assign or append one Vec<ZZ_p> to another "out of context".

The same strategy is used for Vec<GF2E>'s.

In any case, the above restrictions adhere to the general rules for safely using residue class ring objects "out of context".

Vec<GF2>'s are implemented by packing coefficients (which are just bits) into words. A mechanism is provided to make indexing these vectors behave like normal vectors, via a class the mimics ordinary references to GF2's.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-time.html000644 000765 000024 00000005533 12377144460 016214 0ustar00shoupstaff000000 000000 A Tour of NTL: Some Performance Data
[Previous] [Up] [Next]

A Tour of NTL: Some Performance Data


Here are some timing figures from using NTL. They were obtained using NTL 6.2 compiled with g++ 4.2.1 and with GMP 5.1 on a 2.4GHz Intel Core 2 Duo running on Max OSX 10.7.2.

All times are ins seconds. The times were obtained using the program Timing included in the distribution. The data was generated using NTL's random number generator, but running this on a different machine should (in theory) generate the same data.

multiply 1000-bit ints: 5.31027e-07
remainder 2000/1000-bit ints: 1.01566e-06
gcd 1000-bit ints: 1.4682e-05
multiply degree-1000 poly mod 1000-bit prime: 0.0264952
remainder degree-2000/1000 poly mod 1000-bit prime: 0.076708
preconditioned remainder degree-2000/1000 poly mod 1000-bit prime: 0.0266063
gcd degree-1000 poly mod 1000-bit prime: 0.565005
multiply degree-1000 int poly with 1000-bit coeffs: 0.0273532

factoring degree-1000 poly mod 1000-bit prime...
square-free decomposition...0.558535
factoring multiplicity 1, deg = 1000
computing X^p...42.0216
computing DDF...generating baby steps...+++++++++++++++++++++24.69
generating giant steps...++++++++++++++++++++++25.3912
giant refine...++++split 1 43
split 2 38
split 3 64
*++++split 5 108
*++++split 11 237
split 12 510
*giant refine time: 15.1859
baby refine...split 3 6
split 6 6
split 9 9
split 22 22
split 38 38
split 64 64
split 108 108
split 237 237
split 248 248
split 262 262
baby refine time: 1.0758
DDF time: 66.3546
computing EDF(3,2)...+0.028255
...total time = 109.019

multiply 500-bit GF2Xs: 1.33614e-06
remainder 1000/500-bit GF2Xs: 7.95517e-06
gcd 500-bit GF2Xs: 1.55201e-05

factoring degree-500 GF2X: 0.00137361
gcd 500-bit GF2X: 1.56605e-05
multiply degree-500 poly mod 500-bit GF2X: 0.0324352
remainder degree-1000/500 poly mod 500-bit GF2X: 0.114726
preconditioned remainder degree-1000/500 poly mod 500-bit GF2X: 0.0641071
gcd degree-500 poly mod 500-bit prime: 0.710028

factoring degree-500 poly mod 500-bit prime...
square-free decomposition...0.048244
factoring multiplicity 1, deg = 250
computing X^p...6.35723
computing DDF...generating baby steps...++++++++++4.55756
generating giant steps...+++++++++++4.92042
giant refine...++++*++++

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-tips.html000644 000765 000024 00000010614 12377144460 016231 0ustar00shoupstaff000000 000000 A Tour of NTL: Tips for Getting the Best Performance out of NTL
[Previous] [Up] [Next]

A Tour of NTL: Tips for Getting the Best Performance out of NTL


  1. Build NTL using GMP as the long integer package. This is extremely important, as the GMP implementation of long integer arithmetic is much faster than the default implementation. Go here for details.

  2. On many machines that optionally offer 64-bit integer arithmetic (recent Mac OSX machines, for instance), you should compile using gcc with the option -m64 to get the full benefit. To do this, pass "CFLAGS=-O2 -m64" to the configure script (note the use of quotes). If you are using NTL with GMP on such a machine, you must do this to get compatible code. Note, however, that 64-bit is becoming the default, so this may not be necessary.

  3. On Sparcs, pass the argument "CFLAGS=-O2 -mcpu=v8" to the configure script. On more recent, 64-bit sparcs, pass "CFLAGS=-O2 -mcpu=v9 -m64" to get the full instruction set and 64-bit code.

  4. Make sure you run the configuration wizard when you install NTL. This is the default behaviour in the makefile in the Unix distribution, so don't change this; in the Windows distribution, there is unfortunately no easy way to run the wizard.

  5. In time-critical code, avoid creating unnecessary temporary objects. For example, instead of

    ZZ InnerProduct(const ZZ *a, const ZZ *b, long n)
    {
       long i;
       ZZ res;
       for (i = 0; i < n; i++)
          res += a[i] * b[i];
       return res;
    }

    write this as

    ZZ InnerProduct(const ZZ *a, const ZZ *b, long n)
    {
       long i;
       ZZ res, t;
       for (i = 0; i < n; i++) {
          mul(t, a[i], b[i]);
          add(res, res, t);
       }
       return res;
    }

    The first version of InnerProduct creates and destroys a temporary object, holding the value a[i]*b[i], in every loop iteration. The second does not.

  6. If you use the class ZZ_p, try to avoid switching the modulus too often, as this can be a rather expensive operation. If you must switch the modulus often, use the class ZZ_pContext to save the information associated with the modulus (see ZZ_p.txt).

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-unix.html000644 000765 000024 00000040161 12377144460 016235 0ustar00shoupstaff000000 000000 A Tour of NTL: Obtaining and Installing NTL for UNIX
[Previous] [Up] [Next]

A Tour of NTL: Obtaining and Installing NTL for UNIX


This procedure should work on most Unix or Unix-like platorms (including Mac OSX, and Windows with Cygwin tools).

To obtain the source code and documentation for NTL, download ntl-xxx.tar.gz, placing it a directory, and then, working in this directory, do the following. Here, "xxx" denotes the current version number.

   % gunzip ntl-xxx.tar.gz
   % tar xf ntl-xxx.tar
   % cd ntl-xxx/src
   % ./configure PREFIX=$HOME/sw
   % make
   % make check
   % make install
This will build, test, and install NTL in $HOME/sw. Of course, change $HOME/sw to whatever you want (the default is /usr/local). You will find the NTL header files in $HOME/sw/include/NTL and the compiled binary in $HOME/sw/lib/libntl.a (this is a static library -- if you want a shared library, see below).

If you really are interested in high-performace, you will definitely want to build NTL using GMP (the GNU Multi-Precision package). If GMP has already been installed in a standard place, like /usr/local, then invoke configure above as

   % ./configure PREFIX=$HOME/sw NTL_GMP_LIP=on
and if GMP is installed somewhere else, say $HOME/sw, then either
   % ./configure PREFIX=$HOME/sw NTL_GMP_LIP=on GMP_PREFIX=$HOME/sw
or, more simply,
   % ./configure DEF_PREFIX=$HOME/sw NTL_GMP_LIP=on 
does the job. Here, DEF_PREFIX is a variable that is used to specify the location of all software, and it defaults to /usr/local. This page provides more details.

If you want very high-performance for polynomial arithmetic over GF(2), you may want to consider using the gf2x library. To do this, gf2x must already be installed somewhere. In addition, you should invoke configure with the option NTL_GF2X_LIB=on. If gf2x is installed in a standard location, this is all you need to do; otherwise, if gf2x is installed, say, in $HOME/sw, then you also need to pass the option GF2X_PREFIX=$HOME/sw. This page provides more details.

Now suppose you want to compile a program that uses NTL. Suppose you are working in some directory and foo.c is your program. Assume that you have installed NTL in $HOME/sw as above. The following should work:

   % g++  -I$HOME/sw/include foo.c -o foo  -L$HOME/sw/lib -lntl  -lm
If you are using GMP, then:
   % g++ -I$HOME/sw/include foo.c -o foo  -L$HOME/sw/lib -lntl -lgmp  -lm
If you are using GMP and gf2x, then
   % g++  -I$HOME/sw/include foo.c -o foo  -L$HOME/sw/lib -lntl -lgmp -lgf2x  -lm

More Details

What follows is a more detailed description of the installation process.

Step 1. Extract the source files by executing:

   % gunzip ntl-xxx.tar.gz
   % tar xvf ntl-xxx.tar

Note that this will unpack everything into a sub-directory ntl-xxx, creating this directory if necessary. Next:

   % cd ntl-xxx
   % ls
You should see a file "README", and directories "include", "doc", and "src". The directory "doc" contains all the documentation. The file "doc/tour.html" contains a copy of the on-line documentation. The directory "include" contains all the header files within a subdirectory "include/NTL". The directory "src" contains everything else. Go there now:
   % cd src

Step 2. Run the configuration script.

Execute the command

   % ./configure [ variable=value ]...
This configure script generates the file "makefile" and the file "../include/NTL/config.h", based upon the values assigned to the variables on the command line.

Here are the most important variables, and their default values.

CXX=g++              # The C++ compiler
CXXFLAGS=-O2         # C++ complilation flags

DEF_PREFIX=/usr/local # Default software directory
PREFIX=$(DEF_PREFIX) # Directory in which to install NTL library components
SHARED=off           # Generate a shared library (as well as static)

NTL_STD_CXX=on       # ISO Mode switch

NTL_GMP_LIP=off      # Switch to enable the use of GMP as primary 
                     #   long integer package

GMP_PREFIX=$(DEF_PREFIX) # Directory in which GMP components are installed

NTL_GF2X_LIB=off     # Switch to enable the use of the gf2x package
                     #   for faster arithmetic over GF(2)[X]

GF2X_PREFIX=$(DEF_PREFIX) # Directory in which gf2x components are installed

Examples.

  • If you are happy with all the default values, run:
       % ./configure
    
    Actually, the initially installed makefile and config.h files already reflect the default values, and you do not have to even run the configure script.

  • If your C++ compilers is called CC, run:
       % ./configure CXX=CC
    

  • If you want to use, say, the options -g and -O for compiling C and C++, run:
       % ./configure "CXXFLAGS=-g -O"
    
    Note the use of quotes to keep the argument in one piece.

  • If GMP (the GNU Multi-Precision package) is installed in a standard system directory, and you want to use it to obtain better performance for long integer arithemtic, run:
       % ./configure NTL_GMP_LIP=on
    
    If GMP was installed in $HOME/sw, run:
       % ./configure NTL_GMP_LIP=on GMP_PREFIX=$HOME/sw
    
    Go here for complete details.

  • If gf2x is installed in a standard system directory, and you want to use it to obtain better performance for polynomial arithemtic over GF(2), run:
       % ./configure NTL_GF2X_LIB=on
    
    If gf2x was installed in $HOME/sw, run:
       % ./configure NTL_GF2X_LIB=on GF2X_PREFIX=$HOME/sw
    
    Go here for complete details.

  • If you want to use traditional rather than ISO mode, run:
       % ./configure NTL_STD_CXX=off
    

  • If you want to install NTL in the directory $HOME/sw, run:
       % ./configure PREFIX=$HOME/sw
    

There are a number of more esoteric configuration variables that can be set. See config.txt for a complete description.

Note that all of these configuration options can also be set by editing the two files makefile and ../include/NTL/def_config.h by hand. These files are fairly simple and well documented, and so this is not too hard to do.

Note that the file "../include/NTL/def_config.h" contains a backup copy of the original config.h file, and that the file "def_makefile" contains a backup copy of the original makefile file.

This command is intended only as a convenience and -- more importantly -- to allow the configuration process to be script driven. This script does not perform any "magic", like finding out what the local C compiler is called, etc. If the defaults are not correct for your platform, you have to set an appropriate variable.

Step 3. Execute make.

Just type:

   % make

The build process after this point is fully automatic. But here is a description of what happens.

  1. The makefile builds the file "../include/NTL/mach_desc.h", which defines some machine characteristics such as word size and machine precision. This is done by compiling and running a C program called MakeDesc that figures out these characteristics on its own, and prints some diagnostics to the terminal.

  2. A script is run that "automagically" determines the best way to write a timing function on your platform. It tries different routines in the files GetTime1.c, GetTime2.c, etc., and when it finds a good one, it copies the file into GetTime.c.

  3. The file "../include/NTL/gmp_aux.h" is generated for use with GMP. If not using GMP, this files are still created, but it is empty.

  4. The configuration wizard script is run. This script works in a sub-directory, compiling several programs, and performing a number of timing experiments, in order to determine the optimal setting for a number of flags in the file ../include/NTL/config.h. When the script finishes (it may take several minutes), you will be told what the wizard thinks are the best settings, and your config.h file will be automatically updated. Note that any flags you set in Step 2 will be in effect while the wizard runs, and will be retained in the updated config.h file, with the exception of the flags
       NTL_LONG_LONG NTL_AVOID_FLOAT NTL_TBL_REM NTL_AVOID_BRANCHING 
       NTL_SPMM_UL NTL_SPMM_ULL NTL_SPMM_ASM NTL_GF2X_NOINLINE NTL_GF2X_ALTCODE
    
    which are set by the wizard. Also note that if you do not want the wizard to run, you should pass WIZARD=off to the configure script; however, this is not recommended.

  5. The makefile will compile all the source files, and then creates the library "ntl.a" in the current directory.

Note that for finer control you can optionally break up this process into the five component steps:

   % make setup1
   % make setup2
   % make setup3
   % make setup4
   % make ntl.a

After NTL is built.

Executing make check runs a series of timing and test programs. It is a good idea to run this to see if everything really went well.

Executing make install copies a number of files to a directory <prefix> that you specify by passing PREFIX=<prefix> as an argument to configure at configuration time, or as an argument to make install at installation time. The default is /usr/local, so either you need root permissions, or you choose a <prefix> for which you have write permission. The files ../include/NTL/* are copied into <prefix>/include/NTL. The file ntl.a is copied to <prefix>/lib/libntl.a. The files ../doc/* are copied into <prefix>/share/doc/NTL.

You can also "fine tune" the installation procedure further. See the configure documentation for details.

Executing make uninstall undoes make install.

Executing make clobber essentially undoes make. Make sure you do this if you re-build NTL for a different architecture!

Executing make clean will remove object files, but not ntl.a. To rebuild after executing make clean, execute make ntl.a.

Assuming you have installed NTL as above, to compile a program foo.c that uses NTL, execute

   g++  -I<prefix>/include foo.c -o foo  -L<prefix>/lib -lntl  -lm
This compiles foo.c as a C++ program and creates the binary foo.

If you built NTL using GMP, execute:

   g++  -I<prefix>/include foo.c -o foo  -L<prefix>/lib -lntl  -L<gmp_prefix>/lib -lgmp  -lm

Of course, if <prefix> and <gmp_prefix> are the same, you do not need to duplicate the -L flags, and if either are standard directories, like /usr/local, you can leave out the corresponding -I and -L flags altogether.

Similarly, if you built NTL using gf2x, you should include flags

   -L<gf2x_prefix>/lib -lgf2x
on the command line.

This works even if you are not working in the directory in which you built NTL. If you are working in that directory, you can just execute

   make foo

Building a Shared Library

By default, the above installation procedure builds a static library only. Static libraries are nice because the procedures for building and using them are nearly identical across various flavors of Unix. However, static libraries have their drawbacks, and sometimes it is desirable to build a shared library. This can be done (in theory) by simply passing SHARED=on to NTL's configure.

If you set SHARED=on, then behind the scenes, the procedure used by the makefile changes a bit. In particular, the magical GNU program libtool is used to deal with all idiosyncracies of shared libraries. You may need to set the configuration variable LIBTOOL, to point to another version of libtool. For example, on Mac OSX, the built-in command called libtool is not actually the GNU libtool program; in this case, you will want to set LIBTOOL=glibtool. On other systems, it may be necssary to download and install a fresh copy of the libtool program (which can be obtained from here). Note that if SHARED=on, then in addition to using the libtool program, the makefile relies on features specific to GNU make.

Note that if you want to build NTL as a shared library, then if you use them, GMP and gf2x must also be built and installed as shared libraries. Also note that to use a shared library version of NTL, you may have to do something special, like set a special shell variable: the output generated by the libtool program during make install should give specific instructions. In addition, if NTL is built as a shared library, then you typically do not have to include -lgmp (if using GMP), or -lgf2x (if using gf2x), or corresponding -L flags, or -lm on the command line when compiling programs that use NTL.

32-bit and 64-bit ABIs

An ABI (Application Binary Interface) defines the sizes of various C data types. Typically, with a 32-bit ABI, int's and long's are 32 bits, while on a 64-bit ABI, int's are 32 bits and long's are 64 bits. Some platforms support both 64-bit and 32-bit ABI's; typically in such settings, the 64-bit ABI will yield much better performance, while the 32-bit ABI is available for backward compatibility. In addition, the 64-bit ABI may not be the default: if you are using gcc, you need to pass the -m64 flag to the compiler to get the 64-bit ABI.

When compiling NTL, you may want to try running configure with CFLAGS="-O2 -m64" to force a 64-bit ABI -- this may yield a very marked performance improvement.

If you are using NTL with either the GMP or gf2x libraries, then these must be built with the same ABI as NTL. The installation script for GMP will typically select the 64-bit ABI automatically if it is available. The installation script for gf2x may need some hints.

When compiling programs that use NTL, you must also ensure that the program is compiled with the same ABI as NTL. Again, if you want a 64-bit ABI, then just pass the flag -m64 to the compiler.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour-win.html000644 000765 000024 00000026110 12377144460 016045 0ustar00shoupstaff000000 000000 A Tour of NTL: Obtaining and Installing NTL for Windows and other Platforms
[Previous] [Up] [Next]

A Tour of NTL: Obtaining and Installing NTL for Windows and other Platforms


The WinNTL distribution of NTL can be used on any Windows 95 or NT platform (but not on Windows 3.11 or earlier). Actually, there is nothing Windows-specific about WinNTL. The source code is identical to the UNIX NTL distribution; only the packaging is slightly different, and no assumptions are made about the program development environment. Thus, it should be possible to install WinNTL on other operating systems (e.g., Macintosh, OS/2) with little difficulty.

MAC OSX Users: since MAC OSX is essentially just a (rather funny) flavor of Unix, you will be much better served using the Unix distribution.

Obtaining and unpacking NTL.

To obtain the source code and documentation for NTL, download WinNTL-xxx.zip. Here, "xxx" is the current version number. Then unzip this file into a directory (folder). This will unpack everything into a directory called "WinNTL-xxx". Inside this directory, you will find several directories.

  • The directory "doc" contains all of NTL's documentation, including this "tour" ("tour.html") and the ".txt" files explaining each module, which can be accessed directly, or through the "tour".

  • The directory "src" contains all of the source files for the library, all with ".cpp" extensions. The file "lip.cpp" can be compiled as a C source file (this can sometimes yield a marginal performance gain).

  • The directory "include" contains a single directory called "NTL", and the latter contains all of the ".h" files.

Platform dependent macros.

In directory "include/NTL" there is a file called "mach_desc.h", which contains all of the platform-dependent macro definitions. The default settings should be correct for any x86- or Pentium-based system running Windows; however, the correct definitions can depend on the compiler and run-time environment. Therefore, to be on the safe side, you might consider compiling and running the program MakeDesc, whose source files are in directory "MakeDesc". This program will dynamically build a correct "mach_desc.h" for your platform (processor, compiler, run-time environment). To get accurate results, you must compile this program using the level of optimization (or higher) that you will use for NTL. The program will print some diagnostics to the screen, and create the file "mach_desc.h" (in the current directory, and not in the "include/NTL" directory, where it needs to go).

Configuration flags.

Also in directory "include/NTL" is a file called "config.h". You can edit this file to override some of NTL's default options for basic configuration and performance.

Basic configuration options.
Most of the these flags are rather esoteric and can be safely ignored.

One exception to this is the NTL_STD_CXX flag (or perhaps just the NTL_PSTD_NNS flag) which you will want to unset if your compiler is too old to handle it. Go here for details.

Another exception are the flags to use GMP for potentially faster long integer arithmetic. See the GMP section for more details. Note that getting GMP to run on Windows is a pain in the neck. If you really want to use GMP, use Unix or Linux!

Performance options.
These flags let you fine tune for best performance. (If you were using Unix, you could run a script that automatically selects the best settings for your platform.)

TIP for Pentium platforms:

  • Users running on a Pentium, or other x86-like processor, will almost surely want to set the NTL_LONG_LONG flag, or possibly the NTL_AVOID_FLOAT flag, in file config.h to get the best performance for long integer arithmetic. If you set either of these flags, you should also set the NTL_TBL_REM flag as well, to get the best performance for ZZ_pX arithmetic. You might also want to set the NTL_SPMM_ULL or NTL_SMPP_UL flags.
  • These flags can be useful on other platforms as well, especially on processors with slow int/float conversion.
  • The best thing is to experiment, and compile and run program QuickTest to see the impact on the running time of various basic operations.

Note that the file "def_config.h" contains a backup copy of the original config.h file.

Test programs.

The directory "tests" contains several test programs. For each program FooTest, there is a source file "FooTest.cpp", and optionally two files "FooTestIn" and "FooTestOut". If the latter exist, then the program should be run with the "FooTestIn" as standard input; correct output (printed to standard output) should match the contents of "FooTestOut" exactly; note that these programs also print diagnostic output on the screen (through standard error output).

Timing functions.

The directory "GetTime" contains several alternative definitions of the GetTime() function. The file "GetTime.cpp" in the "src" directory should be OK, but your compiler might like one of the definitions in the directory "GetTime" better.

Other tools.

The directory "misc" contains a program newnames.cpp to help make the transition to NTL version 3.5 from earlier versions of NTL. See the changes section for more details. It also contains the programs gen_lip_gmp_aux.cpp and gen_gmp_aux.cpp that automatically generate the auxilliary files needed when using NTL with GMP. You will have to look at the makefile in the Unix distribution to see how to use these.

Compiling NTL.

Since there are a number of incompatible compilers and program development environments available for Windows, no attempt has been made to provide automatic tools for building and testing, as is done for the Unix distribution. Nevertheless, it should be straightforward to install NTL (even if it involves a bit of pointing and clicking). First, compile all of the files in "src", and create a static library. Make sure the compiler knows where to find NTL's include files (directory "include" and not "include/NTL") Then, to compile a program using the library, make sure the compiler knows about the library and the directory of NTL's include files. In any case, if you want to do any serious computations, you will certainly want to compile everything with your compiler's code optimizer on.

For the benefit of those who must use Microsoft Visual C++ on Windows, here are some steps for compiling and using NTL. These steps work with MSVC++ v6. While these steps seem to do the job, there may be other steps that work better. The following steps may be used to build the library, and to build and run program QuickTest, as a simple console application, using the library. The instructions assume you have already unzipped NTL into a directory c:\mystuff, and are running the MSVC++ Development Studio.

I hope these instructions make some sense: I don't know a good language for accuratly describing the particular pointing an clicking steps.


File -> New -> Projects 
   project name: ntl
   location[default]: c:\Program Files\Microsoft Visual Studio\MyProjects\ntl
   Click on Win32 static library
   Click on OK
   pre-compiled headers[default]: no
   MFC support[default]: no
   Click on Finish
   Click on OK

Project -> Add to Project -> Files
   select all files in c:\mystuff\WinNTL-xxx\src and click on OK.

Project -> Settings -> C/C++ 
   Category: Preprocessor.
   Additional include directories: c:\mystuff\WinNTL-xxx\include.
   Click on OK.

Build -> build ntl.lib

File -> New -> Projects -> Win32 Console Application
   project name: test
   location[default]: c:\Program Files\Microsoft Visual Studio\MyProjects\ntl
   Click on Win32 Console Application
   Click on OK
   What kind of windows application...? [default]: An empty project
   Click on Finish
   Click on OK

Project -> Add to Project -> Files
   select the file c:\mystuff\WinNTL-xxx\tests\QuickTest.cpp
   Click on OK

Project -> Add to Project -> Files
   select the file 
      c:\Program Files\Microsoft Visual Studio\MyProjects\ntl\Debug\ntl.lib
   Note: one must select Files of type: Library Files (.lib) to make this
      file visible in the pop-up window.
   Click on OK

Project -> Settings -> C/C++ 
   Category: Preprocessor.
   Additional include directories: c:\mystuff\WinNTL-xxx\include.
   Click on OK.

Build -> build test.exe

Build -> execute test.exe

Further remarks.

TIP: When writing programs using NTL, you should include files using the syntax

   #include <NTL/ZZ.h>
and not using a backslash ("\") as a delimiter.

TIP: When writing windows applications using NTL (as opposed to console applications) you might want to compile your program with the NTL_NO_MIN_MAX macro defined. This suppresses the declaration of several min and max functions in file tools.h that conflict with macro names in the MFC header files. Do not attempt to build the library with this macro defined -- only programs that use the library.

NTL has been successfully installed and tested on Windows 95 platforms with both the Microsoft and Borland compilers.

If you have installed the Unix tools from Cygnus, then you can use the Unix distribution of NTL. This distribution has been specially tailored to work smoothly with Cygnus tools. For many programmers, this is a much more comfortable and reliable program development environment than commercial systems like those from Microsoft and Borland. And moreover, these Unix tools are free. Of course, an even better approach is to install Linux on your PC.

[Previous] [Up] [Next]
ntl-6.2.1/doc/tour.html000644 000765 000024 00000002506 12377144460 015255 0ustar00shoupstaff000000 000000 A Tour of NTL

A Tour of NTL


Table of Contents

  1. Introduction
  2. Examples
  3. Programming Interface
  4. Summary of NTL's Main Modules
  5. Traditional and ISO Modes
  6. Obtaining and Installing NTL for UNIX
  7. Obtaining and Installing NTL for Windows and other Platforms
  8. Tips for Getting the Best Performance out of NTL
  9. NTL Implementation and Portability
  10. Using NTL with GMP
  11. Using NTL with the gf2x library
  12. Some Performance Data
  13. NTL past, present, and future
  14. Summary of Changes
  15. Acknowledgements


Back to NTL page

Back to Victor Shoup's home page ntl-6.2.1/doc/vec_GF2.cpp.html000644 000765 000024 00000033473 12377144460 016267 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vec_GF2.cpp.html


/**************************************************************************\

MODULE: vec_GF2

SUMMARY:


The class Vec<GF2> is explicitly specialized.
It behaves much like a generic Vec<T> (see vector.txt), 
but there are some differences.

For efficiency, elements of a Vec<GF2> are "packed" into a word.
You can still use subscript notation v[i] or v(i).
For const vectors, these evaluate to values of type const GF2.
For non-const vectors, these evaluate to values of the
special type ref_GF2, which is defined in the GF2 header file.

There are implicit conversions from ref_GF2 to const GF2
and from GF2& to ref_GF2.  Therefore, if you want to declare
a function that takes a non-const reference to a GF2, you
should declare the parameter of type ref_GF2: this will
allow you to pass variables of type GF2 as well as 
elements of vec_GF2's obtained through indexing.

As an alternative, one can use the get and put methods below to access
vector elements.

There is one subtle but important difference in the semantics
of Vec<GF2> and that of generic NTL vectors.  With a Vec<GF2>, whenever its
length is increased (via SetLength), the "new" bits are always 0.
For example, if v.length() == 20, then 

   v.SetLength(10); v.setLength(20);

will effectively clear bits 10..19 of v.
This is quite different from the semantics of generic NTL vectors, where
the above sequence would not change the value of v at all.
One has to be aware of this difference, but it will not matter
in most ordinary circumstances.


\**************************************************************************/



template<>
class Vec<GF2> {

public:

   Vec(); // 0 length vector
   Vec(INIT_SIZE_TYPE, long n); // initialize to length n
                                // usage: Vec(INIT_SIZE, n)

   Vec(const Vec<GF2>& a); // copy constructor
   Vec& operator=(const Vec<GF2>& a); // assignment
   ~Vec(); // destructor

   void SetLength(long n); // set length to n bits
   void SetLength(long n, GF2 a);
      // set length to n, if length increases, initialize new bits to a

   void SetMaxLength(long n); // allocate space for n bits

   long length() const; // current length, in bits

   long MaxLength() const; // maximum length, i.e., the maximum
                           // value passed to either SetLength or SetMaxLength
                           // since creation or last kill

   long allocated() const; // number of bits for which space is allocated;
                           // if n <= v.allocated(), then v.SetLength(n)
                           // will not result in any memory re-allocation.

   // INVARIANT: 
   //    length() <= MaxLength() <= allocated() < 2^(NTL_BITS_PER_LONG-4)



   void FixLength(long n); // fix length to n bits
      // can only be applied after default initialization or kill

   long fixed() const; // test if length has been fixed

   void kill(); // free space and make length 0

   const GF2 get(long i) const; // fetch value at index i (indexing from 0)

   void put(long i, GF2 a); // write value a to index i (indexing from 0)
   void put(long i, long a);

// Here are the subscripting operators, defined using the
// "helper" class ref_GF2

   ref_GF2 operator[](long i);
   ref_GF2 operator()(long i);

   const GF2 operator[](long i) const;
   const GF2 operator()(long i) const;


   void swap(Vec<GF2>& y);
   // swap with y (fast: just swaps pointers)

   void append(GF2 a);
   // append a to end of vector

   void append(const Vec<GF2>& w);
   // append w to end of vector


// Some partial STL compatibility...also used
// to interface with the Matrix template class

   typedef GF2 value_type;
   typedef ref_GF2 reference;
   typedef const GF2 const_reference;



};



void swap(Vec<GF2>& x, Vec<GF2>& y);
// swap x and y (fast pointer swap)

void append(Vec<GF2>& v, GF2 a);
// append a to v

void append(Vec<GF2>& v, const Vec<GF2>& a);
// append a to v

// equality operators:

long operator==(const Vec<GF2>& a, const Vec<GF2>& b);
long operator!=(const Vec<GF2>& a, const Vec<GF2>& b);


// I/O operators:

ostream& operator<<(ostream& s, const Vec<GF2>& a);
istream& operator>>(istream& s, Vec<GF2>& a);

// The I/O format is [a_0 a_1 ... a_{n-1}], where each a_i is "0" or "1".
// On input, the a_i may be arbitrary integers, which are reduced mod 2.



typedef Vec<GF2> vec_GF2;  // backward compatibility

// utility routines:

void clear(vec_GF2& x); // clear all bits--length unchanged
long IsZero(const vec_GF2& a); // test if all bits are zero

void shift(vec_GF2& x, const vec_GF2& a, long n);
vec_GF2 shift(const vec_GF2& a, long n);
// x = a shifted n places, where n may be positive or negative.
// Generally, x[i] = a[i-n], so positive n shifts to a higher index.
// The length of x is set to the length of a, and bits 
// are zero-filled or discarded as necessary.

void reverse(vec_GF2& x, const vec_GF2& a); // c = a reversed
vec_GF2 reverse(const vec_GF2& a);

long weight(const vec_GF2& a); // return number of 1 bits in a

void random(vec_GF2& x, long n);  // x = random vector of length n
vec_GF2 random_vec_GF2(long n);


// arithmetic operations over GF(2):

void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b);
void sub(vec_GF2& x, const vec_GF2& a, const vec_GF2& b);
void negate(vec_GF2& x, const vec_GF2& a);

void mul(vec_GF2& x, const vec_GF2& a, GF2 b);
void mul(vec_GF2& x, const vec_GF2& a, long b);

void mul(vec_GF2& x, GF2 a, const vec_GF2& b);
void mul(vec_GF2& x, long a, const vec_GF2& b);
// x = a * b

void InnerProduct(ref_GF2 x, const vec_GF2& a, const vec_GF2& b);
// vectors may differ in length

void VectorCopy(vec_GF2& x, const vec_GF2& a, long n);
vec_GF2 VectorCopy(const vec_GF2& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.



// arithmetic operator notation:

vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b);
vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b);
vec_GF2 operator-(const vec_GF2& a);

// scalar mul:

vec_GF2 operator*(const vec_GF2& a, GF2 b);
vec_GF2 operator*(const vec_GF2& a, long b);

vec_GF2 operator*(GF2 a, const vec_GF2& b);
vec_GF2 operator*(long a, const vec_GF2& b);

// inner product: 

inline GF2 operator*(const vec_GF2& a, const vec_GF2& b);

// assignment operator notation:

vec_GF2& operator+=(vec_GF2& x, const vec_GF2& a);
vec_GF2& operator-=(vec_GF2& x, const vec_GF2& a);

vec_GF2& operator*=(vec_GF2& x, GF2 a);
vec_GF2& operator*=(vec_GF2& x, long a);

ntl-6.2.1/doc/vec_GF2.txt000644 000765 000024 00000014546 12377144460 015361 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vec_GF2 SUMMARY: The class Vec is explicitly specialized. It behaves much like a generic Vec (see vector.txt), but there are some differences. For efficiency, elements of a Vec are "packed" into a word. You can still use subscript notation v[i] or v(i). For const vectors, these evaluate to values of type const GF2. For non-const vectors, these evaluate to values of the special type ref_GF2, which is defined in the GF2 header file. There are implicit conversions from ref_GF2 to const GF2 and from GF2& to ref_GF2. Therefore, if you want to declare a function that takes a non-const reference to a GF2, you should declare the parameter of type ref_GF2: this will allow you to pass variables of type GF2 as well as elements of vec_GF2's obtained through indexing. As an alternative, one can use the get and put methods below to access vector elements. There is one subtle but important difference in the semantics of Vec and that of generic NTL vectors. With a Vec, whenever its length is increased (via SetLength), the "new" bits are always 0. For example, if v.length() == 20, then v.SetLength(10); v.setLength(20); will effectively clear bits 10..19 of v. This is quite different from the semantics of generic NTL vectors, where the above sequence would not change the value of v at all. One has to be aware of this difference, but it will not matter in most ordinary circumstances. \**************************************************************************/ template<> class Vec { public: Vec(); // 0 length vector Vec(INIT_SIZE_TYPE, long n); // initialize to length n // usage: Vec(INIT_SIZE, n) Vec(const Vec& a); // copy constructor Vec& operator=(const Vec& a); // assignment ~Vec(); // destructor void SetLength(long n); // set length to n bits void SetLength(long n, GF2 a); // set length to n, if length increases, initialize new bits to a void SetMaxLength(long n); // allocate space for n bits long length() const; // current length, in bits long MaxLength() const; // maximum length, i.e., the maximum // value passed to either SetLength or SetMaxLength // since creation or last kill long allocated() const; // number of bits for which space is allocated; // if n <= v.allocated(), then v.SetLength(n) // will not result in any memory re-allocation. // INVARIANT: // length() <= MaxLength() <= allocated() < 2^(NTL_BITS_PER_LONG-4) void FixLength(long n); // fix length to n bits // can only be applied after default initialization or kill long fixed() const; // test if length has been fixed void kill(); // free space and make length 0 const GF2 get(long i) const; // fetch value at index i (indexing from 0) void put(long i, GF2 a); // write value a to index i (indexing from 0) void put(long i, long a); // Here are the subscripting operators, defined using the // "helper" class ref_GF2 ref_GF2 operator[](long i); ref_GF2 operator()(long i); const GF2 operator[](long i) const; const GF2 operator()(long i) const; void swap(Vec& y); // swap with y (fast: just swaps pointers) void append(GF2 a); // append a to end of vector void append(const Vec& w); // append w to end of vector // Some partial STL compatibility...also used // to interface with the Matrix template class typedef GF2 value_type; typedef ref_GF2 reference; typedef const GF2 const_reference; }; void swap(Vec& x, Vec& y); // swap x and y (fast pointer swap) void append(Vec& v, GF2 a); // append a to v void append(Vec& v, const Vec& a); // append a to v // equality operators: long operator==(const Vec& a, const Vec& b); long operator!=(const Vec& a, const Vec& b); // I/O operators: ostream& operator<<(ostream& s, const Vec& a); istream& operator>>(istream& s, Vec& a); // The I/O format is [a_0 a_1 ... a_{n-1}], where each a_i is "0" or "1". // On input, the a_i may be arbitrary integers, which are reduced mod 2. typedef Vec vec_GF2; // backward compatibility // utility routines: void clear(vec_GF2& x); // clear all bits--length unchanged long IsZero(const vec_GF2& a); // test if all bits are zero void shift(vec_GF2& x, const vec_GF2& a, long n); vec_GF2 shift(const vec_GF2& a, long n); // x = a shifted n places, where n may be positive or negative. // Generally, x[i] = a[i-n], so positive n shifts to a higher index. // The length of x is set to the length of a, and bits // are zero-filled or discarded as necessary. void reverse(vec_GF2& x, const vec_GF2& a); // c = a reversed vec_GF2 reverse(const vec_GF2& a); long weight(const vec_GF2& a); // return number of 1 bits in a void random(vec_GF2& x, long n); // x = random vector of length n vec_GF2 random_vec_GF2(long n); // arithmetic operations over GF(2): void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b); void sub(vec_GF2& x, const vec_GF2& a, const vec_GF2& b); void negate(vec_GF2& x, const vec_GF2& a); void mul(vec_GF2& x, const vec_GF2& a, GF2 b); void mul(vec_GF2& x, const vec_GF2& a, long b); void mul(vec_GF2& x, GF2 a, const vec_GF2& b); void mul(vec_GF2& x, long a, const vec_GF2& b); // x = a * b void InnerProduct(ref_GF2 x, const vec_GF2& a, const vec_GF2& b); // vectors may differ in length void VectorCopy(vec_GF2& x, const vec_GF2& a, long n); vec_GF2 VectorCopy(const vec_GF2& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // arithmetic operator notation: vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b); vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b); vec_GF2 operator-(const vec_GF2& a); // scalar mul: vec_GF2 operator*(const vec_GF2& a, GF2 b); vec_GF2 operator*(const vec_GF2& a, long b); vec_GF2 operator*(GF2 a, const vec_GF2& b); vec_GF2 operator*(long a, const vec_GF2& b); // inner product: inline GF2 operator*(const vec_GF2& a, const vec_GF2& b); // assignment operator notation: vec_GF2& operator+=(vec_GF2& x, const vec_GF2& a); vec_GF2& operator-=(vec_GF2& x, const vec_GF2& a); vec_GF2& operator*=(vec_GF2& x, GF2 a); vec_GF2& operator*=(vec_GF2& x, long a); ntl-6.2.1/doc/vec_GF2E.cpp.html000644 000765 000024 00000015611 12377144460 016366 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vec_GF2E.cpp.html

/**************************************************************************\

MODULE: vec_GF2E

SUMMARY:

Provides vectors over GF2E, along with some related operations.

\**************************************************************************/

#include <NTL/GF2E.h>
#include <NTL/vector.h>


typedef Vec<GF2E> vec_GF2E; // backward compatibility

void mul(vec_GF2E& x, const vec_GF2E& a, const GF2E& b);
void mul(vec_GF2E& x, const vec_GF2E& a, GF2 b);
void mul(vec_GF2E& x, const vec_GF2E& a, long b);

void mul(vec_GF2E& x, const GF2E& a, const vec_GF2E& b);
void mul(vec_GF2E& x, GF2 a, const vec_GF2E& b);
void mul(vec_GF2E& x, long a, const vec_GF2E& b);
// x = a * b

void add(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b);
// x = a + b

void sub(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b);
// x = a - b = x + a

void negate(vec_GF2E& x, const vec_GF2E& a);
// x = - a = a

void clear(vec_GF2E& x);
// x = 0 (length unchanged)

long IsZero(const vec_GF2E& a);
// test if a is the zero vector



void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), b.length())

void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

void VectorCopy(vec_GF2E& x, const vec_GF2E& a, long n);
vec_GF2E VectorCopy(const vec_GF2E& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.



// operator notation:

vec_GF2E
operator+(const vec_GF2E& a, const vec_GF2E& b);

vec_GF2E
operator-(const vec_GF2E& a, const vec_GF2E& b);

vec_GF2E operator-(const vec_GF2E& a);


// vector/scalar multiplication:

vec_GF2E operator*(const vec_GF2E& a, const GF2E& b);
vec_GF2E operator*(const vec_GF2E& a, GF2 b);
vec_GF2E operator*(const vec_GF2E& a, long b);

vec_GF2E operator*(const GF2E& a, const vec_GF2E& b);
vec_GF2E operator*(GF2 a, const vec_GF2E& b);
vec_GF2E operator*(long a, const vec_GF2E& b);

// inner product:

GF2E operator*(const vec_GF2E& a, const vec_GF2E& b);


// assignment operator notation:

vec_GF2E& operator+=(vec_GF2E& x, const vec_GF2E& a);
vec_GF2E& operator-=(vec_GF2E& x, const vec_GF2E& a);

vec_GF2E& operator*=(vec_GF2E& x, const GF2E& a);
vec_GF2E& operator*=(vec_GF2E& x, GF2 a);
vec_GF2E& operator*=(vec_GF2E& x, long a);



// Implementation note: the BlockConstruct routine has been customized
// for GF2E so that when a vec_GF2E is grown, space for the needed
// elements is allocated in one contiguous chunk.  This saves on calls to
// malloc and free, and should also yield better locality of reference.
// One consequence of this is that swapping an element of a vec_GF2E
// with another GF2E can not be implemented by pointer swap, and will in
// this case be done by copy.
ntl-6.2.1/doc/vec_GF2E.txt000644 000765 000024 00000005510 12377144460 015455 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vec_GF2E SUMMARY: Provides vectors over GF2E, along with some related operations. \**************************************************************************/ #include #include typedef Vec vec_GF2E; // backward compatibility void mul(vec_GF2E& x, const vec_GF2E& a, const GF2E& b); void mul(vec_GF2E& x, const vec_GF2E& a, GF2 b); void mul(vec_GF2E& x, const vec_GF2E& a, long b); void mul(vec_GF2E& x, const GF2E& a, const vec_GF2E& b); void mul(vec_GF2E& x, GF2 a, const vec_GF2E& b); void mul(vec_GF2E& x, long a, const vec_GF2E& b); // x = a * b void add(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b); // x = a + b void sub(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b); // x = a - b = x + a void negate(vec_GF2E& x, const vec_GF2E& a); // x = - a = a void clear(vec_GF2E& x); // x = 0 (length unchanged) long IsZero(const vec_GF2E& a); // test if a is the zero vector void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), b.length()) void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) void VectorCopy(vec_GF2E& x, const vec_GF2E& a, long n); vec_GF2E VectorCopy(const vec_GF2E& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // operator notation: vec_GF2E operator+(const vec_GF2E& a, const vec_GF2E& b); vec_GF2E operator-(const vec_GF2E& a, const vec_GF2E& b); vec_GF2E operator-(const vec_GF2E& a); // vector/scalar multiplication: vec_GF2E operator*(const vec_GF2E& a, const GF2E& b); vec_GF2E operator*(const vec_GF2E& a, GF2 b); vec_GF2E operator*(const vec_GF2E& a, long b); vec_GF2E operator*(const GF2E& a, const vec_GF2E& b); vec_GF2E operator*(GF2 a, const vec_GF2E& b); vec_GF2E operator*(long a, const vec_GF2E& b); // inner product: GF2E operator*(const vec_GF2E& a, const vec_GF2E& b); // assignment operator notation: vec_GF2E& operator+=(vec_GF2E& x, const vec_GF2E& a); vec_GF2E& operator-=(vec_GF2E& x, const vec_GF2E& a); vec_GF2E& operator*=(vec_GF2E& x, const GF2E& a); vec_GF2E& operator*=(vec_GF2E& x, GF2 a); vec_GF2E& operator*=(vec_GF2E& x, long a); // Implementation note: the BlockConstruct routine has been customized // for GF2E so that when a vec_GF2E is grown, space for the needed // elements is allocated in one contiguous chunk. This saves on calls to // malloc and free, and should also yield better locality of reference. // One consequence of this is that swapping an element of a vec_GF2E // with another GF2E can not be implemented by pointer swap, and will in // this case be done by copy. ntl-6.2.1/doc/vec_RR.cpp.html000644 000765 000024 00000012034 12377144460 016222 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vec_RR.cpp.html

/**************************************************************************\

MODULE: vec_RR

SUMMARY:

Defines the class vec_RR.

\**************************************************************************/


typedef Vec<RR> vec_RR; // backward compatibility

void mul(vec_RR& x, const vec_RR& a, const RR& b);
void mul(vec_RR& x, const vec_RR& a, double b);

void mul(vec_RR& x, const RR& a, const vec_RR& b);
void mul(vec_RR& x, double a, const vec_RR& b);
// x = a * b


void add(vec_RR& x, const vec_RR& a, const vec_RR& b);
// x = a + b

void sub(vec_RR& x, const vec_RR& a, const vec_RR& b);
// x = a - b

void clear(vec_RR& x);
// x = 0 (length unchanged)

void negate(vec_RR& x, const vec_RR& a);
// x = -a

long IsZero(const vec_RR& a);
// test if a is the zero vector


void InnerProduct(RR& x, const vec_RR& a, const vec_RR& b);
// x = inner product of a and b, padded with zeros to make the lengths
// even.

void VectorCopy(vec_RR& x, const vec_RR& a, long n);
vec_RR VectorCopy(const vec_RR& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.


// operator notation:

vec_RR operator+(const vec_RR& a, const vec_RR& b);
vec_RR operator-(const vec_RR& a, const vec_RR& b);

vec_RR operator-(const vec_RR& a);


// vector/scalar multiplication:

vec_RR operator*(const vec_RR& a, const RR& b);
vec_RR operator*(const vec_RR& a, double b);

vec_RR operator*(const RR& a, const vec_RR& b);
vec_RR operator*(double a, const vec_RR& b);

// inner product:

RR operator*(const vec_RR& a, const vec_RR& b);


// assignment operator notation:

vec_RR& operator+=(vec_RR& x, const vec_RR& a);
vec_RR& operator-=(vec_RR& x, const vec_RR& a);

vec_RR& operator*=(vec_RR& x, const RR& a);
vec_RR& operator*=(vec_RR& x, double a);


ntl-6.2.1/doc/vec_RR.txt000644 000765 000024 00000003407 12377144460 015320 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vec_RR SUMMARY: Defines the class vec_RR. \**************************************************************************/ typedef Vec vec_RR; // backward compatibility void mul(vec_RR& x, const vec_RR& a, const RR& b); void mul(vec_RR& x, const vec_RR& a, double b); void mul(vec_RR& x, const RR& a, const vec_RR& b); void mul(vec_RR& x, double a, const vec_RR& b); // x = a * b void add(vec_RR& x, const vec_RR& a, const vec_RR& b); // x = a + b void sub(vec_RR& x, const vec_RR& a, const vec_RR& b); // x = a - b void clear(vec_RR& x); // x = 0 (length unchanged) void negate(vec_RR& x, const vec_RR& a); // x = -a long IsZero(const vec_RR& a); // test if a is the zero vector void InnerProduct(RR& x, const vec_RR& a, const vec_RR& b); // x = inner product of a and b, padded with zeros to make the lengths // even. void VectorCopy(vec_RR& x, const vec_RR& a, long n); vec_RR VectorCopy(const vec_RR& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // operator notation: vec_RR operator+(const vec_RR& a, const vec_RR& b); vec_RR operator-(const vec_RR& a, const vec_RR& b); vec_RR operator-(const vec_RR& a); // vector/scalar multiplication: vec_RR operator*(const vec_RR& a, const RR& b); vec_RR operator*(const vec_RR& a, double b); vec_RR operator*(const RR& a, const vec_RR& b); vec_RR operator*(double a, const vec_RR& b); // inner product: RR operator*(const vec_RR& a, const vec_RR& b); // assignment operator notation: vec_RR& operator+=(vec_RR& x, const vec_RR& a); vec_RR& operator-=(vec_RR& x, const vec_RR& a); vec_RR& operator*=(vec_RR& x, const RR& a); vec_RR& operator*=(vec_RR& x, double a); ntl-6.2.1/doc/vec_ZZ.cpp.html000644 000765 000024 00000012021 12377144460 016236 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vec_ZZ.cpp.html

/**************************************************************************\

MODULE: vec_ZZ

SUMMARY:

Defines the class vec_ZZ.

\**************************************************************************/


typedef Vec<ZZ> vec_ZZ; // backward compatibility

void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b);
void mul(vec_ZZ& x, const vec_ZZ& a, long b);

void mul(vec_ZZ& x, const ZZ& a, const vec_ZZ& b);
void mul(vec_ZZ& x, long a, const vec_ZZ& b);
// x = a * b

void add(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b);
// x = a + b

void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b);
// x = a - b

void clear(vec_ZZ& x);
// x = 0 (length unchanged)

void negate(vec_ZZ& x, const vec_ZZ& a);
// x = -a

long IsZero(const vec_ZZ& a);
// test if a is the zero vector

void InnerProduct(ZZ& x, const vec_ZZ& a, const vec_ZZ& b);
// x = inner product of a and b, padded with zeros to make the lengths
// even.

void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n);
vec_ZZ VectorCopy(const vec_ZZ& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.


// operator notation:

vec_ZZ operator+(const vec_ZZ& a, const vec_ZZ& b);
vec_ZZ operator-(const vec_ZZ& a, const vec_ZZ& b);

vec_ZZ operator-(const vec_ZZ& a);


// vector/scalar multiplication:

vec_ZZ operator*(const vec_ZZ& a, const ZZ& b);
vec_ZZ operator*(const vec_ZZ& a, long b);

vec_ZZ operator*(const ZZ& a, const vec_ZZ& b);
vec_ZZ operator*(long a, const vec_ZZ& b);

// inner product:

ZZ operator*(const vec_ZZ& a, const vec_ZZ& b);



// assignment operator notation:

vec_ZZ& operator+=(vec_ZZ& x, const vec_ZZ& a);
vec_ZZ& operator-=(vec_ZZ& x, const vec_ZZ& a);

vec_ZZ& operator*=(vec_ZZ& x, const ZZ& a);
vec_ZZ& operator*=(vec_ZZ& x, long a);


ntl-6.2.1/doc/vec_ZZ.txt000644 000765 000024 00000003374 12377144460 015343 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vec_ZZ SUMMARY: Defines the class vec_ZZ. \**************************************************************************/ typedef Vec vec_ZZ; // backward compatibility void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b); void mul(vec_ZZ& x, const vec_ZZ& a, long b); void mul(vec_ZZ& x, const ZZ& a, const vec_ZZ& b); void mul(vec_ZZ& x, long a, const vec_ZZ& b); // x = a * b void add(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b); // x = a + b void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b); // x = a - b void clear(vec_ZZ& x); // x = 0 (length unchanged) void negate(vec_ZZ& x, const vec_ZZ& a); // x = -a long IsZero(const vec_ZZ& a); // test if a is the zero vector void InnerProduct(ZZ& x, const vec_ZZ& a, const vec_ZZ& b); // x = inner product of a and b, padded with zeros to make the lengths // even. void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n); vec_ZZ VectorCopy(const vec_ZZ& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // operator notation: vec_ZZ operator+(const vec_ZZ& a, const vec_ZZ& b); vec_ZZ operator-(const vec_ZZ& a, const vec_ZZ& b); vec_ZZ operator-(const vec_ZZ& a); // vector/scalar multiplication: vec_ZZ operator*(const vec_ZZ& a, const ZZ& b); vec_ZZ operator*(const vec_ZZ& a, long b); vec_ZZ operator*(const ZZ& a, const vec_ZZ& b); vec_ZZ operator*(long a, const vec_ZZ& b); // inner product: ZZ operator*(const vec_ZZ& a, const vec_ZZ& b); // assignment operator notation: vec_ZZ& operator+=(vec_ZZ& x, const vec_ZZ& a); vec_ZZ& operator-=(vec_ZZ& x, const vec_ZZ& a); vec_ZZ& operator*=(vec_ZZ& x, const ZZ& a); vec_ZZ& operator*=(vec_ZZ& x, long a); ntl-6.2.1/doc/vec_ZZ_p.cpp.html000644 000765 000024 00000014763 12377144460 016574 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vec_ZZ_p.cpp.html

/**************************************************************************\

MODULE: vec_ZZ_p

SUMMARY:

Provides vectors over ZZ_p, along with some related operations.

\**************************************************************************/

#include <NTL/ZZ_p.h>
#include <NTL/vec_ZZ.h>
#include <NTL/vector.h>


typedef Vec<ZZ_p> vec_ZZ_p; // backward compatibility

void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_p& b);
void mul(vec_ZZ_p& x, const vec_ZZ_p& a, long b);

void mul(vec_ZZ_p& x, const ZZ_p& a, const vec_ZZ_p& b);
void mul(vec_ZZ_p& x, long a, const vec_ZZ_p& b);
// x = a * b

void add(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b);
// x = a + b

void sub(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b);
// x = a - b

void clear(vec_ZZ_p& x);
// x = 0 (length unchanged)

void negate(vec_ZZ_p& x, const vec_ZZ_p& a);
// x = -a

long IsZero(const vec_ZZ_p& a);
// test if a is the zero vector


void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(),
// b.length())

void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

void VectorCopy(vec_ZZ_p& x, const vec_ZZ_p& a, long n);
vec_ZZ_p VectorCopy(const vec_ZZ_p& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.





// operator notation:

vec_ZZ_p operator+(const vec_ZZ_p& a, const vec_ZZ_p& b);
vec_ZZ_p operator-(const vec_ZZ_p& a, const vec_ZZ_p& b);

vec_ZZ_p operator-(const vec_ZZ_p& a);


// vector/scalar multiplication:

vec_ZZ_p operator*(const vec_ZZ_p& a, const ZZ_p& b);
vec_ZZ_p operator*(const vec_ZZ_p& a, long b);

vec_ZZ_p operator*(const ZZ_p& a, const vec_ZZ_p& b);
vec_ZZ_p operator*(long a, const vec_ZZ_p& b);

// inner product:

ZZ_p operator*(const vec_ZZ_p& a, const vec_ZZ_p& b);


// assignment operator notation:

vec_ZZ_p& operator+=(vec_ZZ_p& x, const vec_ZZ_p& a);
vec_ZZ_p& operator-=(vec_ZZ_p& x, const vec_ZZ_p& a);

vec_ZZ_p& operator*=(vec_ZZ_p& x, const ZZ_p& a);
vec_ZZ_p& operator*=(vec_ZZ_p& x, long a);



// Implementation note: the BlockConstruct routine has been customized
// for ZZ_p so that when a vec_ZZ_p is grown, space for the needed
// elements is allocated in one contiguous chunk.  This saves on calls to
// malloc and free, and should also yield better locality of reference.
// One connsequence of this is that swapping an element of a vec_ZZ_p
// with another ZZ_p can not be implemented by pointer swap, and will in
// this case be done by copy.
ntl-6.2.1/doc/vec_ZZ_p.txt000644 000765 000024 00000005155 12377144460 015661 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vec_ZZ_p SUMMARY: Provides vectors over ZZ_p, along with some related operations. \**************************************************************************/ #include #include #include typedef Vec vec_ZZ_p; // backward compatibility void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_p& b); void mul(vec_ZZ_p& x, const vec_ZZ_p& a, long b); void mul(vec_ZZ_p& x, const ZZ_p& a, const vec_ZZ_p& b); void mul(vec_ZZ_p& x, long a, const vec_ZZ_p& b); // x = a * b void add(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); // x = a + b void sub(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); // x = a - b void clear(vec_ZZ_p& x); // x = 0 (length unchanged) void negate(vec_ZZ_p& x, const vec_ZZ_p& a); // x = -a long IsZero(const vec_ZZ_p& a); // test if a is the zero vector void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), // b.length()) void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) void VectorCopy(vec_ZZ_p& x, const vec_ZZ_p& a, long n); vec_ZZ_p VectorCopy(const vec_ZZ_p& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // operator notation: vec_ZZ_p operator+(const vec_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator-(const vec_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator-(const vec_ZZ_p& a); // vector/scalar multiplication: vec_ZZ_p operator*(const vec_ZZ_p& a, const ZZ_p& b); vec_ZZ_p operator*(const vec_ZZ_p& a, long b); vec_ZZ_p operator*(const ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator*(long a, const vec_ZZ_p& b); // inner product: ZZ_p operator*(const vec_ZZ_p& a, const vec_ZZ_p& b); // assignment operator notation: vec_ZZ_p& operator+=(vec_ZZ_p& x, const vec_ZZ_p& a); vec_ZZ_p& operator-=(vec_ZZ_p& x, const vec_ZZ_p& a); vec_ZZ_p& operator*=(vec_ZZ_p& x, const ZZ_p& a); vec_ZZ_p& operator*=(vec_ZZ_p& x, long a); // Implementation note: the BlockConstruct routine has been customized // for ZZ_p so that when a vec_ZZ_p is grown, space for the needed // elements is allocated in one contiguous chunk. This saves on calls to // malloc and free, and should also yield better locality of reference. // One connsequence of this is that swapping an element of a vec_ZZ_p // with another ZZ_p can not be implemented by pointer swap, and will in // this case be done by copy. ntl-6.2.1/doc/vec_ZZ_pE.cpp.html000644 000765 000024 00000015151 12377144460 016671 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vec_ZZ_pE.cpp.html

/**************************************************************************\

MODULE: vec_ZZ_pE

SUMMARY:

Provides vectors over ZZ_pE, along with some related operations.

\**************************************************************************/

#include <NTL/ZZ_pE.h>
#include <NTL/vec_ZZ.h>
#include <NTL/vector.h>

typedef Vec<ZZ_pE> vec_ZZ_pE; // backward compatibility

void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pE& b);
void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_p& b);
void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, long b);

void mul(vec_ZZ_pE& x, const ZZ_pE& a, const vec_ZZ_pE& b);
void mul(vec_ZZ_pE& x, const ZZ_p& a, const vec_ZZ_pE& b);
void mul(vec_ZZ_pE& x, long a, const vec_ZZ_pE& b);
// x = a * b

void add(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b);
// x = a + b

void sub(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b);
// x = a - b

void clear(vec_ZZ_pE& x);
// x = 0 (length unchanged)

void negate(vec_ZZ_pE& x, const vec_ZZ_pE& a);
// x = -a

long IsZero(const vec_ZZ_pE& a);
// test if a is the zero vector


void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(),
// b.length())

void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

void VectorCopy(vec_ZZ_pE& x, const vec_ZZ_pE& a, long n);
vec_ZZ_pE VectorCopy(const vec_ZZ_pE& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.





// operator notation:

vec_ZZ_pE operator+(const vec_ZZ_pE& a, const vec_ZZ_pE& b);
vec_ZZ_pE operator-(const vec_ZZ_pE& a, const vec_ZZ_pE& b);

vec_ZZ_pE operator-(const vec_ZZ_pE& a);


// vector/scalar multiplication:

vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_pE& b);
vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_p& b);
vec_ZZ_pE operator*(const vec_ZZ_pE& a, long b);

vec_ZZ_pE operator*(const ZZ_pE& a, const vec_ZZ_pE& b);
vec_ZZ_pE operator*(const ZZ_p& a, const vec_ZZ_pE& b);
vec_ZZ_pE operator*(long a, const vec_ZZ_pE& b);

// inner product:

ZZ_pE operator*(const vec_ZZ_pE& a, const vec_ZZ_pE& b);


// assignment operator notation:

vec_ZZ_pE& operator+=(vec_ZZ_pE& x, const vec_ZZ_pE& a);
vec_ZZ_pE& operator-=(vec_ZZ_pE& x, const vec_ZZ_pE& a);

vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_pE& a);
vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_p& a);
vec_ZZ_pE& operator*=(vec_ZZ_pE& x, long a);

ntl-6.2.1/doc/vec_ZZ_pE.txt000644 000765 000024 00000004776 12377144460 015776 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vec_ZZ_pE SUMMARY: Provides vectors over ZZ_pE, along with some related operations. \**************************************************************************/ #include #include #include typedef Vec vec_ZZ_pE; // backward compatibility void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pE& b); void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_p& b); void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, long b); void mul(vec_ZZ_pE& x, const ZZ_pE& a, const vec_ZZ_pE& b); void mul(vec_ZZ_pE& x, const ZZ_p& a, const vec_ZZ_pE& b); void mul(vec_ZZ_pE& x, long a, const vec_ZZ_pE& b); // x = a * b void add(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); // x = a + b void sub(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); // x = a - b void clear(vec_ZZ_pE& x); // x = 0 (length unchanged) void negate(vec_ZZ_pE& x, const vec_ZZ_pE& a); // x = -a long IsZero(const vec_ZZ_pE& a); // test if a is the zero vector void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), // b.length()) void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) void VectorCopy(vec_ZZ_pE& x, const vec_ZZ_pE& a, long n); vec_ZZ_pE VectorCopy(const vec_ZZ_pE& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // operator notation: vec_ZZ_pE operator+(const vec_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator-(const vec_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator-(const vec_ZZ_pE& a); // vector/scalar multiplication: vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_pE& b); vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_p& b); vec_ZZ_pE operator*(const vec_ZZ_pE& a, long b); vec_ZZ_pE operator*(const ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator*(const ZZ_p& a, const vec_ZZ_pE& b); vec_ZZ_pE operator*(long a, const vec_ZZ_pE& b); // inner product: ZZ_pE operator*(const vec_ZZ_pE& a, const vec_ZZ_pE& b); // assignment operator notation: vec_ZZ_pE& operator+=(vec_ZZ_pE& x, const vec_ZZ_pE& a); vec_ZZ_pE& operator-=(vec_ZZ_pE& x, const vec_ZZ_pE& a); vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_pE& a); vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_p& a); vec_ZZ_pE& operator*=(vec_ZZ_pE& x, long a); ntl-6.2.1/doc/vec_lzz_p.cpp.html000644 000765 000024 00000014242 12377144460 017040 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vec_lzz_p.cpp.html

/**************************************************************************\

MODULE: vec_zz_p

SUMMARY:

Provides vectors over zz_p, along with some related operations.

\**************************************************************************/

#include "zz_p.h"
#include "vec_zz.h"
#include <NTL/vector.h>

typedef Vec<zz_p> vec_zz_p; // backward compatibility

void mul(vec_zz_p& x, const vec_zz_p& a, zz_p b);
void mul(vec_zz_p& x, const vec_zz_p& a, long b);

void mul(vec_zz_p& x, zz_p a, const vec_zz_p& b);
void mul(vec_zz_p& x, long a, const vec_zz_p& b);
// x = a * b

void add(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b);
// x = a + b

void sub(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b);
// x = a - b

void clear(vec_zz_p& x);
// x = 0 (length unchanged)

void negate(vec_zz_p& x, const vec_zz_p& a);
// x = -a

long IsZero(const vec_zz_p& a);
// test if a is the zero vector

void VectorCopy(vec_zz_p& x, const vec_zz_p& a, long n);
vec_zz_p VectorCopy(const vec_zz_p& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.



void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(),
// b.length())

void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

long CRT(vec_ZZ& a, ZZ& prod, const vec_zz_p& A);
// Incremental Chinese Remaindering: If p is the current zz_p modulus with
// (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p,
// with coefficients in the interval (-p*prod/2, p*prod/2]; 
// Sets a := a', prod := p*prod, and returns 1 if a's value changed.


// operator notation:

vec_zz_p operator+(const vec_zz_p& a, const vec_zz_p& b);
vec_zz_p operator-(const vec_zz_p& a, const vec_zz_p& b);

vec_zz_p operator-(const vec_zz_p& a);


// vector/scalar multiplication:

vec_zz_p operator*(const vec_zz_p& a, zz_p b);
vec_zz_p operator*(const vec_zz_p& a, long b);

vec_zz_p operator*(zz_p a, const vec_zz_p& b);
vec_zz_p operator*(long a, const vec_zz_p& b);


// inner product:

zz_p operator*(const vec_zz_p& a, const vec_zz_p& b);



// assignment operator notation:

vec_zz_p& operator+=(vec_zz_p& x, const vec_zz_p& a);
vec_zz_p& operator-=(vec_zz_p& x, const vec_zz_p& a);

vec_zz_p& operator*=(vec_zz_p& x, zz_p a);
vec_zz_p& operator*=(vec_zz_p& x, long a);

ntl-6.2.1/doc/vec_lzz_p.txt000644 000765 000024 00000004700 12377144460 016130 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vec_zz_p SUMMARY: Provides vectors over zz_p, along with some related operations. \**************************************************************************/ #include "zz_p.h" #include "vec_zz.h" #include typedef Vec vec_zz_p; // backward compatibility void mul(vec_zz_p& x, const vec_zz_p& a, zz_p b); void mul(vec_zz_p& x, const vec_zz_p& a, long b); void mul(vec_zz_p& x, zz_p a, const vec_zz_p& b); void mul(vec_zz_p& x, long a, const vec_zz_p& b); // x = a * b void add(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b); // x = a + b void sub(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b); // x = a - b void clear(vec_zz_p& x); // x = 0 (length unchanged) void negate(vec_zz_p& x, const vec_zz_p& a); // x = -a long IsZero(const vec_zz_p& a); // test if a is the zero vector void VectorCopy(vec_zz_p& x, const vec_zz_p& a, long n); vec_zz_p VectorCopy(const vec_zz_p& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), // b.length()) void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) long CRT(vec_ZZ& a, ZZ& prod, const vec_zz_p& A); // Incremental Chinese Remaindering: If p is the current zz_p modulus with // (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p, // with coefficients in the interval (-p*prod/2, p*prod/2]; // Sets a := a', prod := p*prod, and returns 1 if a's value changed. // operator notation: vec_zz_p operator+(const vec_zz_p& a, const vec_zz_p& b); vec_zz_p operator-(const vec_zz_p& a, const vec_zz_p& b); vec_zz_p operator-(const vec_zz_p& a); // vector/scalar multiplication: vec_zz_p operator*(const vec_zz_p& a, zz_p b); vec_zz_p operator*(const vec_zz_p& a, long b); vec_zz_p operator*(zz_p a, const vec_zz_p& b); vec_zz_p operator*(long a, const vec_zz_p& b); // inner product: zz_p operator*(const vec_zz_p& a, const vec_zz_p& b); // assignment operator notation: vec_zz_p& operator+=(vec_zz_p& x, const vec_zz_p& a); vec_zz_p& operator-=(vec_zz_p& x, const vec_zz_p& a); vec_zz_p& operator*=(vec_zz_p& x, zz_p a); vec_zz_p& operator*=(vec_zz_p& x, long a); ntl-6.2.1/doc/vec_lzz_pE.cpp.html000644 000765 000024 00000015153 12377144460 017147 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vec_lzz_pE.cpp.html

/**************************************************************************\

MODULE: vec_zz_pE

SUMMARY:

Provides vectors over zz_pE, along with some related operations.

\**************************************************************************/

#include <NTL/lzz_pE.h>
#include <NTL/vec_ZZ.h>
#include <NTL/vector.h>

typedef Vec<zz_pE> vec_zz_pE; // backward compatibility

void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_pE& b);
void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_p& b);
void mul(vec_zz_pE& x, const vec_zz_pE& a, long b);

void mul(vec_zz_pE& x, const zz_pE& a, const vec_zz_pE& b);
void mul(vec_zz_pE& x, const zz_p& a, const vec_zz_pE& b);
void mul(vec_zz_pE& x, long a, const vec_zz_pE& b);
// x = a * b

void add(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b);
// x = a + b

void sub(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b);
// x = a - b

void clear(vec_zz_pE& x);
// x = 0 (length unchanged)

void negate(vec_zz_pE& x, const vec_zz_pE& a);
// x = -a

long IsZero(const vec_zz_pE& a);
// test if a is the zero vector


void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(),
// b.length())

void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

void VectorCopy(vec_zz_pE& x, const vec_zz_pE& a, long n);
vec_zz_pE VectorCopy(const vec_zz_pE& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.





// operator notation:

vec_zz_pE operator+(const vec_zz_pE& a, const vec_zz_pE& b);
vec_zz_pE operator-(const vec_zz_pE& a, const vec_zz_pE& b);

vec_zz_pE operator-(const vec_zz_pE& a);


// vector/scalar multiplication:

vec_zz_pE operator*(const vec_zz_pE& a, const zz_pE& b);
vec_zz_pE operator*(const vec_zz_pE& a, const zz_p& b);
vec_zz_pE operator*(const vec_zz_pE& a, long b);

vec_zz_pE operator*(const zz_pE& a, const vec_zz_pE& b);
vec_zz_pE operator*(const zz_p& a, const vec_zz_pE& b);
vec_zz_pE operator*(long a, const vec_zz_pE& b);

// inner product:

zz_pE operator*(const vec_zz_pE& a, const vec_zz_pE& b);


// assignment operator notation:

vec_zz_pE& operator+=(vec_zz_pE& x, const vec_zz_pE& a);
vec_zz_pE& operator-=(vec_zz_pE& x, const vec_zz_pE& a);

vec_zz_pE& operator*=(vec_zz_pE& x, const zz_pE& a);
vec_zz_pE& operator*=(vec_zz_pE& x, const zz_p& a);
vec_zz_pE& operator*=(vec_zz_pE& x, long a);

ntl-6.2.1/doc/vec_lzz_pE.txt000644 000765 000024 00000004777 12377144460 016253 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vec_zz_pE SUMMARY: Provides vectors over zz_pE, along with some related operations. \**************************************************************************/ #include #include #include typedef Vec vec_zz_pE; // backward compatibility void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_pE& b); void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_p& b); void mul(vec_zz_pE& x, const vec_zz_pE& a, long b); void mul(vec_zz_pE& x, const zz_pE& a, const vec_zz_pE& b); void mul(vec_zz_pE& x, const zz_p& a, const vec_zz_pE& b); void mul(vec_zz_pE& x, long a, const vec_zz_pE& b); // x = a * b void add(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); // x = a + b void sub(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); // x = a - b void clear(vec_zz_pE& x); // x = 0 (length unchanged) void negate(vec_zz_pE& x, const vec_zz_pE& a); // x = -a long IsZero(const vec_zz_pE& a); // test if a is the zero vector void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), // b.length()) void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) void VectorCopy(vec_zz_pE& x, const vec_zz_pE& a, long n); vec_zz_pE VectorCopy(const vec_zz_pE& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // operator notation: vec_zz_pE operator+(const vec_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator-(const vec_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator-(const vec_zz_pE& a); // vector/scalar multiplication: vec_zz_pE operator*(const vec_zz_pE& a, const zz_pE& b); vec_zz_pE operator*(const vec_zz_pE& a, const zz_p& b); vec_zz_pE operator*(const vec_zz_pE& a, long b); vec_zz_pE operator*(const zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator*(const zz_p& a, const vec_zz_pE& b); vec_zz_pE operator*(long a, const vec_zz_pE& b); // inner product: zz_pE operator*(const vec_zz_pE& a, const vec_zz_pE& b); // assignment operator notation: vec_zz_pE& operator+=(vec_zz_pE& x, const vec_zz_pE& a); vec_zz_pE& operator-=(vec_zz_pE& x, const vec_zz_pE& a); vec_zz_pE& operator*=(vec_zz_pE& x, const zz_pE& a); vec_zz_pE& operator*=(vec_zz_pE& x, const zz_p& a); vec_zz_pE& operator*=(vec_zz_pE& x, long a); ntl-6.2.1/doc/vector.cpp.html000644 000765 000024 00000045632 12377144460 016356 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/vector.cpp.html


/**************************************************************************\

MODULE: vector

SUMMARY:

Template class for dynamic-sized vectors.

The declaration

   Vec<T> v;

creates a zero-length vector.  To grow this vector to length n,
execute

   v.SetLength(n)

This causes space to be allocated for (at least) n elements, and also
causes the delault constructor for T to be called to initialize these
elements.

The current length of a vector is available as v.length().

The i-th vector element (counting from 0) is accessed as v[i].  If the
macro NTL_RANGE_CHECK is defined, code is emitted to test if 0 <= i <
v.length().  This check is not performed by default.

For old-time FORTRAN programmers, the i-th vector element (counting
from 1) is accessed as v(i).

Let n = v.length().  Calling v.SetLength(m) with m <= n sets the
current length of v to m (but does not call any destructors or free
any space).  Calling v.SetLength(m) with m > n will allocate space and
initialize as necessary, but will leave the values of the already
allocated elements unchanged (although their addresses may change).
Initializations are performed using T's default constructor.

v.MaxLength() is the largest value of n for which v.SetLength(n) was invoked,
and is equal to the number of entries that have been initialized.
v.SetMaxLength(n) will allocate space for and initialize up to n elements,
without changing v.length().

When v's destructor is called, all constructed elements will be
destructed, and all space will be relinquished.

Space is managed using malloc, realloc, and free.  When a vector is
grown, a bit more space may be allocated than was requested for
efficiency reasons.

Note that when a vector is grown, the space is reallocated using
realloc, and thus the addresses of vector elements may change,
possibly creating dangling references to vector elements.  One has to
be especially careful of this when using vectors passed as reference
parameters that may alias one another.

Because realloc is used to grow a vector, the objects stored
in a vector should be "relocatable"---that is, they shouldn't care
what their actual address is, which may change over time.
Most reasonable objects satisfy this constraint.

v.allocated() is the number of elements which have been allocated,
which may be more than the number elements initialized.
Note that if n <= v.allocated(), then v.SetLength(n) is guaranteed
not to cause any memory allocation, or movement of objects.

\**************************************************************************/

template<class T>
class Vec {
public:

   Vec();  // initially length 0

   Vec(const Vec<T>& a);
   // copy constructor;  uses the assignment operator of T
   // for copying into locations that have already been initialized,
   // and uses the copy constructor for T for initializing new locations.

   Vec& operator=(const Vec<T>& a);
   // assignment;  uses the assignment operator of T
   // for copying into locations that have already been initialized,
   // and uses the copy constructor for T for initializing new locations.

   ~Vec();
   // destructor: calls T's destructor for all initialized
   // elements in the vector, and then frees the vector itself

   void SetLength(long n);
   // set current length to n, growing vector if necessary
   // new objects are initialized using the default contructor for T

   void SetLength(long n, const T& a);
   // set current length to n, growing vector if necessary
   // new objects are initialized using the copy contructor for T

   long length() const;
   // current length

   T& operator[](long i);
   const T& operator[](long i) const;
   // indexing operation, starting from 0.
   // The first version is applied to non-const Vec<T>,
   // and returns a non-const reference to a T, while the second version
   // is applied to a const Vec<T> and returns a const reference to a T.

   T& operator()(long i);
   const T& operator()(long i) const;
   // indexing operation, starting from 1
   // The first version is applied to non-const Vec<T>,
   // and returns a non-const reference to a T, while the second version
   // is applied to a const Vec<T> and returns a const reference to a T.

   T* elts();
   const T* elts() const;
   // returns address of first vector element (or 0 if no space has
   // been allocated for this vector).  If a vector potentially has
   // length 0, it is safer to write v.elts() instead of &v[0].
   // The first version is applied to non-const Vec<T>,
   // and returns a non-const pointer to a T, while the second version
   // is applied to a const Vec<T> and returns a const reference to a T.


   void swap(Vec<T>& y);
   // swap with y (fast: just swaps pointers)

   void append(const T& a);
   // append a to end of vector; uses the assignment operator of T
   // for copying into locations that have already been initialized,
   // and uses the copy constructor for T for initializing new locations.

   void append(const Vec<T>& w);
   // append w to end of vector; uses the assignment operator of T
   // for copying into locations that have already been initialized,
   // and uses the copy constructor for T for initializing new locations.


// Alternative access interface 

   const T& get(long i) const;
   // v.get(i) returns v[i]

   void put(long i, const T& a);
   // v.put(i, a) equivalent to v[i] = q



// Some STL compatibility

   typedef T value_type;
   typedef value_type& reference;
   typedef const value_type& const_reference;
   typedef value_type *iterator;
   typedef const value_type *const_iterator;

   T* data();
   const T* data() const;
   // v.data() same as v.elts()

   T* begin();
   const T* begin() const;
   // v.begin() same as v.elts()

   T* end();
   const T* end() const;
   // pointer to last element (or NULL)

   T& at(long i);
   const T& at(long i) const;
   // indexing with range checking


// the remaining member functions are a bit esoteric (skip on first
// reading)

   Vec(INIT_SIZE_TYPE, long n);
   // Vec(INIT_SIZE, n) initializes with an intial length of n.

   void kill();
   // release space and set to length 0

   void SetMaxLength(long n);
   // allocates space and initializes up to n elements. Does not change
   // current length

   void FixLength(long n);
   // sets length to n and prohibits all future length changes.
   // FixLength may only be invoked immediately after the default
   // construction or kill.

   // The kill operation is also subsequently prohibited, and swap is
   // allowed on fixed length vectors of the same length.

   // FixLength is provided mainly to implement Mat<T>, to enforce
   // the restriction that all rows have the same length.

   long fixed() const;
   // test if length has been fixed by FixLength().

   long MaxLength() const;
   // maximum length, i.e., number of allocated and initialized elements

   long allocated() const;
   // the number of objects for which space has been allocated, but not
   // necessarily initialized;  this may be larger than MaxLength().

   T& RawGet(long i);
   const T& RawGet(long i) const;
   // indexing with no range checking

   long position(const T& a) const;
   // returns position of a in the vector, or -1 if it is not there.
   // The search is conducted from position 0 to allocated()-1 the vector, 
   // and an error is raised if the object is found at position MaxLength()
   // or higher (in which case a references an uninitialized object).
   // Note that if NTL_CLEAN_PTR flag is set, this routine takes
   // linear time, and otherwise, it takes constant time.

   long position1(const T& a) const;
   // returns position of a in the vector, or -1 if it is not there.
   // The search is conducted from position 0 to length()-1 of the vector.
   // Note that if NTL_CLEAN_PTR flag is set, this routine takes
   // linear time, and otherwise, it takes constant time.

};


/**************************************************************************\

                       Some utility routines

\**************************************************************************/


template<class T>
void swap(Vec<T>& x, Vec<T>& y);
// swaps x & y; same as x.swap(y)

template<class T>
void append(Vec<T>& v, const T& a);
// appends a to the end of v; same as v.append(a)

template<class T>
void append(Vec<T>& v, const Vec<T>& w);
// appends w to the end of v; same as v.append(w)




/**************************************************************************\

                             Input/Output


The I/O format for a vector v with n elements is:

   [v[0] v[1] ... v[n-1]]

Uses corresponding I/O operators for T

\**************************************************************************/

template<class T>
istream& operator>>(istream&, Vec<T>&);

template<class T>
ostream& operator<<(ostream&, const Vec<T>&);



/**************************************************************************\

                              Equality Testing

\**************************************************************************/


template<class T>
long operator==(const Vec<T>& a, const Vec<T>& b);

template<class T>
long operator!=(const Vec<T>& a, const Vec<T>& b);


/**************************************************************************\

                  Customized Constructors and Destructors
 
Esoteric: skip on first reading...also these interfaces are subject to change

When new elements in a vector need to be constructed, one of the
following routines is called:

   void BlockConstruct(T* p, long n); 
   // invokes T() to initialize p[i] for i = 0..n-1

   void BlockConstructFromVec(T* p, long n, const T* q);
   // invokes T(q[i]) to initialize p[i] for i = 0..n-1;
   // q points to elements from a Vec<T>

   void BlockConstructFromObj(T* p, long n, const T& q);
   // invokes T(q) to initialize p[i] for i = 0..n-1


When a vector is destroyed, the following routine is called:

   void BlockDestroy(T* p, long n);
   // invokes ~T() on p[i] for i = 0..n-1

The default behavior of these routines may be modified by 
overloading these functions with a custom implementation.
 
In NTL, these routines are overridden for the ZZ_p and GF2E classes,
so that many vector entries will be packed into contiguous storage
locations.  This reduces the number of invocations of malloc, and
increases locality of reference.


\**************************************************************************/

ntl-6.2.1/doc/vector.txt000644 000765 000024 00000024417 12377144460 015446 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: vector SUMMARY: Template class for dynamic-sized vectors. The declaration Vec v; creates a zero-length vector. To grow this vector to length n, execute v.SetLength(n) This causes space to be allocated for (at least) n elements, and also causes the delault constructor for T to be called to initialize these elements. The current length of a vector is available as v.length(). The i-th vector element (counting from 0) is accessed as v[i]. If the macro NTL_RANGE_CHECK is defined, code is emitted to test if 0 <= i < v.length(). This check is not performed by default. For old-time FORTRAN programmers, the i-th vector element (counting from 1) is accessed as v(i). Let n = v.length(). Calling v.SetLength(m) with m <= n sets the current length of v to m (but does not call any destructors or free any space). Calling v.SetLength(m) with m > n will allocate space and initialize as necessary, but will leave the values of the already allocated elements unchanged (although their addresses may change). Initializations are performed using T's default constructor. v.MaxLength() is the largest value of n for which v.SetLength(n) was invoked, and is equal to the number of entries that have been initialized. v.SetMaxLength(n) will allocate space for and initialize up to n elements, without changing v.length(). When v's destructor is called, all constructed elements will be destructed, and all space will be relinquished. Space is managed using malloc, realloc, and free. When a vector is grown, a bit more space may be allocated than was requested for efficiency reasons. Note that when a vector is grown, the space is reallocated using realloc, and thus the addresses of vector elements may change, possibly creating dangling references to vector elements. One has to be especially careful of this when using vectors passed as reference parameters that may alias one another. Because realloc is used to grow a vector, the objects stored in a vector should be "relocatable"---that is, they shouldn't care what their actual address is, which may change over time. Most reasonable objects satisfy this constraint. v.allocated() is the number of elements which have been allocated, which may be more than the number elements initialized. Note that if n <= v.allocated(), then v.SetLength(n) is guaranteed not to cause any memory allocation, or movement of objects. \**************************************************************************/ template class Vec { public: Vec(); // initially length 0 Vec(const Vec& a); // copy constructor; uses the assignment operator of T // for copying into locations that have already been initialized, // and uses the copy constructor for T for initializing new locations. Vec& operator=(const Vec& a); // assignment; uses the assignment operator of T // for copying into locations that have already been initialized, // and uses the copy constructor for T for initializing new locations. ~Vec(); // destructor: calls T's destructor for all initialized // elements in the vector, and then frees the vector itself void SetLength(long n); // set current length to n, growing vector if necessary // new objects are initialized using the default contructor for T void SetLength(long n, const T& a); // set current length to n, growing vector if necessary // new objects are initialized using the copy contructor for T long length() const; // current length T& operator[](long i); const T& operator[](long i) const; // indexing operation, starting from 0. // The first version is applied to non-const Vec, // and returns a non-const reference to a T, while the second version // is applied to a const Vec and returns a const reference to a T. T& operator()(long i); const T& operator()(long i) const; // indexing operation, starting from 1 // The first version is applied to non-const Vec, // and returns a non-const reference to a T, while the second version // is applied to a const Vec and returns a const reference to a T. T* elts(); const T* elts() const; // returns address of first vector element (or 0 if no space has // been allocated for this vector). If a vector potentially has // length 0, it is safer to write v.elts() instead of &v[0]. // The first version is applied to non-const Vec, // and returns a non-const pointer to a T, while the second version // is applied to a const Vec and returns a const reference to a T. void swap(Vec& y); // swap with y (fast: just swaps pointers) void append(const T& a); // append a to end of vector; uses the assignment operator of T // for copying into locations that have already been initialized, // and uses the copy constructor for T for initializing new locations. void append(const Vec& w); // append w to end of vector; uses the assignment operator of T // for copying into locations that have already been initialized, // and uses the copy constructor for T for initializing new locations. // Alternative access interface const T& get(long i) const; // v.get(i) returns v[i] void put(long i, const T& a); // v.put(i, a) equivalent to v[i] = q // Some STL compatibility typedef T value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type *iterator; typedef const value_type *const_iterator; T* data(); const T* data() const; // v.data() same as v.elts() T* begin(); const T* begin() const; // v.begin() same as v.elts() T* end(); const T* end() const; // pointer to last element (or NULL) T& at(long i); const T& at(long i) const; // indexing with range checking // the remaining member functions are a bit esoteric (skip on first // reading) Vec(INIT_SIZE_TYPE, long n); // Vec(INIT_SIZE, n) initializes with an intial length of n. void kill(); // release space and set to length 0 void SetMaxLength(long n); // allocates space and initializes up to n elements. Does not change // current length void FixLength(long n); // sets length to n and prohibits all future length changes. // FixLength may only be invoked immediately after the default // construction or kill. // The kill operation is also subsequently prohibited, and swap is // allowed on fixed length vectors of the same length. // FixLength is provided mainly to implement Mat, to enforce // the restriction that all rows have the same length. long fixed() const; // test if length has been fixed by FixLength(). long MaxLength() const; // maximum length, i.e., number of allocated and initialized elements long allocated() const; // the number of objects for which space has been allocated, but not // necessarily initialized; this may be larger than MaxLength(). T& RawGet(long i); const T& RawGet(long i) const; // indexing with no range checking long position(const T& a) const; // returns position of a in the vector, or -1 if it is not there. // The search is conducted from position 0 to allocated()-1 the vector, // and an error is raised if the object is found at position MaxLength() // or higher (in which case a references an uninitialized object). // Note that if NTL_CLEAN_PTR flag is set, this routine takes // linear time, and otherwise, it takes constant time. long position1(const T& a) const; // returns position of a in the vector, or -1 if it is not there. // The search is conducted from position 0 to length()-1 of the vector. // Note that if NTL_CLEAN_PTR flag is set, this routine takes // linear time, and otherwise, it takes constant time. }; /**************************************************************************\ Some utility routines \**************************************************************************/ template void swap(Vec& x, Vec& y); // swaps x & y; same as x.swap(y) template void append(Vec& v, const T& a); // appends a to the end of v; same as v.append(a) template void append(Vec& v, const Vec& w); // appends w to the end of v; same as v.append(w) /**************************************************************************\ Input/Output The I/O format for a vector v with n elements is: [v[0] v[1] ... v[n-1]] Uses corresponding I/O operators for T \**************************************************************************/ template istream& operator>>(istream&, Vec&); template ostream& operator<<(ostream&, const Vec&); /**************************************************************************\ Equality Testing \**************************************************************************/ template long operator==(const Vec& a, const Vec& b); template long operator!=(const Vec& a, const Vec& b); /**************************************************************************\ Customized Constructors and Destructors Esoteric: skip on first reading...also these interfaces are subject to change When new elements in a vector need to be constructed, one of the following routines is called: void BlockConstruct(T* p, long n); // invokes T() to initialize p[i] for i = 0..n-1 void BlockConstructFromVec(T* p, long n, const T* q); // invokes T(q[i]) to initialize p[i] for i = 0..n-1; // q points to elements from a Vec void BlockConstructFromObj(T* p, long n, const T& q); // invokes T(q) to initialize p[i] for i = 0..n-1 When a vector is destroyed, the following routine is called: void BlockDestroy(T* p, long n); // invokes ~T() on p[i] for i = 0..n-1 The default behavior of these routines may be modified by overloading these functions with a custom implementation. In NTL, these routines are overridden for the ZZ_p and GF2E classes, so that many vector entries will be packed into contiguous storage locations. This reduces the number of invocations of malloc, and increases locality of reference. \**************************************************************************/ ntl-6.2.1/doc/version.cpp.html000644 000765 000024 00000004053 12377144460 016531 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/version.cpp.html

/**************************************************************************\

MODULE: version

SUMMARY:

Macros defining the NTL version number.

\**************************************************************************/



#define NTL_VERSION        ... // version number as a string, e.g., "5.2"

#define NTL_MAJOR_VERSION  ... // e.g., 5 in the above example
#define NTL_MINOR_VERSION  ... // e.g., 2        "
#define NTL_REVISION       ... // e.g., 0        "

// The choice as to whether a new version warrants a higher
// Major version number or Minor version number is fairly subjective,
// with no particular rule.

// Revision numbers are only used for small bug fixes that generally
// do not affect the programming interface at all.


ntl-6.2.1/doc/version.txt000644 000765 000024 00000001355 12377144460 015625 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: version SUMMARY: Macros defining the NTL version number. \**************************************************************************/ #define NTL_VERSION ... // version number as a string, e.g., "5.2" #define NTL_MAJOR_VERSION ... // e.g., 5 in the above example #define NTL_MINOR_VERSION ... // e.g., 2 " #define NTL_REVISION ... // e.g., 0 " // The choice as to whether a new version warrants a higher // Major version number or Minor version number is fairly subjective, // with no particular rule. // Revision numbers are only used for small bug fixes that generally // do not affect the programming interface at all. ntl-6.2.1/doc/xdouble.cpp.html000644 000765 000024 00000032320 12377144460 016504 0ustar00shoupstaff000000 000000 /Volumes/Unix/unix-files.noindex/ntl-new/ntl-6.1.0/doc/xdouble.cpp.html


/**************************************************************************\

MODULE: xdouble 

SUMMARY:

The class xdouble is used to represent floating point numbers with the
same precision as a 'double', but with extended exponent range
(offering a few more bits than that of a 'long' for the exponent).

The programming interface for xdoubles is almost identical to that of
ordinary doubles.


\**************************************************************************/

#include <NTL/ZZ.h>


class xdouble {

public:

xdouble(); // = 0

xdouble(const xdouble& a);  // copy constructor

explicit xdouble(double a);  // promotion constructor

xdouble& operator=(const xdouble& a);  // assignment operator
xdouble& operator=(double a);

~xdouble();


double mantissa() const;  // read-only access to mantissa
long exponent() const;  // read-only access to exponenent



static void SetOutputPrecision(long p);
// This sets the number of decimal digits to be output.  Default is
// 10.

static long OutputPrecision();
// returns current output precision.

};



/**************************************************************************\

                             Arithmetic Operations

The following are the standard arithmetic operators, whose meaning should 
be clear.

\**************************************************************************/


xdouble operator+(const xdouble& a, const xdouble& b);
xdouble operator-(const xdouble& a, const xdouble& b);
xdouble operator*(const xdouble& a, const xdouble& b);
xdouble operator/(const xdouble& a, const xdouble& b);

// PROMOTIONS: +, -, *, / promote double to xdouble on (a, b).

xdouble operator-(const xdouble& a);

xdouble& operator+=(xdouble& a, const xdouble& b);
xdouble& operator+=(xdouble& a, double b);

xdouble& operator-=(xdouble& a, const xdouble& b);
xdouble& operator-=(xdouble& a, double b);

xdouble& operator*=(xdouble& a, const xdouble& b);
xdouble& operator*=(xdouble& a, double b);

xdouble& operator/=(xdouble& a, const xdouble& b);
xdouble& operator/=(xdouble& a, xdouble b);

xdouble& operator++(xdouble& a); // prefix
void operator++(xdouble& a, int); // postfix

xdouble& operator--(xdouble& a); // prefix
void operator--(xdouble& a, int); // postfix



/**************************************************************************\

                                  Comparison

\**************************************************************************/

long sign(const xdouble& a);
// returns sign (+1, -1, 0) of a

long compare(const xdouble& a, const xdouble& b);
// returns sign of a - b

long operator==(const xdouble& a, const xdouble& b);
long operator!=(const xdouble& a, const xdouble& b);
long operator<=(const xdouble& a, const xdouble& b);
long operator>=(const xdouble& a, const xdouble& b);
long operator <(const xdouble& a, const xdouble& b);
long operator >(const xdouble& a, const xdouble& b);

// PROMOTIONS: compare and operators ==, ..., > promote double to xdouble
// on (a, b).



/**************************************************************************\

                               Input/Output
Input Syntax:

<number>: [ "-" ] <unsigned-number>
<unsigned-number>: <dotted-number> [ <e-part> ] | <e-part>
<dotted-number>: <digits> | <digits> "." <digits> | "." <digits> | <digits> "."
<digits>: <digit> <digits> | <digit>
<digit>: "0" | ... | "9"
<e-part>: ( "E" | "e" ) [ "+" | "-" ] <digits>

Examples of valid input:

17 1.5 0.5 .5  5.  -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10

Note that the number of decimal digits of precision that are used
for output can be set to any number p >= 1 by calling
the routine xdouble::SetOutputPrecision(p).  
The default value of p is 10.
The current value of p is returned by a call to xdouble::OutputPrecision().

\**************************************************************************/



ostream& operator<<(ostream& s, const xdouble& a);

istream& operator>>(istream& s, xdouble& x);


/**************************************************************************\

                                  Miscellaneous

\**************************************************************************/



xdouble trunc(const xdouble& a);  // returns integer obtained by truncating
xdouble floor(const xdouble& a);  // returns greatest integer <= a
xdouble ceil(const xdouble& a);   // returns smallest integer >= a
xdouble fabs(const xdouble& a);   // returns |a|
xdouble sqrt(const xdouble& a);   // returns a^{1/2}; error is raised if a < 0

double log(const xdouble& a);  // returns log(a) (note return val is double!)
xdouble xexp(double a);        // returns exp(a) (note argument is double!)



void power(xdouble& z, const xdouble& a, const ZZ& e);
xdouble power(const xdouble& a, const ZZ& e);

void power(xdouble& z, const xdouble& a, long e);
xdouble power(const xdouble& a, long e);
// z = a^e, e may be negative

void power2(xdouble& z, long e);
xdouble power2_xdouble(long e);
// z = 2^e, e may be negative

void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c);
xdouble MulAdd(const xdouble& a, const xdouble& b, const xdouble& c);
// z = a + b*c, but faster

void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c);
xdouble MulSub(const xdouble& a, const xdouble& b, const xdouble& c);
// z = a - b*c, but faster


/**************************************************************************\

Implementation details:

An xdouble is represented as a mantissa/exponent pair (x, e), where x
is a double and e is a long.  The real number represented by (x, e) is
x * NTL_XD_BOUND^e, where

  NTL_XD_BOUND = NTL_XD_HBOUND^2, and
  NTL_XD_HBOUND = 2^{(max(NTL_DOUBLE_PRECISION,NTL_BITS_PER_LONG)+4)}.

Also, the mantissa x satisfies 1/NTL_XD_HBOUND <= |x| <= NTL_XD_HBOUND, except
that the number 0 is always represented as (0, 0).  
Both NTL_XD_BOUND and NTL_XD_HBOUND are macros defined in <NTL/xdouble.h>.

SIZE INVARIANT: |e| < 2^(NTL_BITS_PER_LONG-4).

\**************************************************************************/

ntl-6.2.1/doc/xdouble.txt000644 000765 000024 00000013637 12377144460 015610 0ustar00shoupstaff000000 000000 /**************************************************************************\ MODULE: xdouble SUMMARY: The class xdouble is used to represent floating point numbers with the same precision as a 'double', but with extended exponent range (offering a few more bits than that of a 'long' for the exponent). The programming interface for xdoubles is almost identical to that of ordinary doubles. \**************************************************************************/ #include class xdouble { public: xdouble(); // = 0 xdouble(const xdouble& a); // copy constructor explicit xdouble(double a); // promotion constructor xdouble& operator=(const xdouble& a); // assignment operator xdouble& operator=(double a); ~xdouble(); double mantissa() const; // read-only access to mantissa long exponent() const; // read-only access to exponenent static void SetOutputPrecision(long p); // This sets the number of decimal digits to be output. Default is // 10. static long OutputPrecision(); // returns current output precision. }; /**************************************************************************\ Arithmetic Operations The following are the standard arithmetic operators, whose meaning should be clear. \**************************************************************************/ xdouble operator+(const xdouble& a, const xdouble& b); xdouble operator-(const xdouble& a, const xdouble& b); xdouble operator*(const xdouble& a, const xdouble& b); xdouble operator/(const xdouble& a, const xdouble& b); // PROMOTIONS: +, -, *, / promote double to xdouble on (a, b). xdouble operator-(const xdouble& a); xdouble& operator+=(xdouble& a, const xdouble& b); xdouble& operator+=(xdouble& a, double b); xdouble& operator-=(xdouble& a, const xdouble& b); xdouble& operator-=(xdouble& a, double b); xdouble& operator*=(xdouble& a, const xdouble& b); xdouble& operator*=(xdouble& a, double b); xdouble& operator/=(xdouble& a, const xdouble& b); xdouble& operator/=(xdouble& a, xdouble b); xdouble& operator++(xdouble& a); // prefix void operator++(xdouble& a, int); // postfix xdouble& operator--(xdouble& a); // prefix void operator--(xdouble& a, int); // postfix /**************************************************************************\ Comparison \**************************************************************************/ long sign(const xdouble& a); // returns sign (+1, -1, 0) of a long compare(const xdouble& a, const xdouble& b); // returns sign of a - b long operator==(const xdouble& a, const xdouble& b); long operator!=(const xdouble& a, const xdouble& b); long operator<=(const xdouble& a, const xdouble& b); long operator>=(const xdouble& a, const xdouble& b); long operator <(const xdouble& a, const xdouble& b); long operator >(const xdouble& a, const xdouble& b); // PROMOTIONS: compare and operators ==, ..., > promote double to xdouble // on (a, b). /**************************************************************************\ Input/Output Input Syntax: : [ "-" ] : [ ] | : | "." | "." | "." : | : "0" | ... | "9" : ( "E" | "e" ) [ "+" | "-" ] Examples of valid input: 17 1.5 0.5 .5 5. -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10 Note that the number of decimal digits of precision that are used for output can be set to any number p >= 1 by calling the routine xdouble::SetOutputPrecision(p). The default value of p is 10. The current value of p is returned by a call to xdouble::OutputPrecision(). \**************************************************************************/ ostream& operator<<(ostream& s, const xdouble& a); istream& operator>>(istream& s, xdouble& x); /**************************************************************************\ Miscellaneous \**************************************************************************/ xdouble trunc(const xdouble& a); // returns integer obtained by truncating xdouble floor(const xdouble& a); // returns greatest integer <= a xdouble ceil(const xdouble& a); // returns smallest integer >= a xdouble fabs(const xdouble& a); // returns |a| xdouble sqrt(const xdouble& a); // returns a^{1/2}; error is raised if a < 0 double log(const xdouble& a); // returns log(a) (note return val is double!) xdouble xexp(double a); // returns exp(a) (note argument is double!) void power(xdouble& z, const xdouble& a, const ZZ& e); xdouble power(const xdouble& a, const ZZ& e); void power(xdouble& z, const xdouble& a, long e); xdouble power(const xdouble& a, long e); // z = a^e, e may be negative void power2(xdouble& z, long e); xdouble power2_xdouble(long e); // z = 2^e, e may be negative void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c); xdouble MulAdd(const xdouble& a, const xdouble& b, const xdouble& c); // z = a + b*c, but faster void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c); xdouble MulSub(const xdouble& a, const xdouble& b, const xdouble& c); // z = a - b*c, but faster /**************************************************************************\ Implementation details: An xdouble is represented as a mantissa/exponent pair (x, e), where x is a double and e is a long. The real number represented by (x, e) is x * NTL_XD_BOUND^e, where NTL_XD_BOUND = NTL_XD_HBOUND^2, and NTL_XD_HBOUND = 2^{(max(NTL_DOUBLE_PRECISION,NTL_BITS_PER_LONG)+4)}. Also, the mantissa x satisfies 1/NTL_XD_HBOUND <= |x| <= NTL_XD_HBOUND, except that the number 0 is always represented as (0, 0). Both NTL_XD_BOUND and NTL_XD_HBOUND are macros defined in . SIZE INVARIANT: |e| < 2^(NTL_BITS_PER_LONG-4). \**************************************************************************/