ezgcd.red 204 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765
  1. module fac!-intro; % Support for factorizer.
  2. % Authors: A. C. Norman and P. M. A. Moore, 1981.
  3. fluid '(!*timings !*trallfac !*trfac factor!-level factor!-trace!-list);
  4. global '(!*ifactor posn!* spare!*);
  5. switch ifactor,overview,timings,trallfac,trfac;
  6. factor!-level:=0; % start with a numeric value;
  7. comment This factorizer should be used with a system dependent file
  8. containing a setting of the variable LARGEST!-SMALL!-MODULUS. If at all
  9. possible the integer arithmetic operations used here should be mapped
  10. onto corresponding ones available in the underlying Lisp implementation,
  11. and the support for modular arithmetic (perhaps based on these integer
  12. arithmetic operations) should be reviewed. This file provides
  13. placeholder definitions of functions that are used on some
  14. implementations to support block compilation, car/cdr access checks and
  15. the like. The front-end files on the systems that can use these
  16. features will disable the definitions given here by use of a 'LOSE flag;
  17. deflist('((minus!-one -1)),'newnam); %so that it EVALs properly;
  18. symbolic smacro procedure carcheck u; nil;
  19. symbolic procedure errorf u;
  20. rederr list("Factorizer error:",u);
  21. symbolic smacro procedure factor!-trace action;
  22. begin scalar stream;
  23. if !*trallfac or (!*trfac and factor!-level = 1) then
  24. stream := nil . nil
  25. else
  26. stream := assoc(factor!-level,factor!-trace!-list);
  27. if stream then <<
  28. stream:=wrs cdr stream;
  29. action;
  30. wrs stream >>
  31. end;
  32. symbolic smacro procedure irecip u; 1/u;
  33. symbolic smacro procedure isdomain u; domainp u;
  34. symbolic smacro procedure readgctime; gctime();
  35. symbolic smacro procedure readtime; time()-gctime();
  36. symbolic smacro procedure ttab n; spaces(n-posn());
  37. % ***** The remainder of this module used to be in FLUIDS.
  38. % Macro definitions for functions that create and access reduce-type
  39. % datastructures.
  40. smacro procedure tvar a; caar a;
  41. smacro procedure polyzerop u; null u;
  42. smacro procedure didntgo q; null q;
  43. smacro procedure depends!-on!-var(a,v);
  44. (lambda !#!#a; (not domainp !#!#a) and (mvar !#!#a=v)) a;
  45. smacro procedure l!-numeric!-c(a,vlist); lnc a;
  46. % Macro definitions for use in berlekamps algorithm.
  47. % SMACROs used in linear equation package.
  48. smacro procedure getm2(a,i,j);
  49. % Store by rows, to ease pivoting process.
  50. getv(getv(a,i),j);
  51. smacro procedure putm2(a,i,j,v);
  52. putv(getv(a,i),j,v);
  53. %%%smacro procedure !*d2n a;
  54. %%%% converts domain elt into number.
  55. %%% (lambda !#a!#;
  56. %%% if null !#a!# then 0 else !#a!#) a;
  57. symbolic procedure !*d2n a; if null a then 0 else a;
  58. smacro procedure !*num2f n;
  59. % converts number to s.f.
  60. (lambda !#n!#; if !#n!#=0 then nil else !#n!#) n;
  61. smacro procedure !*mod2f u; u;
  62. smacro procedure !*f2mod u; u;
  63. smacro procedure comes!-before(p1,p2);
  64. % Similar to the REDUCE function ORDPP, but does not cater for
  65. % non-commutative terms and assumes that exponents are small integers.
  66. (car p1=car p2 and igreaterp(cdr p1,cdr p2)) or
  67. (not car p1=car p2 and ordop(car p1,car p2));
  68. %%%smacro procedure adjoin!-term (p,c,r);
  69. %%% (lambda !#c!#; % Lambda binding prevents repeated evaluation of C.
  70. %%% if null !#c!# then r else (p .* !#c!#) .+ r) c;
  71. symbolic procedure adjoin!-term (p,c,r);
  72. if null c then r else (p .* c) .+ r;
  73. % A load of access smacros for image sets follow:
  74. smacro procedure get!-image!-set s; car s;
  75. smacro procedure get!-chosen!-prime s; cadr s;
  76. smacro procedure get!-image!-lc s; caddr s;
  77. smacro procedure get!-image!-mod!-p s; cadr cddr s;
  78. smacro procedure get!-image!-content s; cadr cdr cddr s;
  79. smacro procedure get!-image!-poly s; cadr cddr cddr s;
  80. smacro procedure get!-f!-numvec s; cadr cddr cdddr s;
  81. smacro procedure put!-image!-poly!-and!-content(s,imcont,impol);
  82. list(get!-image!-set s,
  83. get!-chosen!-prime s,
  84. get!-image!-lc s,
  85. get!-image!-mod!-p s,
  86. imcont,
  87. impol,
  88. get!-f!-numvec s);
  89. % !*timings:=nil; % Default not to displaying timings.
  90. % !*overshoot:=nil; % Default not to show overshoot occurring.
  91. % reconstructing!-gcd:=nil; % This is primarily a factorizer!
  92. symbolic procedure ttab!* n;
  93. <<if n>(linelength nil - spare!*) then n:=0;
  94. if posn!* > n then terpri!*(nil);
  95. while not(posn!*=n) do prin2!* '! >>;
  96. smacro procedure printstr l; << prin2!* l; terpri!*(nil) >>;
  97. smacro procedure printvar v; printstr v;
  98. smacro procedure prinvar v; prin2!* v;
  99. symbolic procedure printvec(str1,n,str2,v);
  100. << for i:=1:n do <<
  101. prin2!* str1;
  102. prin2!* i;
  103. prin2!* str2;
  104. printsf getv(v,i) >>;
  105. terpri!*(nil) >>;
  106. smacro procedure display!-time(str,mt);
  107. % Displays the string str followed by time mt (millisecs).
  108. << prin2 str; prin2 mt; printc " millisecs." >>;
  109. % trace control package.
  110. smacro procedure trace!-time action; if !*timings then action;
  111. smacro procedure new!-level(n,c); (lambda factor!-level; c) n;
  112. symbolic procedure set!-trace!-factor(n,file);
  113. factor!-trace!-list:=(n . (if file=nil then nil
  114. else open(mkfil file,'output))) .
  115. factor!-trace!-list;
  116. symbolic procedure clear!-trace!-factor n;
  117. begin
  118. scalar w;
  119. w := assoc(n,factor!-trace!-list);
  120. if w then <<
  121. if cdr w then close cdr w;
  122. factor!-trace!-list:=delasc(n,factor!-trace!-list) >>;
  123. return nil
  124. end;
  125. symbolic procedure close!-trace!-files();
  126. << while factor!-trace!-list
  127. do clear!-trace!-factor(caar factor!-trace!-list);
  128. nil >>;
  129. endmodule;
  130. module alphas;
  131. % Authors: A. C. Norman and P. M. A. Moore, 1981;
  132. fluid '(alphalist current!-modulus hensel!-growth!-size
  133. number!-of!-factors);
  134. %********************************************************************;
  135. %
  136. % this section contains access and update functions for the alphas;
  137. symbolic procedure get!-alpha poly;
  138. % gets the poly and its associated alpha from the current alphalist
  139. % if poly is not on the alphalist then we force an error;
  140. begin scalar w;
  141. w:=assoc!-alpha(poly,alphalist);
  142. if null w then errorf list("Alpha not found for ",poly," in ",
  143. alphalist);
  144. return w
  145. end;
  146. symbolic procedure divide!-all!-alphas n;
  147. % multiply the factors by n mod p and alter the alphas accordingly;
  148. begin scalar om,m;
  149. om:=set!-modulus hensel!-growth!-size;
  150. m:=modular!-expt(
  151. modular!-reciprocal modular!-number n,
  152. number!-of!-factors #- 1);
  153. alphalist:=for each a in alphalist collect
  154. (times!-mod!-p(n,car a) . times!-mod!-p(m,cdr a));
  155. set!-modulus om
  156. end;
  157. symbolic procedure multiply!-alphas(n,oldpoly,newpoly);
  158. % multiply all the alphas except the one associated with oldpoly
  159. % by n mod p. also replace oldpoly by newpoly in the alphalist;
  160. begin scalar om,faca;
  161. om:=set!-modulus hensel!-growth!-size;
  162. n:=modular!-number n;
  163. oldpoly:=reduce!-mod!-p oldpoly;
  164. faca:=get!-alpha oldpoly;
  165. alphalist:=delete(faca,alphalist);
  166. alphalist:=for each a in alphalist collect
  167. car a . times!-mod!-p(cdr a,n);
  168. alphalist:=(reduce!-mod!-p newpoly . cdr faca) . alphalist;
  169. set!-modulus om
  170. end;
  171. symbolic procedure multiply!-alphas!-recip(n,oldpoly,newpoly);
  172. % multiply all the alphas except the one associated with oldpoly
  173. % by the reciprocal mod p of n. also replace oldpoly by newpoly;
  174. begin scalar om,w;
  175. om:=set!-modulus hensel!-growth!-size;
  176. n:=modular!-reciprocal modular!-number n;
  177. w:=multiply!-alphas(n,oldpoly,newpoly);
  178. set!-modulus om;
  179. return w
  180. end;
  181. endmodule;
  182. module coeffts;
  183. % Authors: A. C. Norman and P. M. A. Moore, 1981;
  184. fluid '(!*timings
  185. !*trfac
  186. alphalist
  187. best!-known!-factor!-list
  188. best!-known!-factors
  189. coefft!-vectors
  190. deg!-of!-unknown
  191. difference!-for!-unknown
  192. divisor!-for!-unknown
  193. factor!-level
  194. factor!-trace!-list
  195. full!-gcd
  196. hensel!-growth!-size
  197. image!-factors
  198. m!-image!-variable
  199. multivariate!-factors
  200. multivariate!-input!-poly
  201. non!-monic
  202. number!-of!-factors
  203. polyzero
  204. reconstructing!-gcd
  205. true!-leading!-coeffts
  206. unknown
  207. unknowns!-list);
  208. %**********************************************************************;
  209. % code for trying to determine more multivariate coefficients
  210. % by inspection before using multivariate hensel construction. ;
  211. symbolic procedure determine!-more!-coeffts();
  212. % ...;
  213. begin scalar unknowns!-list,uv,r,w,best!-known!-factor!-list;
  214. best!-known!-factors:=mkvect number!-of!-factors;
  215. uv:=mkvect number!-of!-factors;
  216. for i:=number!-of!-factors step -1 until 1 do
  217. putv(uv,i,convert!-factor!-to!-termvector(
  218. getv(image!-factors,i),getv(true!-leading!-coeffts,i)));
  219. r:=red multivariate!-input!-poly;
  220. % we know all about the leading coeffts;
  221. if not depends!-on!-var(r,m!-image!-variable)
  222. or null(w:=try!-first!-coefft(
  223. ldeg r,lc r,unknowns!-list,uv)) then <<
  224. for i:=1:number!-of!-factors do
  225. putv(best!-known!-factors,i,force!-lc(
  226. getv(image!-factors,i),getv(true!-leading!-coeffts,i)));
  227. coefft!-vectors:=uv;
  228. return nil >>;
  229. factor!-trace <<
  230. printstr
  231. "By exploiting any sparsity wrt the main variable in the";
  232. printstr "factors, we can try guessing some of the multivariate";
  233. printstr "coefficients." >>;
  234. try!-other!-coeffts(r,unknowns!-list,uv);
  235. w:=convert!-and!-trial!-divide uv;
  236. trace!-time
  237. if full!-gcd then printc "Possible gcd found"
  238. else printc "Have found some coefficients";
  239. return set!-up!-globals(uv,w)
  240. end;
  241. symbolic procedure convert!-factor!-to!-termvector(u,tlc);
  242. % ...;
  243. begin scalar termlist,res,n,slist;
  244. termlist:=(ldeg u . tlc) . list!-terms!-in!-factor red u;
  245. res:=mkvect (n:=length termlist);
  246. for i:=1:n do <<
  247. slist:=(caar termlist . i) . slist;
  248. putv(res,i,car termlist);
  249. termlist:=cdr termlist >>;
  250. putv(res,0,(n . (n #- 1)));
  251. unknowns!-list:=(reversewoc slist) . unknowns!-list;
  252. return res
  253. end;
  254. symbolic procedure try!-first!-coefft(n,c,slist,uv);
  255. % ...;
  256. begin scalar combns,unknown,w,l,d,v,m;
  257. combns:=get!-term(n,slist);
  258. if (combns='no) or not null cdr combns then return nil;
  259. l:=car combns;
  260. for i:=1:number!-of!-factors do <<
  261. w:=getv(getv(uv,i),car l); % degree . coefft ;
  262. if null cdr w then <<
  263. if unknown then <<c := nil; i := number!-of!-factors + 1>>
  264. else <<unknown := i . car l; d := car w>>>>
  265. else <<
  266. c:=quotf(c,cdr w);
  267. if didntgo c then i := number!-of!-factors+1>>;
  268. l:=cdr l >>;
  269. if didntgo c then return nil;
  270. putv(v:=getv(uv,car unknown),cdr unknown,(d . c));
  271. m:=getv(v,0);
  272. putv(v,0,(car m . (cdr m #- 1)));
  273. if cdr m = 1 and factors!-complete uv then return 'complete;
  274. return c
  275. end;
  276. symbolic procedure solve!-next!-coefft(n,c,slist,uv);
  277. % ...;
  278. begin scalar combns,w,unknown,deg!-of!-unknown,divisor!-for!-unknown,
  279. difference!-for!-unknown,v;
  280. difference!-for!-unknown:=polyzero;
  281. divisor!-for!-unknown:=polyzero;
  282. combns:=get!-term(n,slist);
  283. if combns='no then return 'nogood;
  284. while combns do <<
  285. w:=split!-term!-list(car combns,uv);
  286. if w='nogood then combns := nil else combns:=cdr combns >>;
  287. if w='nogood then return w;
  288. if null unknown then return;
  289. w:=quotf(addf(c,negf difference!-for!-unknown),
  290. divisor!-for!-unknown);
  291. if didntgo w then return 'nogood;
  292. putv(v:=getv(uv,car unknown),cdr unknown,(deg!-of!-unknown . w));
  293. n:=getv(v,0);
  294. putv(v,0,(car n . (cdr n #- 1)));
  295. if cdr n = 1 and factors!-complete uv then return 'complete;
  296. return w
  297. end;
  298. symbolic procedure split!-term!-list(term!-combn,uv);
  299. % ...;
  300. begin scalar a,v,w;
  301. a:=1;
  302. for i:=1:number!-of!-factors do <<
  303. w:=getv(getv(uv,i),car term!-combn); % degree . coefft ;
  304. if null cdr w then
  305. if v or (unknown and not((i.car term!-combn)=unknown)) then
  306. <<v:='nogood; i := number!-of!-factors+1>>
  307. else <<
  308. unknown:=(i . car term!-combn);
  309. deg!-of!-unknown:=car w;
  310. v:=unknown >>
  311. else a:=multf(a,cdr w);
  312. if not(v eq 'nogood) then term!-combn:=cdr term!-combn >>;
  313. if v='nogood then return v;
  314. if v then divisor!-for!-unknown:=addf(divisor!-for!-unknown,a)
  315. else difference!-for!-unknown:=addf(difference!-for!-unknown,a);
  316. return 'ok
  317. end;
  318. symbolic procedure factors!-complete uv;
  319. % ...;
  320. begin scalar factor!-not!-done,r;
  321. r:=t;
  322. for i:=1:number!-of!-factors do
  323. if not(cdr getv(getv(uv,i),0)=0) then
  324. if factor!-not!-done then <<r:=nil; i:=number!-of!-factors+1>>
  325. else factor!-not!-done:=t;
  326. return r
  327. end;
  328. symbolic procedure convert!-and!-trial!-divide uv;
  329. % ...;
  330. begin scalar w,r,fdone!-product!-mod!-p,om;
  331. om:=set!-modulus hensel!-growth!-size;
  332. fdone!-product!-mod!-p:=1;
  333. for i:=1:number!-of!-factors do <<
  334. w:=getv(uv,i);
  335. w:= if (cdr getv(w,0))=0 then termvector2sf w
  336. else merge!-terms(getv(image!-factors,i),w);
  337. r:=quotf(multivariate!-input!-poly,w);
  338. if didntgo r then best!-known!-factor!-list:=
  339. ((i . w) . best!-known!-factor!-list)
  340. else if reconstructing!-gcd and i=1
  341. then <<full!-gcd:=if non!-monic then car primitive!.parts(
  342. list w,m!-image!-variable,nil) else w;
  343. i := number!-of!-factors+1>>
  344. else <<
  345. multivariate!-factors:=w . multivariate!-factors;
  346. fdone!-product!-mod!-p:=times!-mod!-p(
  347. reduce!-mod!-p getv(image!-factors,i),
  348. fdone!-product!-mod!-p);
  349. multivariate!-input!-poly:=r >> >>;
  350. if full!-gcd then return;
  351. if null best!-known!-factor!-list then multivariate!-factors:=
  352. primitive!.parts(multivariate!-factors,m!-image!-variable,nil)
  353. else if null cdr best!-known!-factor!-list then <<
  354. if reconstructing!-gcd then
  355. if not(caar best!-known!-factor!-list=1) then
  356. errorf("gcd is jiggered in determining other coeffts")
  357. else full!-gcd:=if non!-monic then car primitive!.parts(
  358. list multivariate!-input!-poly,
  359. m!-image!-variable,nil)
  360. else multivariate!-input!-poly
  361. else multivariate!-factors:=primitive!.parts(
  362. multivariate!-input!-poly . multivariate!-factors,
  363. m!-image!-variable,nil);
  364. best!-known!-factor!-list:=nil >>;
  365. factor!-trace <<
  366. if null best!-known!-factor!-list then
  367. printstr
  368. "We have completely determined all the factors this way"
  369. else if multivariate!-factors then <<
  370. prin2!* "We have completely determined the following factor";
  371. printstr if (length multivariate!-factors)=1 then ":" else "s:";
  372. for each ww in multivariate!-factors do printsf ww >> >>;
  373. set!-modulus om;
  374. return fdone!-product!-mod!-p
  375. end;
  376. symbolic procedure set!-up!-globals(uv,f!-product);
  377. if null best!-known!-factor!-list or full!-gcd then 'done
  378. else begin scalar i,r,n,k,flist!-mod!-p,imf,om,savek;
  379. n:=length best!-known!-factor!-list;
  380. best!-known!-factors:=mkvect n;
  381. coefft!-vectors:=mkvect n;
  382. r:=mkvect n;
  383. k:=if reconstructing!-gcd then 1 else 0;
  384. om:=set!-modulus hensel!-growth!-size;
  385. for each w in best!-known!-factor!-list do <<
  386. i:=car w; w:=cdr w;
  387. if reconstructing!-gcd and i=1 then << savek:=k; k:=1 >>
  388. else k:=k #+ 1;
  389. % in case we are reconstructing gcd we had better know
  390. % which is the gcd and which the cofactor - so don't move
  391. % move the gcd from elt one;
  392. putv(r,k,imf:=getv(image!-factors,i));
  393. flist!-mod!-p:=(reduce!-mod!-p imf) . flist!-mod!-p;
  394. putv(best!-known!-factors,k,w);
  395. putv(coefft!-vectors,k,getv(uv,i));
  396. if reconstructing!-gcd and k=1 then k:=savek;
  397. % restore k if necessary;
  398. >>;
  399. if not(n=number!-of!-factors) then <<
  400. alphalist:=for each modf in flist!-mod!-p collect
  401. (modf . remainder!-mod!-p(times!-mod!-p(f!-product,
  402. cdr get!-alpha modf),modf));
  403. number!-of!-factors:=n >>;
  404. set!-modulus om;
  405. image!-factors:=r;
  406. return 'need! to! reconstruct
  407. end;
  408. symbolic procedure get!-term(n,l);
  409. % ...;
  410. if n#<0 then 'no
  411. else if null cdr l then get!-term!-n(n,car l)
  412. else begin scalar w,res;
  413. for each fterm in car l do <<
  414. w:=get!-term(n#-car fterm,cdr l);
  415. if not(w='no) then res:=
  416. append(for each v in w collect (cdr fterm . v),res) >>;
  417. return if null res then 'no else res
  418. end;
  419. symbolic procedure get!-term!-n(n,u);
  420. if null u or n #> caar u then 'no
  421. else if caar u = n then list(cdar u . nil)
  422. else get!-term!-n(n,cdr u);
  423. endmodule;
  424. module ezgcdf; % Polynomial GCD algorithms.
  425. % Author: A. C. Norman, 1981;
  426. fluid '(!*exp
  427. !*gcd
  428. !*heugcd
  429. !*overview
  430. !*timings
  431. !*trfac
  432. alphalist
  433. bad!-case
  434. best!-known!-factors
  435. current!-modulus
  436. dmode!*
  437. factor!-level
  438. factor!-trace!-list
  439. full!-gcd
  440. hensel!-growth!-size
  441. image!-factors
  442. image!-set
  443. irreducible
  444. kord!*
  445. m!-image!-variable
  446. multivariate!-factors
  447. multivariate!-input!-poly
  448. non!-monic
  449. no!-of!-primes!-to!-try
  450. number!-of!-factors
  451. prime!-base
  452. reconstructing!-gcd
  453. reduced!-degree!-lclst
  454. reduction!-count
  455. target!-factor!-count
  456. true!-leading!-coeffts
  457. unlucky!-case);
  458. symbolic procedure ezgcdf(u,v);
  459. %entry point for REDUCE call in GCDF;
  460. begin scalar factor!-level;
  461. factor!-level := 0;
  462. return poly!-abs gcdlist list(u,v)
  463. end;
  464. %symbolic procedure simpezgcd u;
  465. % calculate the gcd of the polynomials given as arguments;
  466. % begin
  467. % scalar factor!-level,w;
  468. % factor!-level:=0;
  469. % u := for each p in u collect <<
  470. % w := simp!* p;
  471. % if (denr w neq 1) then
  472. % rederr "EZGCD requires polynomial arguments";
  473. % numr w >>;
  474. % return (poly!-abs gcdlist u) ./ 1
  475. % end;
  476. %put('ezgcd,'simpfn,'simpezgcd);
  477. symbolic procedure simpnprimitive p;
  478. % Remove any simple numeric factors from the expression P;
  479. begin
  480. scalar np,dp;
  481. if atom p or not atom cdr p then
  482. rederr "NPRIMITIVE requires just one argument";
  483. p := simp!* car p;
  484. if polyzerop(numr p) then return nil ./ 1;
  485. np := quotfail(numr p,numeric!-content numr p);
  486. dp := quotfail(denr p,numeric!-content denr p);
  487. return (np ./ dp)
  488. end;
  489. put('nprimitive,'simpfn,'simpnprimitive);
  490. symbolic procedure poly!-gcd(u,v);
  491. %U and V are standard forms.
  492. %Value is the gcd of U and V;
  493. begin scalar xexp,z;
  494. if polyzerop u then return poly!-abs v
  495. else if polyzerop v then return poly!-abs u
  496. else if u=1 or v=1 then return 1;
  497. xexp := !*exp;
  498. !*exp := t;
  499. % The case of one argument exactly dividing the other is
  500. % detected specially here because it is perhaps a fairly
  501. % common circumstance;
  502. if quotf1(u,v) then z := v
  503. else if quotf1(v,u) then z := u
  504. else if !*gcd then z := gcdlist list(u,v)
  505. else z := 1;
  506. !*exp := xexp;
  507. return poly!-abs z
  508. end;
  509. % moved('gcdf,'poly!-gcd);
  510. symbolic procedure ezgcd!-comfac p;
  511. %P is a standard form
  512. %CAR of result is lowest common power of leading kernel in
  513. %every term in P (or NIL). CDR is gcd of all coefficients of
  514. %powers of leading kernel;
  515. if domainp p then nil . poly!-abs p
  516. else if null red p then lpow p . poly!-abs lc p
  517. else begin
  518. scalar power,coeflist,var;
  519. % POWER will be the first part of the answer returned,
  520. % COEFLIST will collect a list of all coefs in the polynomial
  521. % P viewed as a poly in its main variable,
  522. % VAR is the main variable concerned;
  523. var := mvar p;
  524. while mvar p=var and not domainp red p do <<
  525. coeflist := lc p . coeflist;
  526. p:=red p >>;
  527. if mvar p=var then <<
  528. coeflist := lc p . coeflist;
  529. if null red p then power := lpow p
  530. else coeflist := red p . coeflist >>
  531. else coeflist := p . coeflist;
  532. return power . gcdlist coeflist
  533. end;
  534. symbolic procedure gcd!-with!-number(n,a);
  535. % n is a number, a is a polynomial - return their gcd, given that
  536. % n is non-zero;
  537. if n=1 or not atom n or flagp(dmode!*,'field) then 1
  538. else if domainp a
  539. then if a=nil then abs n
  540. else if not atom a then 1
  541. else gcddd(n,a)
  542. else gcd!-with!-number(gcd!-with!-number(n,lc a),red a);
  543. % moved('gcdfd,'gcd!-with!-number);
  544. symbolic procedure contents!-with!-respect!-to(p,v);
  545. if domainp p then nil . poly!-abs p
  546. else if mvar p=v then ezgcd!-comfac p
  547. else begin
  548. scalar y,w;
  549. y := setkorder list v;
  550. p := reorder p;
  551. w := ezgcd!-comfac p;
  552. setkorder y;
  553. p := reorder p;
  554. return reorder w
  555. end;
  556. symbolic procedure numeric!-content form;
  557. % Find numeric content of non-zero polynomial;
  558. if domainp form then abs form
  559. else if null red form then numeric!-content lc form
  560. else begin
  561. scalar g1;
  562. g1 := numeric!-content lc form;
  563. if not (g1=1) then g1 := gcddd(g1,numeric!-content red form);
  564. return g1
  565. end;
  566. symbolic procedure gcdlist l;
  567. % Return the GCD of all the polynomials in the list L.
  568. %
  569. % First find all variables mentioned in the polynomials in L,
  570. % and remove monomial content from them all. If in the process
  571. % a constant poly is found, take special action. If then there
  572. % is some variable that is mentioned in all the polys in L, and
  573. % which occurs only linearly in one of them establish that as
  574. % main variable and proceed to GCDLIST3 (which will take
  575. % a special case exit). Otherwise, if there are any variables that
  576. % do not occur in all the polys in L they can not occur in the GCD,
  577. % so take coefficients with respect to them to get a longer list of
  578. % smaller polynomials - restart. Finally we have a set of polys
  579. % all involving exactly the same set of variables;
  580. if null l then nil
  581. else if null cdr l then poly!-abs car l
  582. else if domainp car l then gcdld(cdr l,car l)
  583. else begin
  584. scalar l1,gcont,x;
  585. % Copy L to L1, but on the way detect any domain elements
  586. % and deal with them specially;
  587. while not null l do <<
  588. if null car l then l := cdr l
  589. else if domainp car l then <<
  590. l1 := list list gcdld(cdr l,gcdld(mapcarcar l1,car l));
  591. l := nil >>
  592. else <<
  593. l1 := (car l . powers1 car l) . l1;
  594. l := cdr l >> >>;
  595. if null l1 then return nil
  596. else if null cdr l1 then return poly!-abs caar l1;
  597. % Now L1 is a list where each polynomial is paired with information
  598. % about the powers of variables in it;
  599. gcont := nil; % Compute monomial content on things in L;
  600. x := nil; % First time round flag;
  601. l := for each p in l1 collect begin
  602. scalar gcont1,gcont2,w;
  603. % Set GCONT1 to least power information, and W to power
  604. % difference;
  605. w := for each y in cdr p
  606. collect << gcont1 := (car y . cddr y) . gcont1;
  607. car y . (cadr y-cddr y) >>;
  608. % Now get the monomial content as a standard form (in GCONT2);
  609. gcont2 := numeric!-content car p;
  610. if null x then << gcont := gcont1; x := gcont2 >>
  611. else << gcont := vintersection(gcont,gcont1);
  612. % Accumulate monomial gcd;
  613. x := gcddd(x,gcont2) >>;
  614. for each q in gcont1 do if not cdr q=0 then
  615. gcont2 := multf(gcont2,!*p2f mksp(car q,cdr q));
  616. return quotfail1(car p,gcont2,"Term content division failed")
  617. . w
  618. end;
  619. % Here X is the numeric part of the final GCD;
  620. for each q in gcont do x := multf(x,!*p2f mksp(car q,cdr q));
  621. trace!-time <<
  622. prin2!* "Term gcd = ";
  623. printsf x >>;
  624. return poly!-abs multf(x,gcdlist1 l)
  625. end;
  626. symbolic procedure gcdlist1 l;
  627. % Items in L are monomial-primitive, and paired with power information.
  628. % Find out what variables are common to all polynomials in L and
  629. % remove all others;
  630. begin
  631. scalar unionv,intersectionv,vord,x,l1,reduction!-count;
  632. unionv := intersectionv := cdar l;
  633. for each p in cdr l do <<
  634. unionv := vunion(unionv,cdr p);
  635. intersectionv := vintersection(intersectionv,cdr p) >>;
  636. if null intersectionv then return 1;
  637. for each v in intersectionv do
  638. unionv := vdelete(v,unionv);
  639. % Now UNIONV is list of those variables mentioned that
  640. % are not common to all polynomials;
  641. intersectionv := sort(intersectionv,function lesspcdr);
  642. if cdar intersectionv=1 then <<
  643. % I have found something that is linear in one of its variables;
  644. vord := mapcarcar append(intersectionv,unionv);
  645. l1 := setkorder vord;
  646. trace!-time <<
  647. prin2 "Selecting "; prin2 caar intersectionv;
  648. printc " as main because some poly is linear in it" >>;
  649. x := gcdlist3(for each p in l collect reorder car p,nil,vord);
  650. setkorder l1;
  651. return reorder x >>
  652. else if null unionv then return gcdlist2(l,intersectionv);
  653. trace!-time <<
  654. prin2 "The variables "; prin2 unionv; printc " can be removed" >>;
  655. vord := setkorder mapcarcar append(unionv,intersectionv);
  656. l1 := nil;
  657. for each p in l do
  658. l1:=split!-wrt!-variables(reorder car p,mapcarcar unionv,l1);
  659. setkorder vord;
  660. return gcdlist1(for each p in l1 collect
  661. (reorder p . total!-degree!-in!-powers(p,nil)))
  662. end;
  663. symbolic procedure gcdlist2(l,vars);
  664. % Here all the variables in VARS are used in every polynomial
  665. % in L. Select a good variable ordering;
  666. begin
  667. scalar x,x1,gg,lmodp,onestep,vord,oldmod,image!-set,gcdpow,
  668. unlucky!-case;
  669. % In the univariate case I do not need to think very hard about
  670. % the selection of a main variable!! ;
  671. if null cdr vars
  672. then return
  673. if !*heugcd then
  674. if (x:=heu!-gcd!-list(mapcarcar l))
  675. then x
  676. else gcdlist3(mapcarcar l,nil,list caar vars)
  677. else gcdlist3(mapcarcar l,nil,list caar vars);
  678. oldmod := set!-modulus nil;
  679. % If some variable appears at most to degree two in some pair of the
  680. % polynomials then that will do as a main variable. Note that this is
  681. % not so useful if the two polynomials happen to be duplicates of each
  682. % other, but still... ;
  683. vars := mapcarcar sort(vars,function greaterpcdr);
  684. % Vars is now arranged with the variable that appears to highest
  685. % degree anywhere in L first, and the rest in descending order;
  686. l := for each p in l collect car p .
  687. sort(cdr p,function lesspcdr);
  688. l := sort(l,function lesspcdadr);
  689. % Each list of degree information in L is sorted with lowest degree
  690. % vars first, and the polynomial with the lowest degree variable
  691. % of all will come first;
  692. x := intersection(deg2vars(cdar l),deg2vars(cdadr l));
  693. if not null x then <<
  694. trace!-time << prin2 "Two inputs are at worst quadratic in ";
  695. printc car x >>;
  696. go to x!-to!-top >>; % Here I have found two polys with a common
  697. % variable that they are quadratic in;
  698. % Now generate modular images of the gcd to guess its degree wrt
  699. % all possible variables;
  700. % If either (a) modular gcd=1 or (b) modular gcd can be computed with
  701. % just 1 reduction step, use that information to choose a main variable;
  702. try!-again: % Modular images may be degenerate;
  703. set!-modulus random!-prime();
  704. unlucky!-case := nil;
  705. image!-set := for each v in vars
  706. collect (v . modular!-number next!-random!-number());
  707. trace!-time <<
  708. prin2 "Select variable ordering using P=";
  709. prin2 current!-modulus;
  710. prin2 " and substitutions from ";
  711. printc image!-set >>;
  712. x1 := vars;
  713. try!-vars:
  714. if null x1 then go to images!-tried;
  715. lmodp := for each p in l collect make!-image!-mod!-p(car p,car x1);
  716. if unlucky!-case then go to try!-again;
  717. lmodp := sort(lmodp,function lesspdeg);
  718. gg := gcdlist!-mod!-p(car lmodp,cdr lmodp);
  719. if domainp gg or (reduction!-count<2 and (onestep:=t)) then <<
  720. trace!-time << prin2 "Select "; printc car x1 >>;
  721. x := list car x1; go to x!-to!-top >>;
  722. gcdpow := (car x1 . ldeg gg) . gcdpow;
  723. x1 := cdr x1;
  724. go to try!-vars;
  725. images!-tried:
  726. % In default of anything better to do, use image variable such that
  727. % degree of gcd wrt it is as large as possible;
  728. vord := mapcarcar sort(gcdpow,function greaterpcdr);
  729. trace!-time << prin2 "Select order by degrees: ";
  730. printc gcdpow >>;
  731. go to order!-chosen;
  732. x!-to!-top:
  733. for each v in x do vars := delete(v,vars);
  734. vord := append(x,vars);
  735. order!-chosen:
  736. trace!-time << prin2 "Selected Var order = "; printc vord >>;
  737. set!-modulus oldmod;
  738. vars := setkorder vord;
  739. x := gcdlist3(for each p in l collect reorder car p,onestep,vord);
  740. setkorder vars;
  741. return reorder x
  742. end;
  743. symbolic procedure gcdlist!-mod!-p(gg,l);
  744. if null l then gg
  745. else if gg=1 then 1
  746. else gcdlist!-mod!-p(gcd!-mod!-p(gg,car l),cdr l);
  747. symbolic procedure deg2vars l;
  748. if null l then nil
  749. else if cdar l>2 then nil
  750. else caar l . deg2vars cdr l;
  751. symbolic procedure vdelete(a,b);
  752. if null b then nil
  753. else if car a=caar b then cdr b
  754. else car b . vdelete(a,cdr b);
  755. symbolic procedure intersection(u,v);
  756. if null u then nil
  757. else if member(car u,v) then car u . intersection(cdr u,v)
  758. else intersection(cdr u,v);
  759. symbolic procedure vintersection(a,b);
  760. begin
  761. scalar c;
  762. return if null a then nil
  763. else if null (c:=assoc(caar a,b)) then vintersection(cdr a,b)
  764. else if cdar a>cdr c then
  765. if cdr c=0 then vintersection(cdr a,b)
  766. else c . vintersection(cdr a,b)
  767. else if cdar a=0 then vintersection(cdr a,b)
  768. else car a . vintersection(cdr a,b)
  769. end;
  770. symbolic procedure vunion(a,b);
  771. begin
  772. scalar c;
  773. return if null a then b
  774. else if null (c:=assoc(caar a,b)) then car a . vunion(cdr a,b)
  775. else if cdar a>cdr c then car a . vunion(cdr a,delete(c,b))
  776. else c . vunion(cdr a,delete(c,b))
  777. end;
  778. symbolic procedure mapcarcar l;
  779. for each x in l collect car x;
  780. symbolic procedure gcdld(l,n);
  781. % GCD of the domain element N and all the polys in L;
  782. if n=1 or n=-1 then 1
  783. else if l=nil then abs n
  784. else if car l=nil then gcdld(cdr l,n)
  785. else gcdld(cdr l,gcd!-with!-number(n,car l));
  786. symbolic procedure split!-wrt!-variables(p,vl,l);
  787. % Push all the coeffs in P wrt variables in VL onto the list L
  788. % Stop if 1 is found as a coeff;
  789. if p=nil then l
  790. else if not null l and car l=1 then l
  791. else if domainp p then abs p . l
  792. else if member(mvar p,vl) then
  793. split!-wrt!-variables(red p,vl,split!-wrt!-variables(lc p,vl,l))
  794. else p . l;
  795. symbolic procedure gcdlist3(l,onestep,vlist);
  796. % GCD of the nontrivial polys in the list L given that they all
  797. % involve all the variables that any of them mention,
  798. % and they are all monomial-primitive.
  799. % ONESTEP is true if it is predicted that only one PRS step
  800. % will be needed to compute the gcd - if so try that PRS step;
  801. begin
  802. scalar unlucky!-case,image!-set,gg,gcont,l1,w,
  803. reduced!-degree!-lclst,p1,p2;
  804. % Make all the polys primitive;
  805. l1:=for each p in l collect p . ezgcd!-comfac p;
  806. l:=for each c in l1 collect
  807. quotfail1(car c,comfac!-to!-poly cdr c,
  808. "Content divison in GCDLIST3 failed");
  809. % All polys in L are now primitive;
  810. % Because all polys were monomial-primitive, there should
  811. % be no power of V to go in the result;
  812. gcont:=gcdlist for each c in l1 collect cddr c;
  813. if domainp gcont then if not gcont=1
  814. then errorf "GCONT has numeric part";
  815. % GCD of contents complete now;
  816. % Now I will remove duplicates from the list;
  817. trace!-time <<
  818. printc "GCDLIST3 on the polynomials";
  819. for each p in l do print p >>;
  820. l := sort(for each p in l collect poly!-abs p,function ordp);
  821. w := nil;
  822. while l do <<
  823. w := car l . w;
  824. repeat l := cdr l until null l or not car w = car l >>;
  825. l := reversewoc w;
  826. w := nil;
  827. trace!-time <<
  828. printc "Made positive, with duplicates removed...";
  829. for each p in l do print p >>;
  830. if null cdr l then return multf(gcont,car l);
  831. % That left just one poly;
  832. if domainp (gg:=car (l:=sort(l,function degree!-order))) then
  833. return gcont;
  834. % Primitive part of one poly is a constant (must be +/-1);
  835. if ldeg gg=1 then <<
  836. % True gcd is either GG or 1;
  837. if division!-test(gg,l) then return multf(poly!-abs gg,gcont)
  838. else return gcont >>;
  839. % All polys are now primitive and nontrivial. Use a modular
  840. % method to extract GCD;
  841. if onestep then <<
  842. % Try to take gcd in just one pseudoremainder step, because some
  843. % previous modular test suggests it may be possible;
  844. p1 := poly!-abs car l; p2 := poly!-abs cadr l;
  845. if p1=p2 then <<
  846. if division!-test(p1,cddr l) then return multf(p1,gcont) >>
  847. else <<
  848. trace!-time printc "Just one pseudoremainder step needed?";
  849. gg := poly!-gcd(lc p1,lc p2);
  850. gg := ezgcd!-pp addf(multf(red p1,
  851. quotfail1(lc p2,gg,
  852. "Division failure when just one pseudoremainder step needed")),
  853. multf(red p2,negf quotfail1(lc p1,gg,
  854. "Division failure when just one pseudoremainder step needed")));
  855. trace!-time printsf gg;
  856. if division!-test(gg,l) then return multf(gg,gcont) >>
  857. >>;
  858. return gcdlist31(l,vlist,gcont,gg,l1)
  859. end;
  860. symbolic procedure gcdlist31(l,vlist,gcont,gg,l1);
  861. begin scalar cofactor,lcg,old!-modulus,prime,w,w1,zeros!-list;
  862. old!-modulus:=set!-modulus nil; %Remember modulus;
  863. lcg:=for each poly in l collect lc poly;
  864. trace!-time << printc "L.C.S OF L ARE:";
  865. for each lcpoly in lcg do printsf lcpoly >>;
  866. lcg:=gcdlist lcg;
  867. trace!-time << prin2!* "LCG (=GCD OF THESE) = ";
  868. printsf lcg >>;
  869. try!-again:
  870. unlucky!-case:=nil;
  871. image!-set:=nil;
  872. set!-modulus(prime:=random!-prime());
  873. % Produce random univariate modular images of all the
  874. % polynomials;
  875. w:=l;
  876. if not zeros!-list then <<
  877. image!-set:=
  878. zeros!-list:=try!-max!-zeros!-for!-image!-set(w,vlist);
  879. trace!-time << printc image!-set;
  880. prin2 " Zeros-list = ";
  881. printc zeros!-list >> >>;
  882. trace!-time printc list("IMAGE SET",image!-set);
  883. gg:=make!-image!-mod!-p(car w,car vlist);
  884. trace!-time printc list("IMAGE SET",image!-set," GG",gg);
  885. if unlucky!-case then <<
  886. trace!-time << printc "Unlucky case, try again";
  887. print image!-set >>;
  888. go to try!-again >>;
  889. l1:=list(car w . gg);
  890. make!-images:
  891. if null (w:=cdr w) then go to images!-created!-successfully;
  892. l1:=(car w . make!-image!-mod!-p(car w,car vlist)) . l1;
  893. if unlucky!-case then <<
  894. trace!-time << printc "UNLUCKY AGAIN...";
  895. printc l1;
  896. print image!-set >>;
  897. go to try!-again >>;
  898. gg:=gcd!-mod!-p(gg,cdar l1);
  899. if domainp gg then <<
  900. set!-modulus old!-modulus;
  901. trace!-time print "Primitive parts are coprime";
  902. return gcont >>;
  903. go to make!-images;
  904. images!-created!-successfully:
  905. l1:=reversewoc l1; % Put back in order with smallest first;
  906. % If degree of gcd seems to be same as that of smallest item
  907. % in input list, that item should be the gcd;
  908. if ldeg gg=ldeg car l then <<
  909. gg:=poly!-abs car l;
  910. trace!-time <<
  911. prin2!* "Probable GCD = ";
  912. printsf gg >>;
  913. go to result >>
  914. else if (ldeg car l=add1 ldeg gg) and
  915. (ldeg car l=ldeg cadr l) then <<
  916. % Here it seems that I have just one pseudoremainder step to
  917. % perform, so I might as well do it;
  918. trace!-time <<
  919. printc "Just one pseudoremainder step needed"
  920. >>;
  921. gg := poly!-gcd(lc car l,lc cadr l);
  922. gg := ezgcd!-pp addf(multf(red car l,
  923. quotfail1(lc cadr l,gg,
  924. "Division failure when just one pseudoremainder step needed")),
  925. multf(red cadr l,negf quotfail1(lc car l,gg,
  926. "Divison failure when just one pseudoremainder step needed")));
  927. trace!-time printsf gg;
  928. go to result >>;
  929. w:=l1;
  930. find!-good!-cofactor:
  931. if null w then go to special!-case; % No good cofactor available;
  932. if domainp gcd!-mod!-p(gg,cofactor:=quotient!-mod!-p(cdar w,gg))
  933. then go to good!-cofactor!-found;
  934. w:=cdr w;
  935. go to find!-good!-cofactor;
  936. good!-cofactor!-found:
  937. cofactor:=monic!-mod!-p cofactor;
  938. trace!-time printc "*** Good cofactor found";
  939. w:=caar w;
  940. trace!-time << prin2!* "W= ";
  941. printsf w;
  942. prin2!* "GG= ";
  943. printsf gg;
  944. prin2!* "COFACTOR= ";
  945. printsf cofactor >>;
  946. image!-set:=sort(image!-set,function ordopcar);
  947. trace!-time << prin2 "IMAGE-SET = ";
  948. printc image!-set;
  949. prin2 "PRIME= "; printc prime;
  950. printc "L (=POLYLIST) IS:";
  951. for each ll in l do printsf ll >>;
  952. gg:=reconstruct!-gcd(w,gg,cofactor,prime,image!-set,lcg);
  953. if gg='nogood then go to try!-again;
  954. go to result;
  955. special!-case: % Here I have to do the first step of a PRS method;
  956. trace!-time << printc "*** SPECIAL CASE IN GCD ***";
  957. printc l;
  958. printc "----->";
  959. printc gg >>;
  960. reduced!-degree!-lclst:=nil;
  961. try!-reduced!-degree!-again:
  962. trace!-time << printc "L1 =";
  963. for each ell in l1 do print ell >>;
  964. w1:=reduced!-degree(caadr l1,caar l1);
  965. w:=car w1; w1:=cdr w1;
  966. trace!-time << prin2 "REDUCED!-DEGREE = "; printsf w;
  967. prin2 " and its image = "; printsf w1 >>;
  968. % reduce the degree of the 2nd poly using the 1st. Result is
  969. % a pair : (new poly . image new poly);
  970. if domainp w and not null w then <<
  971. set!-modulus old!-modulus; return gcont >>;
  972. % we're done as they're coprime;
  973. if w and ldeg w = ldeg gg then <<
  974. gg:=w; go to result >>;
  975. % possible gcd;
  976. if null w then <<
  977. % the first poly divided the second one;
  978. l1:=(car l1 . cddr l1); % discard second poly;
  979. if null cdr l1 then <<
  980. gg := poly!-abs caar l1;
  981. go to result >>;
  982. go to try!-reduced!-degree!-again >>;
  983. % haven't made progress yet so repeat with new polys;
  984. if ldeg w<=ldeg gg then <<
  985. gg := poly!-abs w;
  986. go to result >>
  987. else if domainp gcd!-mod!-p(gg,cofactor:=quotient!-mod!-p(w1,gg))
  988. then <<
  989. w := list list w;
  990. go to good!-cofactor!-found >>;
  991. l1:= if ldeg w <= ldeg caar l1 then
  992. ((w . w1) . (car l1 . cddr l1))
  993. else (car l1 . ((w . w1) . cddr l1));
  994. % replace first two polys by the reduced poly and the first
  995. % poly ordering according to degree;
  996. go to try!-reduced!-degree!-again;
  997. % need to repeat as we still haven't found a good cofactor;
  998. result: % Here GG holds a tentative gcd for the primitive parts of
  999. % all input polys, and GCONT holds a proper one for the content;
  1000. if division!-test(gg,l) then <<
  1001. set!-modulus old!-modulus;
  1002. return multf(gg,gcont) >>;
  1003. trace!-time printc list("Trial division by ",gg," failed");
  1004. go to try!-again
  1005. end;
  1006. symbolic procedure make!-a!-list!-of!-variables l;
  1007. begin scalar vlist;
  1008. for each ll in l do vlist:=variables!.in!.form(ll,vlist);
  1009. return make!-order!-consistent(vlist,kord!*)
  1010. end;
  1011. symbolic procedure make!-order!-consistent(l,m);
  1012. % L is a subset of M. Make its order consistent with that
  1013. % of M;
  1014. if null l then nil
  1015. else if null m then errorf("Variable missing from KORD*")
  1016. else if car m member l then car m .
  1017. make!-order!-consistent(delete(car m,l),cdr m)
  1018. else make!-order!-consistent(l,cdr m);
  1019. symbolic procedure try!-max!-zeros!-for!-image!-set(l,vlist);
  1020. if null vlist then error(50,"VLIST NOT SET IN TRY-MAX-ZEROS-...")
  1021. else begin scalar z;
  1022. z:=for each v in cdr vlist collect
  1023. if domainp lc car l or null quotf(lc car l,!*k2f v) then
  1024. (v . 0) else (v . modular!-number next!-random!-number());
  1025. for each ff in cdr l do
  1026. z:=for each w in z collect
  1027. if zerop cdr w then
  1028. if domainp lc ff or null quotf(lc ff,!*k2f car w) then w
  1029. else (car w . modular!-number next!-random!-number())
  1030. else w;
  1031. return z
  1032. end;
  1033. symbolic procedure
  1034. reconstruct!-gcd(full!-poly,gg,cofactor,p,imset,lcg);
  1035. if null addf(full!-poly,negf multf(gg,cofactor)) then gg
  1036. else (lambda factor!-level;
  1037. begin scalar number!-of!-factors,image!-factors,
  1038. true!-leading!-coeffts,multivariate!-input!-poly,
  1039. no!-of!-primes!-to!-try,
  1040. irreducible,non!-monic,bad!-case,target!-factor!-count,
  1041. multivariate!-factors,hensel!-growth!-size,alphalist,
  1042. best!-known!-factors,prime!-base,
  1043. m!-image!-variable, reconstructing!-gcd,full!-gcd;
  1044. if not(current!-modulus=p) then
  1045. errorf("GCDLIST HAS NOT RESTORED THE MODULUS");
  1046. % *WARNING* GCDLIST does not restore the modulus so
  1047. % I had better reset it here! ;
  1048. if poly!-minusp lcg then error(50,list("Negative GCD: ",lcg));
  1049. full!-poly:=poly!-abs full!-poly;
  1050. initialise!-hensel!-fluids(full!-poly,gg,cofactor,p,lcg);
  1051. trace!-time << printc "TRUE LEADING COEFFTS ARE:";
  1052. for i:=1:2 do <<
  1053. printsf getv(image!-factors,i);
  1054. prin2!* " WITH L.C.:";
  1055. printsf getv(true!-leading!-coeffts,i) >> >>;
  1056. if determine!-more!-coeffts()='done then
  1057. return full!-gcd;
  1058. if null alphalist then alphalist:=alphas(2,
  1059. list(getv(image!-factors,1),getv(image!-factors,2)),1);
  1060. if alphalist='factors! not! coprime then
  1061. errorf list("image factors not coprime?",image!-factors);
  1062. if not !*overview then factor!-trace <<
  1063. printstr
  1064. "The following modular polynomials are chosen such that:";
  1065. terpri();
  1066. prin2!* " a(2)*f(1) + a(1)*f(2) = 1 mod ";
  1067. printstr hensel!-growth!-size;
  1068. terpri();
  1069. printstr " where degree of a(1) < degree of f(1),";
  1070. printstr " and degree of a(2) < degree of f(2),";
  1071. printstr " and";
  1072. for i:=1:2 do <<
  1073. prin2!* " a("; prin2!* i; prin2!* ")=";
  1074. printsf cdr get!-alpha getv(image!-factors,i);
  1075. prin2!* "and f("; prin2!* i; prin2!* ")=";
  1076. printsf getv(image!-factors,i);
  1077. terpri!* t >>
  1078. >>;
  1079. reconstruct!-multivariate!-factors(
  1080. for each v in imset collect (car v . modular!-number cdr v));
  1081. if irreducible or bad!-case then return 'nogood
  1082. else return full!-gcd
  1083. end) (factor!-level+1) ;
  1084. symbolic procedure initialise!-hensel!-fluids(fpoly,fac1,fac2,p,lcf1);
  1085. % ... ;
  1086. begin scalar lc1!-image,lc2!-image;
  1087. reconstructing!-gcd:=t;
  1088. multivariate!-input!-poly:=multf(fpoly,lcf1);
  1089. no!-of!-primes!-to!-try := 5;
  1090. prime!-base:=hensel!-growth!-size:=p;
  1091. number!-of!-factors:=2;
  1092. lc1!-image:=make!-numeric!-image!-mod!-p lcf1;
  1093. lc2!-image:=make!-numeric!-image!-mod!-p lc fpoly;
  1094. % Neither of the above leading coefficients will vanish;
  1095. fac1:=times!-mod!-p(lc1!-image,fac1);
  1096. fac2:=times!-mod!-p(lc2!-image,fac2);
  1097. image!-factors:=mkvect 2;
  1098. true!-leading!-coeffts:=mkvect 2;
  1099. putv(image!-factors,1,fac1);
  1100. putv(image!-factors,2,fac2);
  1101. putv(true!-leading!-coeffts,1,lcf1);
  1102. putv(true!-leading!-coeffts,2,lc fpoly);
  1103. % If the GCD is going to be monic, we know the lc
  1104. % of both cofactors exactly;
  1105. non!-monic:=not(lcf1=1);
  1106. m!-image!-variable:=mvar fpoly
  1107. end;
  1108. symbolic procedure division!-test(gg,l);
  1109. % Predicate to test if GG divides all the polynomials in the list L;
  1110. if null l then t
  1111. else if null quotf(car l,gg) then nil
  1112. else division!-test(gg,cdr l);
  1113. symbolic procedure degree!-order(a,b);
  1114. % Order standard forms using their degrees wrt main vars;
  1115. if domainp a then t
  1116. else if domainp b then nil
  1117. else ldeg a<ldeg b;
  1118. symbolic procedure make!-image!-mod!-p(p,v);
  1119. % Form univariate image, set UNLUCKY!-CASE if leading coefficient
  1120. % gets destroyed;
  1121. begin
  1122. scalar lp;
  1123. lp := degree!-in!-variable(p,v);
  1124. p := make!-univariate!-image!-mod!-p(p,v);
  1125. if not degree!-in!-variable(p,v)=lp then unlucky!-case := t;
  1126. return p
  1127. end;
  1128. symbolic procedure make!-univariate!-image!-mod!-p(p,v);
  1129. % Make a modular image of P, keeping only the variable V;
  1130. if domainp p then
  1131. if p=nil then nil
  1132. else !*n2f modular!-number p
  1133. else if mvar p=v then
  1134. adjoin!-term(lpow p,
  1135. make!-univariate!-image!-mod!-p(lc p,v),
  1136. make!-univariate!-image!-mod!-p(red p,v))
  1137. else plus!-mod!-p(
  1138. times!-mod!-p(image!-of!-power(mvar p,ldeg p),
  1139. make!-univariate!-image!-mod!-p(lc p,v)),
  1140. make!-univariate!-image!-mod!-p(red p,v));
  1141. symbolic procedure image!-of!-power(v,n);
  1142. begin
  1143. scalar w;
  1144. w := assoc(v,image!-set);
  1145. if null w then <<
  1146. w := modular!-number next!-random!-number();
  1147. image!-set := (v . w) . image!-set >>
  1148. else w := cdr w;
  1149. return modular!-expt(w,n)
  1150. end;
  1151. symbolic procedure make!-numeric!-image!-mod!-p p;
  1152. % Make a modular image of P;
  1153. if domainp p then
  1154. if p=nil then 0
  1155. else modular!-number p
  1156. else modular!-plus(
  1157. modular!-times(image!-of!-power(mvar p,ldeg p),
  1158. make!-numeric!-image!-mod!-p lc p),
  1159. make!-numeric!-image!-mod!-p red p);
  1160. symbolic procedure total!-degree!-in!-powers(form,powlst);
  1161. % Returns a list where each variable mentioned in FORM is paired
  1162. % with the maximum degree it has. POWLST collects the list, and should
  1163. % normally be NIL on initial entry;
  1164. if null form or domainp form then powlst
  1165. else begin scalar x;
  1166. if (x := atsoc(mvar form,powlst))
  1167. then ldeg form>cdr x and rplacd(x,ldeg form)
  1168. else powlst := (mvar form . ldeg form) . powlst;
  1169. return total!-degree!-in!-powers(red form,
  1170. total!-degree!-in!-powers(lc form,powlst))
  1171. end;
  1172. symbolic procedure powers1 form;
  1173. % For each variable V in FORM collect (V . (MAX . MIN)) where
  1174. % MAX and MIN are limits to the degrees V has in FORM;
  1175. powers2(form,powers3(form,nil),nil);
  1176. symbolic procedure powers3(form,l);
  1177. % Start of POWERS1 by collecting power information for
  1178. % the leading monomial in FORM;
  1179. if domainp form then l
  1180. else powers3(lc form,(mvar form . (ldeg form . ldeg form)) . l);
  1181. symbolic procedure powers2(form,powlst,thismonomial);
  1182. if domainp form then
  1183. if null form then powlst else powers4(thismonomial,powlst)
  1184. else powers2(lc form,
  1185. powers2(red form,powlst,thismonomial),
  1186. lpow form . thismonomial);
  1187. symbolic procedure powers4(new,old);
  1188. % Merge information from new monomial into old information,
  1189. % updating MAX and MIN details;
  1190. if null new then for each v in old collect (car v . (cadr v . 0))
  1191. else if null old then for each v in new collect (car v . (cdr v . 0))
  1192. else if caar new=caar old then <<
  1193. % variables match - do MAX and MIN on degree information;
  1194. if cdar new>cadar old then rplaca(cdar old,cdar new);
  1195. if cdar new<cddar old then rplacd(cdar old,cdar new);
  1196. rplacd(old,powers4(cdr new,cdr old)) >>
  1197. else if ordop(caar new,caar old) then <<
  1198. rplacd(cdar old,0); % Some variable not mentioned in new monomial;
  1199. rplacd(old,powers4(new,cdr old)) >>
  1200. else (caar new . (cdar new . 0)) . powers4(cdr new,old);
  1201. symbolic procedure ezgcd!-pp u;
  1202. %returns the primitive part of the polynomial U wrt leading var;
  1203. quotf1(u,comfac!-to!-poly ezgcd!-comfac u);
  1204. symbolic procedure ezgcd!-sqfrf p;
  1205. %P is a primitive standard form;
  1206. %value is a list of square free factors;
  1207. begin
  1208. scalar pdash,p1,d,v;
  1209. pdash := diff(p,v := mvar p);
  1210. d := poly!-gcd(p,pdash); % p2*p3**2*p4**3*... ;
  1211. if domainp d then return list p;
  1212. p := quotfail1(p,d,"GCD division in FACTOR-SQFRF failed");
  1213. p1 := poly!-gcd(p,
  1214. addf(quotfail1(pdash,d,"GCD division in FACTOR-SQFRF failed"),
  1215. negf diff(p,v)));
  1216. return p1 . ezgcd!-sqfrf d
  1217. end;
  1218. symbolic procedure reduced!-degree(u,v);
  1219. %U and V are primitive polynomials in the main variable VAR;
  1220. %result is pair: (reduced poly of U by V . its image) where by
  1221. % reduced I mean using V to kill the leading term of U;
  1222. begin scalar var,w,x;
  1223. trace!-time << printc "ARGS FOR REDUCED!-DEGREE ARE:";
  1224. printsf u; printsf v >>;
  1225. if u=v or quotf1(u,v) then return (nil . nil)
  1226. else if ldeg v=1 then return (1 . 1);
  1227. trace!-time printc "CASE NON-TRIVIAL SO TAKE A REDUCED!-DEGREE:";
  1228. var := mvar u;
  1229. if ldeg u=ldeg v then x := negf lc u
  1230. else x:=(mksp(var,ldeg u - ldeg v) .* negf lc u) .+ nil;
  1231. w:=addf(multf(lc v,u),multf(x,v));
  1232. trace!-time printsf w;
  1233. if degr(w,var)=0 then return (1 . 1);
  1234. trace!-time << prin2 "REDUCED!-DEGREE-LCLST = ";
  1235. print reduced!-degree!-lclst >>;
  1236. reduced!-degree!-lclst := addlc(v,reduced!-degree!-lclst);
  1237. trace!-time << prin2 "REDUCED!-DEGREE-LCLST = ";
  1238. print reduced!-degree!-lclst >>;
  1239. if x := quotf1(w,lc w) then w := x
  1240. else for each y in reduced!-degree!-lclst do
  1241. while (x := quotf1(w,y)) do w := x;
  1242. u := v; v := ezgcd!-pp w;
  1243. trace!-time << printc "U AND V ARE NOW:";
  1244. printsf u; printsf v >>;
  1245. if degr(v,var)=0 then return (1 . 1)
  1246. else return (v . make!-univariate!-image!-mod!-p(v,var))
  1247. end;
  1248. % moved('comfac,'ezgcd!-comfac);
  1249. % moved('pp,'ezgcd!-pp);
  1250. endmodule;
  1251. module facmisc; % Miscellaneous routines used from several sections.
  1252. % Authors: A. C. Norman and P. M. A. Moore, 1979.
  1253. fluid '(base!-time
  1254. current!-modulus
  1255. gc!-base!-time
  1256. image!-set!-modulus
  1257. last!-displayed!-gc!-time
  1258. last!-displayed!-time
  1259. modulus!/2
  1260. othervars
  1261. polyzero
  1262. pt
  1263. save!-zset
  1264. zerovarset);
  1265. global '(!*test exp!-value e!-value!* largest!-small!-modulus
  1266. pseudo!-primes teeny!-primes);
  1267. % (1) investigate variables in polynomial;
  1268. symbolic procedure multivariatep(a,v);
  1269. if domainp a then nil
  1270. else if not(mvar a eq v) then t
  1271. else if multivariatep(lc a,v) then t
  1272. else multivariatep(red a,v);
  1273. symbolic procedure variables!-in!-form a;
  1274. % collect variables that occur in the form a;
  1275. variables!.in!.form(a,nil);
  1276. symbolic procedure get!.coefft!.bound(poly,degbd);
  1277. % calculates a coefft bound for the factors of poly. this simple
  1278. % bound is that suggested by paul wang and linda p. rothschild in
  1279. % math.comp.vol29 july 75 p.940 due to gel'fond;
  1280. % Note that for tiny polynomials the bound is forced up to be
  1281. % larger than any prime that will get used in the mod-p splitting;
  1282. max(get!-height poly * fixexpfloat sumof degbd,110);
  1283. symbolic procedure sumof degbd;
  1284. if null degbd then 0
  1285. else cdar degbd + sumof cdr degbd;
  1286. % The following vector is used by FIXEXPFLOAT to compute 2+fix exp float
  1287. % n using the appropriate constant values. If exp were available from
  1288. % the underlying LISP support system, it would be better to use that so
  1289. % that the code would be independent of the following table.
  1290. exp!-value := mkvect 10;
  1291. putv(exp!-value,0,1);
  1292. putv(exp!-value,1,3);
  1293. putv(exp!-value,2,8);
  1294. putv(exp!-value,3,21);
  1295. putv(exp!-value,4,55);
  1296. putv(exp!-value,5,149);
  1297. putv(exp!-value,6,404);
  1298. putv(exp!-value,7,1097);
  1299. putv(exp!-value,8,2981);
  1300. putv(exp!-value,9,8104);
  1301. putv(exp!-value,10,22027);
  1302. symbolic procedure fixexpfloat n;
  1303. % Compute exponential function e**n for potentially large N,
  1304. % rounding result up somewhat. Note that exp(10)=22027 or so,
  1305. % so if the basic floating point exponential function is accurate
  1306. % to 6 or so digits we are protected here against roundoff.
  1307. if n>10 then begin
  1308. scalar n2;
  1309. n2 := n/2;
  1310. return fixexpfloat(n2)*fixexpfloat(n-n2)
  1311. end
  1312. % else 2+fix exp float n;
  1313. else getv(exp!-value,n);
  1314. % (2) timer services;
  1315. symbolic procedure set!-time();
  1316. << last!-displayed!-time:=base!-time:=readtime();
  1317. last!-displayed!-gc!-time:=gc!-base!-time:=readgctime();
  1318. nil >>;
  1319. symbolic procedure print!-time m;
  1320. % display time used so far, with given message;
  1321. begin scalar total,incr,gctotal,gcincr,w;
  1322. if not !*test then return nil;
  1323. w:=readtime();
  1324. total:=w-base!-time;
  1325. incr:=w-last!-displayed!-time;
  1326. last!-displayed!-time:=w;
  1327. w:=readgctime();
  1328. gctotal:=w-gc!-base!-time;
  1329. gcincr:=w-last!-displayed!-gc!-time;
  1330. last!-displayed!-gc!-time:=w;
  1331. if atom m then prin2 m else <<
  1332. prin2 car m;
  1333. m:=cdr m;
  1334. while not atom m do << prin2 '! ; prin2 car m; m:=cdr m >>;
  1335. if not null m then << prin2 '! ; prin2 m >> >>;
  1336. prin2 " after ";
  1337. prinmilli incr;
  1338. prin2 "+";
  1339. prinmilli gcincr;
  1340. prin2 " seconds (total = ";
  1341. prinmilli total;
  1342. prin2 "+";
  1343. prinmilli gctotal;
  1344. prin2 ")";
  1345. terpri()
  1346. end;
  1347. symbolic procedure prinmilli n;
  1348. % print n/1000 as a decimal fraction with 2 decimal places;
  1349. begin
  1350. scalar u,d1,d01;
  1351. n:=n+5; %rounding;
  1352. n:=quotient(n,10); %now centiseconds;
  1353. n:=divide(n,10);
  1354. d01:=cdr n;
  1355. n:=car n;
  1356. n:=divide(n,10);
  1357. d1:=cdr n;
  1358. u:=car n;
  1359. prin2 u;
  1360. prin2 '!.;
  1361. prin2 d1;
  1362. prin2 d01;
  1363. return nil
  1364. end;
  1365. % (3) minor variations on ordinary algebraic operations;
  1366. symbolic procedure quotfail(a,b);
  1367. % version of quotf that fails if the division does;
  1368. if polyzerop a then polyzero
  1369. else begin scalar w;
  1370. w:=quotf(a,b);
  1371. if didntgo w then errorf list("UNEXPECTED DIVISION FAILURE",a,b)
  1372. else return w
  1373. end;
  1374. symbolic procedure quotfail1(a,b,msg);
  1375. % version of quotf that fails if the division does, and gives
  1376. % custom message;
  1377. if polyzerop a then polyzero
  1378. else begin scalar w;
  1379. w:=quotf(a,b);
  1380. if didntgo w then errorf msg
  1381. else return w
  1382. end;
  1383. % (4) pseudo-random prime numbers - small and large;
  1384. symbolic procedure set!-teeny!-primes();
  1385. begin scalar i;
  1386. i:=-1;
  1387. teeny!-primes:=mkvect 9;
  1388. putv(teeny!-primes,i:=iadd1 i,3);
  1389. putv(teeny!-primes,i:=iadd1 i,5);
  1390. putv(teeny!-primes,i:=iadd1 i,7);
  1391. putv(teeny!-primes,i:=iadd1 i,11);
  1392. putv(teeny!-primes,i:=iadd1 i,13);
  1393. putv(teeny!-primes,i:=iadd1 i,17);
  1394. putv(teeny!-primes,i:=iadd1 i,19);
  1395. putv(teeny!-primes,i:=iadd1 i,23);
  1396. putv(teeny!-primes,i:=iadd1 i,29);
  1397. putv(teeny!-primes,i:=iadd1 i,31)
  1398. end;
  1399. set!-teeny!-primes();
  1400. symbolic procedure random!-small!-prime();
  1401. begin
  1402. scalar p;
  1403. repeat <<p:=small!-random!-number(); if evenp p then p := iadd1 p>>
  1404. until primep p;
  1405. return p
  1406. end;
  1407. symbolic procedure small!-random!-number();
  1408. % Returns a smallish number from a distribution strongly favouring
  1409. % smaller numbers;
  1410. begin scalar w;
  1411. % The next lines generate a random value in the range 0 to 1000000.
  1412. w:=remainder(next!-random!-number(),1000)
  1413. +1000*remainder(next!-random!-number(),1000);
  1414. if w < 0 then w := w + 1000000;
  1415. w:=1.0+1.5*float w/1000000.0; % 1.0 to 2.5
  1416. w:=times(w,w); % In range 1.0 to 6.25
  1417. return fix fac!-exp w; % Should be in range 3 to 518,
  1418. % < 21 about half the time;
  1419. end;
  1420. symbolic procedure fac!-exp u;
  1421. % Simple exp routine. Assumes that Lisp has a routine for
  1422. % exponentiation of floats by integers. Relative accuracy 4.e-5.
  1423. begin scalar x; integer n;
  1424. n := fix u;
  1425. if (x := (u - float n)) > 0.5 then <<x := x - 1.0; n := n + 1>>;
  1426. u := e!-value!***n;
  1427. return u*((x+6.0)*x+12.0)/((x-6.0)*x+12.0)
  1428. end;
  1429. symbolic procedure random!-teeny!-prime l;
  1430. % get one of the first 10 primes at random providing it is
  1431. % not in the list L or that L says we have tried them all;
  1432. if l='all or (length l = 10) then nil
  1433. else begin scalar p;
  1434. repeat
  1435. p:=getv(teeny!-primes,remainder(next!-random!-number(),10))
  1436. until not member(p,l);
  1437. return p
  1438. end;
  1439. % symbolic procedure primep n;
  1440. % Test if prime. Only for use on small integers.
  1441. % n=2 or
  1442. % (n>2 and not evenp n and primetest(n,3));
  1443. % symbolic procedure primetest(n,trial);
  1444. % if igreaterp(itimes(trial,trial),n) then t
  1445. % else if iremainder(n,trial)=0 then nil
  1446. % else primetest(n,iplus(trial,2));
  1447. % PSEUDO-PRIMES will be a list of all composite numbers which are
  1448. % less than 2^24 and where 2926^(n-1) = 3315^(n-1) = 1 mod n.
  1449. pseudo!-primes:=mkvect 87;
  1450. begin
  1451. scalar i,l;
  1452. i:=0;
  1453. l:= '(2047 4033 33227 38503 56033
  1454. 137149 145351 146611 188191 226801
  1455. 252601 294409 328021 399001 410041
  1456. 488881 512461 556421 597871 636641
  1457. 665281 722261 742813 873181 950797
  1458. 1047619 1084201 1141141 1152271 1193221
  1459. 1373653 1398101 1461241 1584133 1615681
  1460. 1627921 1755001 1857241 1909001 2327041
  1461. 2508013 3057601 3363121 3542533 3581761
  1462. 3828001 4069297 4209661 4335241 4510507
  1463. 4588033 4650049 4877641 5049001 5148001
  1464. 5176153 5444489 5481451 5892511 5968873
  1465. 6186403 6189121 6733693 6868261 6955541
  1466. 7398151 7519441 8086231 8134561 8140513
  1467. 8333333 8725753 8927101 9439201 9494101
  1468. 10024561 10185841 10267951 10606681 11972017
  1469. 13390081 14063281 14469841 14676481 14913991
  1470. 15247621 15829633 16253551);
  1471. while l do <<
  1472. putv(pseudo!-primes,i,car l);
  1473. i:=i+1;
  1474. l:=cdr l >>
  1475. end;
  1476. symbolic procedure random!-prime();
  1477. begin
  1478. % I want a random prime that is smaller than largest-small-modulus.
  1479. % I do this by generating random odd integers in the range lsm/2 to
  1480. % lsm and filtering them for primality. Prime testing is done using
  1481. % a Fermat test followed by lookup in an exception table that was
  1482. % laboriously precomputed. This process should be distinctly faster
  1483. % than trial-division testing of candidate primes, but the exception
  1484. % table is tedious to compute, so I limit lsm to 2**24 here. This is
  1485. % both the value that Cambridge Lisp can support directly, an indication
  1486. % of how large an exception table I computed using 48 hours of CPU time
  1487. % and large enough that primes selected this way will hardly ever
  1488. % be unlucky just through being too small.
  1489. scalar p,w,oldmod,lsm, lsm2;
  1490. lsm := largest!-small!-modulus;
  1491. if lsm > 2**24 then lsm := 2**24;
  1492. lsm2 := lsm/2;
  1493. % W will become 1 when P is prime;
  1494. oldmod := current!-modulus;
  1495. while not (w=1) do <<
  1496. p := remainder(next!-random!-number(), lsm);
  1497. if p < lsm2 then p := p + lsm2;
  1498. if evenp p then p := p + 1;
  1499. set!-modulus p;
  1500. w:=modular!-expt(modular!-number 2926,isub1 p);
  1501. if w=1
  1502. and (modular!-expt(modular!-number 3315,isub1 p) neq 1
  1503. or pseudo!-prime!-p p)
  1504. then w:=0>>;
  1505. set!-modulus oldmod;
  1506. return p
  1507. end;
  1508. symbolic procedure pseudo!-prime!-p n;
  1509. begin
  1510. scalar low,mid,high,v;
  1511. low:=0;
  1512. high:=87; % Size of vector of pseudo-primes;
  1513. while not (high=low) do << % Binary search in table;
  1514. mid:=iquotient(iplus(iadd1 high,low),2);
  1515. % Mid point of (low,high);
  1516. v:=getv(pseudo!-primes,mid);
  1517. if igreaterp(v,n) then high:=isub1 mid else low:=mid >>;
  1518. return (getv(pseudo!-primes,low)=n)
  1519. end;
  1520. % (5) useful routines for vectors;
  1521. symbolic procedure form!-sum!-and!-product!-mod!-p(avec,fvec,r);
  1522. % sum over i (avec(i) * fvec(i));
  1523. begin scalar s;
  1524. s:=polyzero;
  1525. for i:=1:r do
  1526. s:=plus!-mod!-p(times!-mod!-p(getv(avec,i),getv(fvec,i)),
  1527. s);
  1528. return s
  1529. end;
  1530. symbolic procedure form!-sum!-and!-product!-mod!-m(avec,fvec,r);
  1531. % Same as above but AVEC holds alphas mod p and want to work
  1532. % mod m (m > p) so minor difference to change AVEC to AVEC mod m;
  1533. begin scalar s;
  1534. s:=polyzero;
  1535. for i:=1:r do
  1536. s:=plus!-mod!-p(times!-mod!-p(
  1537. !*f2mod !*mod2f getv(avec,i),getv(fvec,i)),s);
  1538. return s
  1539. end;
  1540. symbolic procedure reduce!-vec!-by!-one!-var!-mod!-p(v,pt,n);
  1541. % substitute for the given variable in all elements creating a
  1542. % new vector for the result. (all arithmetic is mod p);
  1543. begin scalar newv;
  1544. newv:=mkvect n;
  1545. for i:=1:n do
  1546. putv(newv,i,evaluate!-mod!-p(getv(v,i),car pt,cdr pt));
  1547. return newv
  1548. end;
  1549. symbolic procedure make!-bivariate!-vec!-mod!-p(v,imset,var,n);
  1550. begin scalar newv;
  1551. newv:=mkvect n;
  1552. for i:=1:n do
  1553. putv(newv,i,make!-bivariate!-mod!-p(getv(v,i),imset,var));
  1554. return newv
  1555. end;
  1556. symbolic procedure times!-vector!-mod!-p(v,n);
  1557. % product of all the elements in the vector mod p;
  1558. begin scalar w;
  1559. w:=1;
  1560. for i:=1:n do w:=times!-mod!-p(getv(v,i),w);
  1561. return w
  1562. end;
  1563. symbolic procedure make!-vec!-modular!-symmetric(v,n);
  1564. % fold each elt of V which is current a modular poly in the
  1565. % range 0->(p-1) onto the symmetric range (-p/2)->(p/2);
  1566. for i:=1:n do putv(v,i,make!-modular!-symmetric getv(v,i));
  1567. % (6) Combinatorial fns used in finding values for the variables;
  1568. symbolic procedure make!-zerovarset vlist;
  1569. % vlist is a list of pairs (v . tag) where v is a variable name and
  1570. % tag is a boolean tag. The procedure splits the list into two
  1571. % according to the tags: Zerovarset is set to a list of variables
  1572. % whose tag is false and othervars contains the rest;
  1573. for each w in vlist do
  1574. if cdr w then othervars:= car w . othervars
  1575. else zerovarset:= car w . zerovarset;
  1576. symbolic procedure make!-zeroset!-list n;
  1577. % Produces a list of lists each of length n with all combinations of
  1578. % ones and zeroes;
  1579. begin scalar w;
  1580. for k:=0:n do w:=append(w,kcombns(k,n));
  1581. return w
  1582. end;
  1583. symbolic procedure kcombns(k,m);
  1584. % produces a list of all combinations of ones and zeroes with k ones
  1585. % in each;
  1586. if k=0 or k=m then begin scalar w;
  1587. if k=m then k:=1;
  1588. for i:=1:m do w:=k.w;
  1589. return list w
  1590. end
  1591. else if k=1 or k=isub1 m then <<
  1592. if k=isub1 m then k:=0;
  1593. list!-with!-one!-a(k,1 #- k,m) >>
  1594. else append(
  1595. for each x in kcombns(isub1 k,isub1 m) collect (1 . x),
  1596. for each x in kcombns(k,isub1 m) collect (0 . x) );
  1597. symbolic procedure list!-with!-one!-a(a,b,m);
  1598. % Creates list of all lists with one a and m-1 b's in;
  1599. begin scalar w,x,r;
  1600. for i:=1:isub1 m do w:=b . w;
  1601. r:=list(a . w);
  1602. for i:=1:isub1 m do <<
  1603. x:=(car w) . x; w:=cdr w;
  1604. r:=append(x,(a . w)) . r >>;
  1605. return r
  1606. end;
  1607. symbolic procedure make!-next!-zset l;
  1608. begin scalar k,w;
  1609. image!-set!-modulus:=iadd1 image!-set!-modulus;
  1610. set!-modulus image!-set!-modulus;
  1611. w:=for each ll in cdr l collect
  1612. for each n in ll collect
  1613. if n=0 then n
  1614. else <<
  1615. k:=modular!-number next!-random!-number();
  1616. while (zerop k) or (onep k) do
  1617. k:=modular!-number next!-random!-number();
  1618. if k>modulus!/2 then k:=k-current!-modulus;
  1619. k >>;
  1620. save!-zset:=nil;
  1621. return w
  1622. end;
  1623. endmodule;
  1624. module facprim; % Factorize a primitive multivariate polynomial.
  1625. % Author: P. M. A. Moore, 1979.
  1626. % Modifications by: Arthur C. Norman.
  1627. fluid '(!*force!-zero!-set
  1628. !*overshoot
  1629. !*overview
  1630. !*timings
  1631. !*trfac
  1632. alphalist
  1633. alphavec
  1634. bad!-case
  1635. base!-time
  1636. best!-factor!-count
  1637. best!-known!-factors
  1638. best!-modulus
  1639. best!-set!-pointer
  1640. chosen!-prime
  1641. current!-factor!-product
  1642. current!-modulus
  1643. degree!-bounds
  1644. deltam
  1645. f!-numvec
  1646. factor!-level
  1647. factor!-trace!-list
  1648. factored!-lc
  1649. factorvec
  1650. facvec
  1651. fhatvec
  1652. forbidden!-primes
  1653. forbidden!-sets
  1654. full!-gcd
  1655. hensel!-growth!-size
  1656. image!-content
  1657. image!-factors
  1658. image!-lc
  1659. image!-mod!-p
  1660. image!-poly
  1661. image!-set
  1662. image!-set!-modulus
  1663. input!-leading!-coefficient
  1664. input!-polynomial
  1665. inverted
  1666. inverted!-sign
  1667. irreducible
  1668. known!-factors
  1669. kord!*
  1670. m!-image!-variable
  1671. modfvec
  1672. modular!-info
  1673. multivariate!-factors
  1674. multivariate!-input!-poly
  1675. no!-of!-best!-sets
  1676. no!-of!-primes!-to!-try
  1677. no!-of!-random!-sets
  1678. non!-monic
  1679. null!-space!-basis
  1680. number!-of!-factors
  1681. one!-complete!-deg!-analysis!-done
  1682. othervars
  1683. poly!-mod!-p
  1684. polynomial!-to!-factor
  1685. predictions
  1686. previous!-degree!-map
  1687. prime!-base
  1688. reconstructing!-gcd
  1689. reduction!-count
  1690. save!-zset
  1691. sfp!-count
  1692. split!-list
  1693. target!-factor!-count
  1694. true!-leading!-coeffts
  1695. usable!-set!-found
  1696. valid!-image!-sets
  1697. vars!-to!-kill
  1698. zero!-set!-tried
  1699. zerovarset
  1700. zset);
  1701. global '(largest!-small!-modulus);
  1702. %**********************************************************************;
  1703. %
  1704. % multivariate polynomial factorization more or less as described
  1705. % by paul wang in: math. comp. vol.32 no.144 oct 1978 pp. 1215-1231
  1706. % 'an improved multivariate polynomial factoring algorithm'
  1707. %
  1708. %**********************************************************************;
  1709. %----------------------------------------------------------------------;
  1710. % this code works by using a local database of fluid variables
  1711. % whose meaning is (hopefully) obvious.
  1712. % they are used as follows:
  1713. %
  1714. % global name: set in: comments:
  1715. %
  1716. % m!-factored!-leading! create!.images only set if non-numeric
  1717. % -coefft
  1718. % m!-factored!-images factorize!.images vector
  1719. % m!-input!-polynomial factorize!-primitive!
  1720. % -polynomial
  1721. % m!-best!-image!-pointer choose!.best!.image
  1722. % m!-image!-factors choose!.best!.image vector
  1723. % m!-true!-leading! choose!.best!.image vector
  1724. % -coeffts
  1725. % m!-prime choose!.best!.image
  1726. % irreducible factorize!.images predicate
  1727. % inverted create!.images predicate
  1728. % m!-inverted!-sign create!-images +1 or -1
  1729. % non!-monic determine!-leading! predicate
  1730. % -coeffts
  1731. % (also reconstruct!-over!
  1732. % -integers)
  1733. % m!-number!-of!-factors choose!.best!.image
  1734. % m!-image!-variable square!.free!.factorize
  1735. % or factorize!-form
  1736. % m!-image!-sets create!.images vector
  1737. % this last contains the images of m!-input!-polynomial and the
  1738. % numbers associated with the factors of lc m!-input!-polynomial (to be
  1739. % used later) the latter existing only when the lc m!-input!-polynomial
  1740. % is non-integral. ie.:
  1741. % m!-image!-sets=< ... , (( d . u ), a, d) , ... > ( a vector)
  1742. % where: a = an image set (=association list);
  1743. % d = cont(m!-input!-polynomial image wrt a);
  1744. % u = prim.part.(same) which is non-trivial square-free
  1745. % by choice of image set.;
  1746. % d = vector of numbers associated with factors in lc
  1747. % m!-input!-polynomial (these depend on a as well);
  1748. % the number of entries in m!-image!-sets is defined by the fluid
  1749. % variable, no.of.random.sets;
  1750. %
  1751. %
  1752. %
  1753. %----------------------------------------------------------------------;
  1754. %**********************************************************************;
  1755. % multivariate factorization part 1. entry point for this code:
  1756. % ** n.b.** the polynomial is assumed to be non-trivial and primitive;
  1757. symbolic procedure square!.free!.factorize u;
  1758. % u primitive (multivariate) poly but not yet square free.
  1759. % result is list of factors consed with their respective multiplicities:
  1760. % ((f1 . m1),(f2 . m2),...) where mi may = mj when i not = j ;
  1761. % u is non-trivial - ie. at least linear in some variable;
  1762. %***** nb. this does not use best square free method *****;
  1763. begin scalar v,w,x,i,newu,f!.list,sfp!-count;
  1764. sfp!-count:=0;
  1765. factor!-trace
  1766. if not u=polynomial!-to!-factor then
  1767. << prin2!* "Primitive polynomial to factor: ";
  1768. printsf u >>;
  1769. if null m!-image!-variable then
  1770. errorf list("M-IMAGE-VARIABLE not set: ",u);
  1771. v:=poly!-gcd(u,
  1772. derivative!-wrt!-main!-variable(u,m!-image!-variable));
  1773. if onep v then <<
  1774. factor!-trace printstr "The polynomial is square-free.";
  1775. return square!-free!-prim!-factor(u,1) >>
  1776. else factor!-trace <<
  1777. printstr
  1778. "We now square-free decompose this to produce a series of ";
  1779. printstr
  1780. "(square-free primitive) factors which we treat in turn: ";
  1781. terpri(); terpri() >>;
  1782. w:=quotfail(u,v);
  1783. x:=poly!-gcd(v,w);
  1784. newu:=quotfail(w,x);
  1785. if not onep newu then
  1786. << f!.list:=append(f!.list,
  1787. square!-free!-prim!-factor(newu,1))
  1788. >>;
  1789. i:=2; % power of next factors;
  1790. % from now on we can avoid an extra gcd and any diffn;
  1791. while not domainp v do
  1792. << v:=quotfail(v,x);
  1793. w:=quotfail(w,newu);
  1794. x:=poly!-gcd(v,w);
  1795. newu:=quotfail(w,x);
  1796. if not onep newu then
  1797. << f!.list:=append(f!.list,
  1798. square!-free!-prim!-factor(newu,i))
  1799. >>;
  1800. i:=iadd1 i
  1801. >>;
  1802. if not v=1 then f!.list:=(v . 1) . f!.list;
  1803. return f!.list
  1804. end;
  1805. symbolic procedure square!-free!-prim!-factor(u,i);
  1806. % factorize the square-free primitive factor u whose multiplicity
  1807. % in the original poly is i. return the factors consed with this
  1808. % multiplicity;
  1809. begin scalar w;
  1810. sfp!-count:=iadd1 sfp!-count;
  1811. factor!-trace <<
  1812. if not(u=polynomial!-to!-factor) then <<
  1813. prin2!* "("; prin2!* sfp!-count;
  1814. prin2!* ") Square-free primitive factor: "; printsf u;
  1815. prin2!* " with multiplicity "; prin2!* i;
  1816. terpri!*(nil) >> >>;
  1817. w:=distribute!.multiplicity(factorize!-primitive!-polynomial u,i);
  1818. factor!-trace
  1819. if not u=polynomial!-to!-factor then <<
  1820. prin2!* "Factors of ("; prin2!* sfp!-count;
  1821. printstr ") are: "; fac!-printfactors(1 . w);
  1822. terpri(); terpri() >>;
  1823. return w
  1824. end;
  1825. symbolic procedure distribute!.multiplicity(factorlist,n);
  1826. % factorlist is a simple list of factors of a square free primitive
  1827. % multivariate poly and n is their multiplicity in a square free
  1828. % decomposition of another polynomial. result is a list of form:
  1829. % ((f1 . n),(f2 . n),...) where fi are the factors.;
  1830. for each w in factorlist collect (w . n);
  1831. symbolic procedure factorize!-primitive!-polynomial u;
  1832. % u is primitive square free and at least linear in
  1833. % m!-image!-variable. m!-image!-variable is the variable preserved in
  1834. % the univariate images. this function determines a random set of
  1835. % integers and a prime to create a univariate modular image of u,
  1836. % factorize it and determine the leading coeffts of the factors in the
  1837. % full factorization of u. finally the modular image factors are grown
  1838. % up to the full multivariates ones using the hensel construction;
  1839. % result is simple list of irreducible factors;
  1840. if degree!-in!-variable(u,m!-image!-variable) = 1 then list u
  1841. else if degree!-in!-variable(u,m!-image!-variable) = 2 then
  1842. factorize!-quadratic u
  1843. else if fac!-univariatep u then
  1844. univariate!-factorize u
  1845. else begin scalar
  1846. valid!-image!-sets,factored!-lc,image!-factors,prime!-base,
  1847. one!-complete!-deg!-analysis!-done,zset,zerovarset,othervars,
  1848. multivariate!-input!-poly,best!-set!-pointer,reduction!-count,
  1849. true!-leading!-coeffts,number!-of!-factors,
  1850. inverted!-sign,irreducible,inverted,vars!-to!-kill,
  1851. forbidden!-sets,zero!-set!-tried,non!-monic,
  1852. no!-of!-best!-sets,no!-of!-random!-sets,bad!-case,
  1853. target!-factor!-count,modular!-info,multivariate!-factors,
  1854. hensel!-growth!-size,alphalist,base!-timer,w!-time,
  1855. previous!-degree!-map,image!-set!-modulus,
  1856. best!-known!-factors,reconstructing!-gcd,full!-gcd;
  1857. base!-timer:=time();
  1858. trace!-time display!-time(
  1859. " Entered multivariate primitive polynomial code after ",
  1860. base!-timer - base!-time);
  1861. %note that this code works by using a local database of
  1862. %fluid variables that are updated by the subroutines directly
  1863. %called here. this allows for the relativly complicated
  1864. %interaction between flow of data and control that occurs in
  1865. %the factorization algorithm.
  1866. factor!-trace <<
  1867. printstr "From now on we shall refer to this polynomial as U.";
  1868. printstr
  1869. "We now create an image of U by picking suitable values ";
  1870. printstr "for all but one of the variables in U.";
  1871. prin2!* "The variable preserved in the image is ";
  1872. prinvar m!-image!-variable; terpri!*(nil) >>;
  1873. initialize!-fluids u;
  1874. % set up the fluids to start things off;
  1875. w!-time:=time();
  1876. tryagain:
  1877. get!-some!-random!-sets();
  1878. choose!-the!-best!-set();
  1879. trace!-time <<
  1880. display!-time("Modular factoring and best set chosen in ",
  1881. time()-w!-time);
  1882. w!-time:=time() >>;
  1883. if irreducible then return list u
  1884. else if bad!-case then <<
  1885. if !*overshoot then printc "Bad image sets - loop";
  1886. bad!-case:=nil; goto tryagain >>;
  1887. reconstruct!-image!-factors!-over!-integers();
  1888. trace!-time <<
  1889. display!-time("Image factors reconstructed in ",time()-w!-time);
  1890. w!-time:=time() >>;
  1891. if irreducible then return list u
  1892. else if bad!-case then <<
  1893. if !*overshoot then printc "Bad image factors - loop";
  1894. bad!-case:=nil; goto tryagain >>;
  1895. determine!.leading!.coeffts();
  1896. trace!-time <<
  1897. display!-time("Leading coefficients distributed in ",
  1898. time()-w!-time);
  1899. w!-time:=time() >>;
  1900. if irreducible then
  1901. return list u
  1902. else if bad!-case then <<
  1903. if !*overshoot then printc "Bad split shown by LC distribution";
  1904. bad!-case:=nil; goto tryagain >>;
  1905. if determine!-more!-coeffts()='done then <<
  1906. trace!-time <<
  1907. display!-time("All the coefficients distributed in ",
  1908. time()-w!-time);
  1909. w!-time:=time() >>;
  1910. return check!-inverted multivariate!-factors >>;
  1911. trace!-time <<
  1912. display!-time("More coefficients distributed in ",
  1913. time()-w!-time);
  1914. w!-time:=time() >>;
  1915. reconstruct!-multivariate!-factors(nil);
  1916. if bad!-case and not irreducible then <<
  1917. if !*overshoot then printc "Multivariate overshoot - restart";
  1918. bad!-case:=nil; goto tryagain >>;
  1919. trace!-time
  1920. display!-time("Multivariate factors reconstructed in ",
  1921. time()-w!-time);
  1922. if irreducible then return list u;
  1923. return check!-inverted multivariate!-factors
  1924. end;
  1925. symbolic procedure getcof(p, v, n);
  1926. % Get coeff of v^n in p;
  1927. % I bet this exists somewhere under a different name....
  1928. if domainp p then if n=0 then p else nil
  1929. else if mvar p = v then
  1930. if ldeg p=n then lc p
  1931. else getcof(red p, v, n)
  1932. else addf(multf((lpow p .* 1) .+ nil, getcof(lc p, v, n)),
  1933. getcof(red p, v, n));
  1934. symbolic procedure factorize!-quadratic u;
  1935. % U is a primitive square-free quadratic. It factors if and only if
  1936. % its discriminant is a perfect square;
  1937. begin
  1938. scalar a, b, c, discr, f1, f2, x;
  1939. % I am unreasonably cautious here - i THINK that the image variable
  1940. % should be the main var here, but in case things have goot themselves
  1941. % reordered & to make myself bomb proof against future changes I will
  1942. % not assume same
  1943. a := getcof(u, m!-image!-variable, 2);
  1944. b := getcof(u, m!-image!-variable, 1);
  1945. c := getcof(u, m!-image!-variable, 0);
  1946. discr := addf(multf(b, b), multf(a, multf(-4, c)));
  1947. discr := sqrtf2 discr;
  1948. if discr=-1 then return list u; % Irreducible;
  1949. x := addf(multf(a, multf(2, !*k2f m!-image!-variable)), b);
  1950. f1 := addf(x, discr);
  1951. f2 := addf(x, negf discr);
  1952. f1 := quotf(f1,
  1953. cdr contents!-with!-respect!-to(f1, m!-image!-variable));
  1954. f2 := quotf(f2,
  1955. cdr contents!-with!-respect!-to(f2, m!-image!-variable));
  1956. return list(f1, f2)
  1957. end;
  1958. symbolic procedure sqrtd2 d;
  1959. % Square root of domain element or -1 if it does not have an exact one;
  1960. % Possibly needs upgrades to deal with non-integer domains, e.g. in
  1961. % modular arithmetic just half of all values have square roots (= are
  1962. % quadratic residues), but finding the roots is (I think) HARD. In
  1963. % floating point it could be taken that all positive values have square
  1964. % roots. Anyway somebody can adjust this as necessary and I think that
  1965. % SQRTF2 will then behave properly...
  1966. if d=nil then nil
  1967. else if not fixp d or d<0 then -1
  1968. else begin
  1969. scalar q, r, rold;
  1970. q := pmam!-sqrt d; % Works even if D is really huge;
  1971. r := q*q-d;
  1972. repeat <<
  1973. rold := abs r;
  1974. q := q - (r+q)/(2*q); % / truncates, so this rounds to nearest
  1975. r := q*q-d >> until abs r >= rold;
  1976. if r=0 then return q
  1977. else return -1
  1978. end;
  1979. symbolic procedure sqrtf2 p;
  1980. % Return square root of the polynomial P if there is an exact one,
  1981. % else returns -1 to indicate failure;
  1982. if domainp p then sqrtd2 p
  1983. else begin
  1984. scalar v, d, qlc, q, r, w;
  1985. if not evenp (d := ldeg p) or
  1986. (qlc := sqrtf2 lc p) = -1 then return -1;
  1987. d := d/2;
  1988. v := mvar p;
  1989. q := (mksp(v, d) .* qlc) .+ nil; % First approx to sqrt(P)
  1990. r := multf(2, q);
  1991. p := red p; % Residue
  1992. while p neq nil and
  1993. mvar p = v and
  1994. ldeg p >= d and
  1995. (w := quotf(lt p .+ nil, r)) neq nil do
  1996. << p := addf(p, multf(negf w, addf(multf(2, q), w)));
  1997. q := addf(q, w) >>;
  1998. if p=nil then return q else return -1
  1999. end;
  2000. symbolic procedure initialize!-fluids u;
  2001. % Set up the fluids to be used in factoring primitive poly;
  2002. begin scalar w,w1,wtime;
  2003. if !*force!-zero!-set then <<
  2004. no!-of!-random!-sets:=1;
  2005. no!-of!-best!-sets:=1 >>
  2006. else <<
  2007. no!-of!-random!-sets:=9;
  2008. % we generate this many and calculate their factor counts.
  2009. no!-of!-best!-sets:=5;
  2010. % we find the modular factors of this many;
  2011. >>;
  2012. image!-set!-modulus:=5;
  2013. vars!-to!-kill:=variables!-to!-kill lc u;
  2014. multivariate!-input!-poly:=u;
  2015. no!-of!-primes!-to!-try := 5;
  2016. target!-factor!-count:=degree!-in!-variable(u,m!-image!-variable);
  2017. if not domainp lc multivariate!-input!-poly then
  2018. if domainp (w:=
  2019. trailing!.coefft(multivariate!-input!-poly,
  2020. m!-image!-variable)) then
  2021. << inverted:=t;
  2022. % note that we are 'inverting' the poly m!-input!-polynomial;
  2023. w1:=invert!.poly(multivariate!-input!-poly,m!-image!-variable);
  2024. multivariate!-input!-poly:=cdr w1;
  2025. inverted!-sign:=car w1;
  2026. % to ease the lc problem, m!-input!-polynomial <- poly
  2027. % produced by taking numerator of (m!-input!-polynomial
  2028. % with 1/m!-image!-variable substituted for
  2029. % m!-image!-variable);
  2030. % m!-inverted!-sign is -1 if we have inverted the sign of
  2031. % the resulting poly to keep it +ve, else +1;
  2032. factor!-trace <<
  2033. prin2!* "The trailing coefficient of U wrt ";
  2034. prinvar m!-image!-variable; prin2!* "(="; prin2!* w;
  2035. printstr ") is purely numeric so we 'invert' U to give: ";
  2036. prin2!* " U <- "; printsf multivariate!-input!-poly;
  2037. printstr "This simplifies any problems with the leading ";
  2038. printstr "coefficient of U." >>
  2039. >>
  2040. else <<
  2041. trace!-time printc "Factoring the leading coefficient:";
  2042. wtime:=time();
  2043. factored!-lc:=
  2044. factorize!-form!-recursion lc multivariate!-input!-poly;
  2045. trace!-time display!-time("Leading coefficient factored in ",
  2046. time()-wtime);
  2047. % factorize the lc of m!-input!-polynomial completely;
  2048. factor!-trace <<
  2049. printstr
  2050. "The leading coefficient of U is non-trivial so we must ";
  2051. printstr "factor it before we can decide how it is distributed";
  2052. printstr "over the leading coefficients of the factors of U.";
  2053. printstr "So the factors of this leading coefficient are:";
  2054. fac!-printfactors factored!-lc >>
  2055. >>;
  2056. make!-zerovarset vars!-to!-kill;
  2057. % Sets ZEROVARSET and OTHERVARS;
  2058. if null zerovarset then zero!-set!-tried:=t
  2059. else <<
  2060. zset:=make!-zeroset!-list length zerovarset;
  2061. save!-zset:=zset >>
  2062. end;
  2063. symbolic procedure variables!-to!-kill lc!-u;
  2064. % picks out all the variables in u except var. also checks to see if
  2065. % any of these divide lc u: if they do they are dotted with t otherwise
  2066. % dotted with nil. result is list of these dotted pairs;
  2067. for each w in cdr kord!* collect
  2068. if (domainp lc!-u) or didntgo quotf(lc!-u,!*k2f w) then
  2069. (w . nil) else (w . t);
  2070. %**********************************************************************;
  2071. % multivariate factorization part 2. creating image sets and picking
  2072. % the best one;
  2073. fluid '(usable!-set!-found);
  2074. symbolic procedure get!-some!-random!-sets();
  2075. % here we create a number of random sets to make the input
  2076. % poly univariate by killing all but 1 of the variables. at
  2077. % the same time we pick a random prime to reduce this image
  2078. % poly mod p;
  2079. begin scalar image!-set,chosen!-prime,image!-lc,image!-mod!-p,wtime,
  2080. image!-content,image!-poly,f!-numvec,forbidden!-primes,i,j,
  2081. usable!-set!-found;
  2082. valid!-image!-sets:=mkvect no!-of!-random!-sets;
  2083. i:=0;
  2084. while i < no!-of!-random!-sets do <<
  2085. wtime:=time();
  2086. generate!-an!-image!-set!-with!-prime(
  2087. if i<idifference(no!-of!-random!-sets,3) then nil else t);
  2088. trace!-time
  2089. display!-time(" Image set generated in ",time()-wtime);
  2090. i:=iadd1 i;
  2091. putv(valid!-image!-sets,i,list(
  2092. image!-set,chosen!-prime,image!-lc,image!-mod!-p,image!-content,
  2093. image!-poly,f!-numvec));
  2094. forbidden!-sets:=image!-set . forbidden!-sets;
  2095. forbidden!-primes:=list chosen!-prime;
  2096. j:=1;
  2097. while (j<3) and (i<no!-of!-random!-sets) do <<
  2098. wtime:=time();
  2099. image!-mod!-p:=find!-a!-valid!-prime(image!-lc,image!-poly,
  2100. not numberp image!-content);
  2101. if not(image!-mod!-p='not!-square!-free) then <<
  2102. trace!-time
  2103. display!-time(" Prime and image mod p found in ",
  2104. time()-wtime);
  2105. i:=iadd1 i;
  2106. putv(valid!-image!-sets,i,list(
  2107. image!-set,chosen!-prime,image!-lc,image!-mod!-p,
  2108. image!-content,image!-poly,f!-numvec));
  2109. forbidden!-primes:=chosen!-prime . forbidden!-primes >>;
  2110. j:=iadd1 j
  2111. >>
  2112. >>
  2113. end;
  2114. symbolic procedure choose!-the!-best!-set();
  2115. % given several random sets we now choose the best by factoring
  2116. % each image mod its chosen prime and taking one with the
  2117. % lowest factor count as the best for hensel growth;
  2118. begin scalar split!-list,poly!-mod!-p,null!-space!-basis,
  2119. known!-factors,w,n,fnum,remaining!-split!-list,wtime;
  2120. modular!-info:=mkvect no!-of!-random!-sets;
  2121. wtime:=time();
  2122. for i:=1:no!-of!-random!-sets do <<
  2123. w:=getv(valid!-image!-sets,i);
  2124. get!-factor!-count!-mod!-p(i,get!-image!-mod!-p w,
  2125. get!-chosen!-prime w,not numberp get!-image!-content w) >>;
  2126. split!-list:=sort(split!-list,function lessppair);
  2127. % this now contains a list of pairs (m . n) where
  2128. % m is the no: of factors in image no: n. the list
  2129. % is sorted with best split (smallest m) first;
  2130. trace!-time
  2131. display!-time(" Factor counts found in ",time()-wtime);
  2132. if caar split!-list = 1 then <<
  2133. irreducible:=t; return nil >>;
  2134. w:=nil;
  2135. wtime:=time();
  2136. for i:=1:no!-of!-best!-sets do <<
  2137. n:=cdar split!-list;
  2138. get!-factors!-mod!-p(n,
  2139. get!-chosen!-prime getv(valid!-image!-sets,n));
  2140. w:=(car split!-list) . w;
  2141. split!-list:=cdr split!-list >>;
  2142. % pick the best few of these and find out their
  2143. % factors mod p;
  2144. trace!-time
  2145. display!-time(" Best factors mod p found in ",time()-wtime);
  2146. remaining!-split!-list:=split!-list;
  2147. split!-list:=reversewoc w;
  2148. % keep only those images that are fully factored mod p;
  2149. wtime:=time();
  2150. check!-degree!-sets(no!-of!-best!-sets,t);
  2151. % the best image is pointed at by best!-set!-pointer;
  2152. trace!-time
  2153. display!-time(" Degree sets analysed in ",time()-wtime);
  2154. % now if these didn't help try the rest to see
  2155. % if we can avoid finding new image sets altogether: ;
  2156. if bad!-case then <<
  2157. bad!-case:=nil;
  2158. wtime:=time();
  2159. while remaining!-split!-list do <<
  2160. n:=cdar remaining!-split!-list;
  2161. get!-factors!-mod!-p(n,
  2162. get!-chosen!-prime getv(valid!-image!-sets,n));
  2163. w:=(car remaining!-split!-list) . w;
  2164. remaining!-split!-list:=cdr remaining!-split!-list >>;
  2165. trace!-time
  2166. display!-time(" More sets factored mod p in ",time()-wtime);
  2167. split!-list:=reversewoc w;
  2168. wtime:=time();
  2169. check!-degree!-sets(no!-of!-random!-sets - no!-of!-best!-sets,t);
  2170. % best!-set!-pointer hopefully points at the best image ;
  2171. trace!-time
  2172. display!-time(" More degree sets analysed in ",time()-wtime)
  2173. >>;
  2174. one!-complete!-deg!-analysis!-done:=t;
  2175. factor!-trace <<
  2176. w:=getv(valid!-image!-sets,best!-set!-pointer);
  2177. prin2!* "The chosen image set is: ";
  2178. for each x in get!-image!-set w do <<
  2179. prinvar car x; prin2!* "="; prin2!* cdr x; prin2!* "; " >>;
  2180. terpri!*(nil);
  2181. prin2!* "and chosen prime is "; printstr get!-chosen!-prime w;
  2182. printstr "Image polynomial (made primitive) = ";
  2183. printsf get!-image!-poly w;
  2184. if not(get!-image!-content w=1) then <<
  2185. prin2!* " with (extracted) content of ";
  2186. printsf get!-image!-content w >>;
  2187. prin2!* "The image polynomial mod "; prin2!* get!-chosen!-prime w;
  2188. printstr ", made monic, is:";
  2189. printsf get!-image!-mod!-p w;
  2190. printstr "and factors of the primitive image mod this prime are:";
  2191. for each x in getv(modular!-info,best!-set!-pointer)
  2192. do printsf x;
  2193. if (fnum:=get!-f!-numvec w) and not !*overview then <<
  2194. printstr "The numeric images of each (square-free) factor of";
  2195. printstr "the leading coefficient of the polynomial are as";
  2196. prin2!* "follows (in order):";
  2197. prin2!* " ";
  2198. for i:=1:length cdr factored!-lc do <<
  2199. prin2!* getv(fnum,i); prin2!* "; " >>;
  2200. terpri!*(nil) >>
  2201. >>
  2202. end;
  2203. %**********************************************************************;
  2204. % multivariate factorization part 3. reconstruction of the
  2205. % chosen image over the integers;
  2206. symbolic procedure reconstruct!-image!-factors!-over!-integers();
  2207. % the hensel construction from modular case to univariate
  2208. % over the integers;
  2209. begin scalar best!-modulus,best!-factor!-count,input!-polynomial,
  2210. input!-leading!-coefficient,best!-known!-factors,s,w,i,
  2211. x!-is!-factor,x!-factor;
  2212. s:=getv(valid!-image!-sets,best!-set!-pointer);
  2213. best!-known!-factors:=getv(modular!-info,best!-set!-pointer);
  2214. best!-modulus:=get!-chosen!-prime s;
  2215. best!-factor!-count:=length best!-known!-factors;
  2216. input!-polynomial:=get!-image!-poly s;
  2217. if ldeg input!-polynomial=1 then
  2218. if not(x!-is!-factor:=not numberp get!-image!-content s) then
  2219. errorf list("Trying to factor a linear image poly: ",
  2220. input!-polynomial)
  2221. else begin scalar brecip,ww,om,x!-mod!-p;
  2222. number!-of!-factors:=2;
  2223. prime!-base:=best!-modulus;
  2224. x!-factor:=!*k2f m!-image!-variable;
  2225. putv(valid!-image!-sets,best!-set!-pointer,
  2226. put!-image!-poly!-and!-content(s,lc get!-image!-content s,
  2227. multf(x!-factor,get!-image!-poly s)));
  2228. om:=set!-modulus best!-modulus;
  2229. brecip:=modular!-reciprocal
  2230. red (ww:=reduce!-mod!-p input!-polynomial);
  2231. x!-mod!-p:=!*f2mod x!-factor;
  2232. alphalist:=list(
  2233. (x!-mod!-p . brecip),
  2234. (ww . modular!-minus modular!-times(brecip,lc ww)));
  2235. do!-quadratic!-growth(list(x!-factor,input!-polynomial),
  2236. list(x!-mod!-p,ww),best!-modulus);
  2237. w:=list input!-polynomial; % All factors apart from X-FACTOR;
  2238. set!-modulus om
  2239. end
  2240. else <<
  2241. input!-leading!-coefficient:=lc input!-polynomial;
  2242. factor!-trace <<
  2243. printstr
  2244. "Next we use the Hensel Construction to grow these modular";
  2245. printstr "factors into factors over the integers." >>;
  2246. w:=reconstruct!.over!.integers();
  2247. if irreducible then return t;
  2248. if (x!-is!-factor:=not numberp get!-image!-content s) then <<
  2249. number!-of!-factors:=length w + 1;
  2250. x!-factor:=!*k2f m!-image!-variable;
  2251. putv(valid!-image!-sets,best!-set!-pointer,
  2252. put!-image!-poly!-and!-content(s,lc get!-image!-content s,
  2253. multf(x!-factor,get!-image!-poly s)));
  2254. fix!-alphas() >>
  2255. else number!-of!-factors:=length w;
  2256. if number!-of!-factors=1 then return irreducible:=t >>;
  2257. if number!-of!-factors>target!-factor!-count then
  2258. return bad!-case:=list get!-image!-set s;
  2259. image!-factors:=mkvect number!-of!-factors;
  2260. i:=1;
  2261. factor!-trace
  2262. printstr "The full factors of the image polynomial are:";
  2263. for each im!-factor in w do <<
  2264. putv(image!-factors,i,im!-factor);
  2265. factor!-trace printsf im!-factor;
  2266. i:=iadd1 i >>;
  2267. if x!-is!-factor then <<
  2268. putv(image!-factors,i,x!-factor);
  2269. factor!-trace <<
  2270. printsf x!-factor;
  2271. printsf get!-image!-content
  2272. getv(valid!-image!-sets,best!-set!-pointer) >> >>
  2273. end;
  2274. symbolic procedure do!-quadratic!-growth(flist,modflist,p);
  2275. begin scalar fhatvec,alphavec,factorvec,modfvec,facvec,
  2276. current!-factor!-product,i,deltam,m;
  2277. fhatvec:=mkvect number!-of!-factors;
  2278. alphavec:=mkvect number!-of!-factors;
  2279. factorvec:=mkvect number!-of!-factors;
  2280. modfvec:=mkvect number!-of!-factors;
  2281. facvec:=mkvect number!-of!-factors;
  2282. current!-factor!-product:=1;
  2283. i:=0;
  2284. for each ff in flist do <<
  2285. putv(factorvec,i:=iadd1 i,ff);
  2286. current!-factor!-product:=multf(ff,current!-factor!-product) >>;
  2287. i:=0;
  2288. for each modff in modflist do <<
  2289. putv(modfvec,i:=iadd1 i,modff);
  2290. putv(alphavec,i,cdr get!-alpha modff) >>;
  2291. deltam:=p;
  2292. m:=deltam*deltam;
  2293. while m<largest!-small!-modulus do <<
  2294. quadratic!-step(m,number!-of!-factors);
  2295. m:=m*deltam >>;
  2296. hensel!-growth!-size:=deltam;
  2297. alphalist:=nil;
  2298. for j:=1:number!-of!-factors do
  2299. alphalist:=(reduce!-mod!-p getv(factorvec,j) . getv(alphavec,j))
  2300. . alphalist
  2301. end;
  2302. symbolic procedure fix!-alphas();
  2303. % we extracted a factor x (where x is the image variable)
  2304. % before any alphas were calculated, we now need to put
  2305. % back this factor and its coresponding alpha which incidently
  2306. % will change the other alphas;
  2307. begin scalar om,f1,x!-factor,a,arecip,b;
  2308. om:=set!-modulus hensel!-growth!-size;
  2309. f1:=reduce!-mod!-p input!-polynomial;
  2310. x!-factor:=!*f2mod !*k2f m!-image!-variable;
  2311. arecip:=modular!-reciprocal
  2312. (a:=evaluate!-mod!-p(f1,m!-image!-variable,0));
  2313. b:=times!-mod!-p(modular!-minus arecip,
  2314. quotfail!-mod!-p(difference!-mod!-p(f1,a),x!-factor));
  2315. alphalist:=(x!-factor . arecip) .
  2316. (for each aa in alphalist collect
  2317. ((car aa) . remainder!-mod!-p(times!-mod!-p(b,cdr aa),car aa)));
  2318. set!-modulus om
  2319. end;
  2320. %**********************************************************************;
  2321. % multivariate factorization part 4. determining the leading
  2322. % coefficients;
  2323. symbolic procedure determine!.leading!.coeffts();
  2324. % this function determines the leading coeffts to all but a constant
  2325. % factor which is spread over all of the factors before reconstruction;
  2326. begin scalar delta,c,s;
  2327. s:=getv(valid!-image!-sets,best!-set!-pointer);
  2328. delta:=get!-image!-content s;
  2329. % cont(the m!-input!-polynomial image);
  2330. if not domainp lc multivariate!-input!-poly then
  2331. << true!-leading!-coeffts:=
  2332. distribute!.lc(number!-of!-factors,image!-factors,s,
  2333. factored!-lc);
  2334. if bad!-case then <<
  2335. bad!-case:=list get!-image!-set s;
  2336. target!-factor!-count:=number!-of!-factors - 1;
  2337. if target!-factor!-count=1 then irreducible:=t;
  2338. return bad!-case >>;
  2339. delta:=car true!-leading!-coeffts;
  2340. true!-leading!-coeffts:=cdr true!-leading!-coeffts;
  2341. % if the lc problem exists then use wang's algorithm to
  2342. % distribute it over the factors. ;
  2343. if not !*overview then factor!-trace <<
  2344. printstr "We now determine the leading coefficients of the ";
  2345. printstr "factors of U by using the factors of the leading";
  2346. printstr "coefficient of U and their (square-free) images";
  2347. printstr "referred to earlier:";
  2348. for i:=1:number!-of!-factors do <<
  2349. prinsf getv(image!-factors,i);
  2350. prin2!* " with l.c.: ";
  2351. printsf getv(true!-leading!-coeffts,i)
  2352. >> >>;
  2353. if not onep delta then factor!-trace <<
  2354. if !*overview then
  2355. << printstr
  2356. "In determining the leading coefficients of the factors";
  2357. prin2!* "of U, " >>;
  2358. prin2!* "We have an integer factor, ";
  2359. prin2!* delta;
  2360. printstr ", left over that we ";
  2361. printstr "cannot yet distribute correctly." >>
  2362. >>
  2363. else <<
  2364. true!-leading!-coeffts:=mkvect number!-of!-factors;
  2365. for i:=1:number!-of!-factors do
  2366. putv(true!-leading!-coeffts,i,lc getv(image!-factors,i));
  2367. if not onep delta then
  2368. factor!-trace <<
  2369. prin2!* "U has a leading coefficient = ";
  2370. prin2!* delta;
  2371. printstr " which we cannot ";
  2372. printstr "yet distribute correctly over the image factors." >>
  2373. >>;
  2374. if not onep delta then
  2375. << for i:=1:number!-of!-factors do
  2376. << putv(image!-factors,i,multf(delta,getv(image!-factors,i)));
  2377. putv(true!-leading!-coeffts,i,
  2378. multf(delta,getv(true!-leading!-coeffts,i)))
  2379. >>;
  2380. divide!-all!-alphas delta;
  2381. c:=expt(delta,isub1 number!-of!-factors);
  2382. multivariate!-input!-poly:=multf(c,multivariate!-input!-poly);
  2383. non!-monic:=t;
  2384. factor!-trace <<
  2385. printstr "(a) We multiply each of the image factors by the ";
  2386. printstr "absolute value of this constant and multiply";
  2387. prin2!* "U by ";
  2388. if not(number!-of!-factors=2) then
  2389. << prin2!* delta; prin2!* "**";
  2390. prin2!* isub1 number!-of!-factors >>
  2391. else prin2!* delta;
  2392. printstr " giving new image factors";
  2393. printstr "as follows: ";
  2394. for i:=1:number!-of!-factors do
  2395. printsf getv(image!-factors,i)
  2396. >>
  2397. >>;
  2398. % if necessary, fiddle the remaining integer part of the
  2399. % lc of m!-input!-polynomial;
  2400. end;
  2401. %**********************************************************************;
  2402. % multivariate factorization part 5. reconstruction;
  2403. symbolic procedure reconstruct!-multivariate!-factors vset!-mod!-p;
  2404. % Hensel construction for multivariate case
  2405. % Full univariate split has already been prepared (if factoring);
  2406. % but we only need the modular factors and the true leading coeffts;
  2407. (lambda factor!-level; begin
  2408. scalar s,om,u0,alphavec,wtime,predictions,
  2409. best!-factors!-mod!-p,fhatvec,w1,fvec!-mod!-p,d,degree!-bounds,
  2410. lc!-vec;
  2411. alphavec:=mkvect number!-of!-factors;
  2412. best!-factors!-mod!-p:=mkvect number!-of!-factors;
  2413. lc!-vec := mkvect number!-of!-factors;
  2414. % This will preserve the LCs of the factors while we are working
  2415. % mod p since they may contain numbers that are bigger than the
  2416. % modulus.;
  2417. if not(
  2418. (d:=max!-degree(multivariate!-input!-poly,0)) < prime!-base) then
  2419. fvec!-mod!-p:=choose!-larger!-prime d;
  2420. om:=set!-modulus hensel!-growth!-size;
  2421. if null fvec!-mod!-p then <<
  2422. fvec!-mod!-p:=mkvect number!-of!-factors;
  2423. for i:=1:number!-of!-factors do
  2424. putv(fvec!-mod!-p,i,reduce!-mod!-p getv(image!-factors,i)) >>;
  2425. for i:=1:number!-of!-factors do <<
  2426. putv(alphavec,i,cdr get!-alpha getv(fvec!-mod!-p,i));
  2427. putv(best!-factors!-mod!-p,i,
  2428. reduce!-mod!-p getv(best!-known!-factors,i));
  2429. putv(lc!-vec,i,lc getv(best!-known!-factors,i)) >>;
  2430. % Set up the Alphas, input factors mod p and remember to save
  2431. % the LCs for use after finding the multivariate factors mod p;
  2432. if not reconstructing!-gcd then <<
  2433. s:=getv(valid!-image!-sets,best!-set!-pointer);
  2434. vset!-mod!-p:=for each v in get!-image!-set s collect
  2435. (car v . modular!-number cdr v) >>;
  2436. % princ "kord* =";% print kord!*;
  2437. % princ "order of variable substitution=";% print vset!-mod!-p;
  2438. u0:=reduce!-mod!-p multivariate!-input!-poly;
  2439. set!-degree!-bounds vset!-mod!-p;
  2440. wtime:=time();
  2441. factor!-trace <<
  2442. printstr
  2443. "We use the Hensel Construction to grow univariate modular";
  2444. printstr
  2445. "factors into multivariate modular factors, which will in";
  2446. printstr "turn be used in the later Hensel construction. The";
  2447. printstr "starting modular factors are:";
  2448. printvec(" f(",number!-of!-factors,")=",best!-factors!-mod!-p);
  2449. prin2!* "The modulus is "; printstr current!-modulus >>;
  2450. find!-multivariate!-factors!-mod!-p(u0,
  2451. best!-factors!-mod!-p,
  2452. vset!-mod!-p);
  2453. if bad!-case then <<
  2454. trace!-time <<
  2455. display!-time(" Multivariate modular factors failed in ",
  2456. time()-wtime);
  2457. wtime:=time() >>;
  2458. target!-factor!-count:=number!-of!-factors - 1;
  2459. if target!-factor!-count=1 then irreducible:=t;
  2460. set!-modulus om;
  2461. return bad!-case >>;
  2462. trace!-time <<
  2463. display!-time(" Multivariate modular factors found in ",
  2464. time()-wtime);
  2465. wtime:=time() >>;
  2466. fhatvec:=make!-multivariate!-hatvec!-mod!-p(best!-factors!-mod!-p,
  2467. number!-of!-factors);
  2468. for i:=1:number!-of!-factors do
  2469. putv(fvec!-mod!-p,i,getv(best!-factors!-mod!-p,i));
  2470. make!-vec!-modular!-symmetric(best!-factors!-mod!-p,
  2471. number!-of!-factors);
  2472. for i:=1:number!-of!-factors do <<
  2473. % w1:=getv(coefft!-vectors,i);
  2474. % putv(best!-known!-factors,i,
  2475. % merge!-terms(getv(best!-factors!-mod!-p,i),w1));
  2476. putv(best!-known!-factors,i,
  2477. force!-lc(getv(best!-factors!-mod!-p,i),getv(lc!-vec,i)));
  2478. % Now we put back the LCs before growing the multivariate
  2479. % factors to be correct over the integers giving the final
  2480. % result;
  2481. >>;
  2482. wtime:=time();
  2483. w1:=hensel!-mod!-p(
  2484. multivariate!-input!-poly,
  2485. fvec!-mod!-p,
  2486. best!-known!-factors,
  2487. get!.coefft!.bound(multivariate!-input!-poly,
  2488. total!-degree!-in!-powers(multivariate!-input!-poly,nil)),
  2489. vset!-mod!-p,
  2490. hensel!-growth!-size);
  2491. if car w1='overshot then <<
  2492. trace!-time <<
  2493. display!-time(" Full factors failed in ",time()-wtime);
  2494. wtime:=time() >>;
  2495. target!-factor!-count:=number!-of!-factors - 1;
  2496. if target!-factor!-count=1 then irreducible:=t;
  2497. set!-modulus om;
  2498. return bad!-case:=t >>;
  2499. if not(car w1='ok) then errorf w1;
  2500. trace!-time <<
  2501. display!-time(" Full factors found in ",time()-wtime);
  2502. wtime:=time() >>;
  2503. if reconstructing!-gcd then <<
  2504. full!-gcd:=if non!-monic then car primitive!.parts(
  2505. list getv(cdr w1,1),m!-image!-variable,nil)
  2506. else getv(cdr w1,1);
  2507. set!-modulus om;
  2508. return full!-gcd >>;
  2509. for i:=1:getv(cdr w1,0) do
  2510. multivariate!-factors:=getv(cdr w1,i) . multivariate!-factors;
  2511. if non!-monic then multivariate!-factors:=
  2512. primitive!.parts(multivariate!-factors,m!-image!-variable,nil);
  2513. factor!-trace <<
  2514. printstr "The full multivariate factors are:";
  2515. for each x in multivariate!-factors do printsf x >>;
  2516. set!-modulus om;
  2517. end) (factor!-level*100);
  2518. symbolic procedure check!-inverted multi!-faclist;
  2519. begin scalar inv!.sign,l;
  2520. if inverted then <<
  2521. inv!.sign:=1;
  2522. multi!-faclist:=
  2523. for each x in multi!-faclist collect <<
  2524. l:=invert!.poly(x,m!-image!-variable);
  2525. inv!.sign:=(car l) * inv!.sign;
  2526. cdr l >>;
  2527. if not(inv!.sign=inverted!-sign) then
  2528. errorf list("INVERSION HAS LOST A SIGN",inv!.sign) >>;
  2529. return multivariate!-factors:=multi!-faclist end;
  2530. endmodule;
  2531. module interfac;
  2532. % Authors: A. C. Norman and P. M. A. Moore, 1981.
  2533. % Modifications by: Anthony C. Hearn.
  2534. fluid '(m!-image!-variable
  2535. poly!-vector
  2536. polyzero
  2537. unknowns!-list
  2538. varlist);
  2539. %**********************************************************************;
  2540. %
  2541. % Routines that are specific to REDUCE.
  2542. % These are either routines that are not needed in the HASH system
  2543. % (which is the other algebra system that this factorizer
  2544. % can be plugged into) or routines that are specifically
  2545. % redefined in the HASH system. ;
  2546. %---------------------------------------------------------------------;
  2547. % The following would normally live in section: ALPHAS
  2548. %---------------------------------------------------------------------;
  2549. symbolic procedure assoc!-alpha(poly,alist); assoc(poly,alist);
  2550. %---------------------------------------------------------------------;
  2551. % The following would normally live in section: COEFFTS
  2552. %---------------------------------------------------------------------;
  2553. symbolic procedure termvector2sf v;
  2554. begin scalar r,w;
  2555. for i:=car getv(v,0) step -1 until 1 do <<
  2556. w:=getv(v,i);
  2557. % degree . coefft;
  2558. r:=if car w=0 then cdr w else
  2559. (mksp(m!-image!-variable,car w) .* cdr w) .+ r
  2560. >>;
  2561. return r
  2562. end;
  2563. symbolic procedure force!-lc(a,n);
  2564. % force polynomial a to have leading coefficient as specified;
  2565. (lpow a .* n) .+ red a;
  2566. symbolic procedure merge!-terms(u,v);
  2567. merge!-terms1(1,u,v,car getv(v,0));
  2568. symbolic procedure merge!-terms1(i,u,v,n);
  2569. if i#>n then u
  2570. else begin scalar a,b;
  2571. a:=getv(v,i);
  2572. if domainp u or not(mvar u=m!-image!-variable) then
  2573. if not(car a=0) then errorf list("MERGING COEFFTS FAILED",u,a)
  2574. else if cdr a then return cdr a
  2575. else return u;
  2576. b:=lt u;
  2577. if tdeg b=car a then return
  2578. (if cdr a then tpow b .* cdr a else b) .+
  2579. merge!-terms1(i #+ 1,red u,v,n)
  2580. else if tdeg b #> car a then return b .+ merge!-terms1(i,red u,v,n)
  2581. else errorf list("MERGING COEFFTS FAILED ",u,a)
  2582. end;
  2583. symbolic procedure list!-terms!-in!-factor u;
  2584. % ...;
  2585. if domainp u then list (0 . nil)
  2586. else (ldeg u . nil) . list!-terms!-in!-factor red u;
  2587. symbolic procedure try!-other!-coeffts(r,unknowns!-list,uv);
  2588. begin scalar ldeg!-r,lc!-r,w;
  2589. while not domainp r and (r:=red r) and not(w='complete) do <<
  2590. if not depends!-on!-var(r,m!-image!-variable) then
  2591. << ldeg!-r:=0; lc!-r:=r >>
  2592. else << ldeg!-r:=ldeg r; lc!-r:=lc r >>;
  2593. w:=solve!-next!-coefft(ldeg!-r,lc!-r,unknowns!-list,uv) >>
  2594. end;
  2595. %---------------------------------------------------------------------;
  2596. % The following would normally live in section: FACMISC
  2597. %---------------------------------------------------------------------;
  2598. symbolic procedure derivative!-wrt!-main!-variable(p,var);
  2599. % partial derivative of the polynomial p with respect to
  2600. % its main variable, var;
  2601. if domainp p or (mvar p neq var) then nil
  2602. else
  2603. begin
  2604. scalar degree;
  2605. degree:=ldeg p;
  2606. if degree=1 then return lc p; %degree one term is special;
  2607. return (mksp(mvar p,degree-1) .* multf(degree,lc p)) .+
  2608. derivative!-wrt!-main!-variable(red p,var)
  2609. end;
  2610. symbolic procedure fac!-univariatep u;
  2611. % tests to see if u is univariate;
  2612. domainp u or not multivariatep(u,mvar u);
  2613. symbolic procedure variables!.in!.form(a,sofar);
  2614. if domainp a then sofar
  2615. else <<
  2616. if not memq(mvar a,sofar) then
  2617. sofar:=mvar a . sofar;
  2618. variables!.in!.form(red a,
  2619. variables!.in!.form(lc a,sofar)) >>;
  2620. symbolic procedure degree!-in!-variable(p,v);
  2621. % returns the degree of the polynomial p in the
  2622. % variable v;
  2623. if domainp p then 0
  2624. else if lc p=0
  2625. then errorf "Polynomial with a zero coefficient found"
  2626. else if v=mvar p then ldeg p
  2627. else max(degree!-in!-variable(lc p,v),
  2628. degree!-in!-variable(red p,v));
  2629. symbolic procedure get!-height poly;
  2630. % find height (max coefft) of given poly;
  2631. if null poly then 0
  2632. else if numberp poly then abs poly
  2633. else max(get!-height lc poly,get!-height red poly);
  2634. symbolic procedure poly!-minusp a;
  2635. if a=nil then nil
  2636. else if domainp a then minusp a
  2637. else poly!-minusp lc a;
  2638. symbolic procedure poly!-abs a;
  2639. if poly!-minusp a then negf a
  2640. else a;
  2641. symbolic procedure fac!-printfactors l;
  2642. % procedure to print the result of factorize!-form;
  2643. % ie. l is of the form: (c . f)
  2644. % where c is the numeric content (may be 1)
  2645. % and f is of the form: ( (f1 . e1) (f2 . e2) ... (fn . en) )
  2646. % where the fi's are s.f.s and ei's are numbers;
  2647. << terpri();
  2648. if not (car l = 1) then printsf car l;
  2649. for each item in cdr l do
  2650. printsf !*p2f mksp(prepf car item,cdr item) >>;
  2651. %---------------------------------------------------------------------;
  2652. % The following would normally live in section: FACPRIM
  2653. %---------------------------------------------------------------------;
  2654. symbolic procedure invert!.poly(u,var);
  2655. % u is a non-trivial primitive square free multivariate polynomial.
  2656. % assuming var is the top-level variable in u, this effectively
  2657. % reverses the position of the coeffts: ie
  2658. % a(n)*var**n + a(n-1)*var**(n-1) + ... + a(0)
  2659. % becomes:
  2660. % a(0)*var**n + a(1)*var**(n-1) + ... + a(n) . ;
  2661. begin scalar w,invert!-sign;
  2662. w:=invert!.poly1(red u,ldeg u,lc u,var);
  2663. if poly!-minusp lc w then <<
  2664. w:=negf w;
  2665. invert!-sign:=-1 >>
  2666. else invert!-sign:=1;
  2667. return invert!-sign . w
  2668. end;
  2669. symbolic procedure invert!.poly1(u,d,v,var);
  2670. % d is the degree of the poly we wish to invert.
  2671. % assume d > ldeg u always, and that v is never nil;
  2672. if (domainp u) or not (mvar u=var) then
  2673. (var to d) .* u .+ v
  2674. else invert!.poly1(red u,d,(var to (d-ldeg u)) .* (lc u) .+ v,var);
  2675. symbolic procedure trailing!.coefft(u,var);
  2676. % u is multivariate poly with var as the top-level variable. we find
  2677. % the trailing coefft - ie the constant wrt var in u;
  2678. if domainp u then u
  2679. else if mvar u=var then trailing!.coefft(red u,var)
  2680. else u;
  2681. %---------------------------------------------------------------------;
  2682. % The following would normally live in section: IMAGESET
  2683. %---------------------------------------------------------------------;
  2684. symbolic procedure make!-image!-lc!-list(u,imset);
  2685. reversewoc make!-image!-lc!-list1(u,imset,
  2686. for each x in imset collect car x);
  2687. symbolic procedure make!-image!-lc!-list1(u,imset,varlist);
  2688. % If IMSET=((x1 . a1, x2 . a2, ... , xn . an)) (ordered) where xj is
  2689. % the variable and aj its value, then this fn creates n images of U wrt
  2690. % sets S(i) where S(i)= ((x1 . a1), ... , (xi . ai)). The result is an
  2691. % ordered list of pairs: (u(i) . X(i+1)) where u(i)= U wrt S(i) and
  2692. % X(i) = (xi, ... , xn) and X(n+1) = NIL. VARLIST = X(1).
  2693. % (Note. the variables tagged to u(i) should be all those
  2694. % appearing in u(i) unless it is degenerate). The returned list is
  2695. % ordered with u(1) first and ending with the number u(n);
  2696. if null imset then nil
  2697. else if domainp u then list(!*d2n u . cdr varlist)
  2698. else if mvar u=caar imset then
  2699. begin scalar w;
  2700. w:=horner!-rule!-for!-one!-var(
  2701. u,caar imset,cdar imset,polyzero,ldeg u) . cdr varlist;
  2702. return
  2703. if polyzerop car w then list (0 . cdr w)
  2704. else (w . make!-image!-lc!-list1(car w,cdr imset,cdr varlist))
  2705. end
  2706. else make!-image!-lc!-list1(u,cdr imset,cdr varlist);
  2707. symbolic procedure horner!-rule!-for!-one!-var(u,x,val,c,degg);
  2708. if domainp u or not(mvar u=x)
  2709. then if zerop val then u else addf(u,multf(c,!*num2f(val**degg)))
  2710. else begin scalar newdeg;
  2711. newdeg:=ldeg u;
  2712. return horner!-rule!-for!-one!-var(red u,x,val,
  2713. if zerop val then lc u
  2714. else addf(lc u,
  2715. multf(c,!*num2f(val**(idifference(degg,newdeg))))),
  2716. newdeg)
  2717. end;
  2718. symbolic procedure make!-image(u,imset);
  2719. % finds image of u wrt image set, imset, (=association list);
  2720. if domainp u then u
  2721. else if mvar u=m!-image!-variable then
  2722. adjoin!-term(lpow u,!*num2f evaluate!-in!-order(lc u,imset),
  2723. make!-image(red u,imset))
  2724. else !*num2f evaluate!-in!-order(u,imset);
  2725. symbolic procedure evaluate!-in!-order(u,imset);
  2726. % makes an image of u wrt imageset, imset, using horner's rule. result
  2727. % should be purely numeric;
  2728. if domainp u then !*d2n u
  2729. else if mvar u=caar imset then
  2730. horner!-rule(evaluate!-in!-order(lc u,cdr imset),
  2731. ldeg u,red u,imset)
  2732. else evaluate!-in!-order(u,cdr imset);
  2733. symbolic procedure horner!-rule(c,degg,a,vset);
  2734. % c is running total and a is what is left;
  2735. if domainp a
  2736. then if zerop cdar vset then !*d2n a
  2737. else (!*d2n a)+c*((cdar vset)**degg)
  2738. else if not(mvar a=caar vset)
  2739. then if zerop cdar vset then evaluate!-in!-order(a,cdr vset)
  2740. else evaluate!-in!-order(a,cdr vset)+c*((cdar vset)**degg)
  2741. else begin scalar newdeg;
  2742. newdeg:=ldeg a;
  2743. return horner!-rule(if zerop cdar vset
  2744. then evaluate!-in!-order(lc a,cdr vset)
  2745. else evaluate!-in!-order(lc a,cdr vset)
  2746. +c*((cdar vset)**(idifference(degg,newdeg))),newdeg,red a,vset)
  2747. end;
  2748. %---------------------------------------------------------------------;
  2749. % The following would normally live in section: MHENSFNS
  2750. %---------------------------------------------------------------------;
  2751. symbolic procedure max!-degree(u,n);
  2752. % finds maximum degree of any single variable in U (n is max so far);
  2753. if domainp u then n
  2754. else if igreaterp(n,ldeg u) then
  2755. max!-degree(red u,max!-degree(lc u,n))
  2756. else max!-degree(red u,max!-degree(lc u,ldeg u));
  2757. symbolic procedure diff!-over!-k!-mod!-p(u,k,v);
  2758. % derivative of u wrt v divided by k (=number);
  2759. if domainp u then nil
  2760. else if mvar u = v then
  2761. if ldeg u = 1 then quotient!-mod!-p(lc u,modular!-number k)
  2762. else adjoin!-term(mksp(v,isub1 ldeg u),
  2763. quotient!-mod!-p(
  2764. times!-mod!-p(modular!-number ldeg u,lc u),
  2765. modular!-number k),
  2766. diff!-over!-k!-mod!-p(red u,k,v))
  2767. else adjoin!-term(lpow u,
  2768. diff!-over!-k!-mod!-p(lc u,k,v),
  2769. diff!-over!-k!-mod!-p(red u,k,v));
  2770. symbolic procedure diff!-k!-times!-mod!-p(u,k,v);
  2771. % differentiates u k times wrt v and divides by (k!) ie. for each term
  2772. % a*v**n we get [n k]*a*v**(n-k) if n>=k and nil if n<k where
  2773. % [n k] is the binomial coefficient;
  2774. if domainp u then nil
  2775. else if mvar u = v then
  2776. if ldeg u < k then nil
  2777. else if ldeg u = k then lc u
  2778. else adjoin!-term(mksp(v,ldeg u - k),
  2779. times!-mod!-p(binomial!-coefft!-mod!-p(ldeg u,k),lc u),
  2780. diff!-k!-times!-mod!-p(red u,k,v))
  2781. else adjoin!-term(lpow u,
  2782. diff!-k!-times!-mod!-p(lc u,k,v),
  2783. diff!-k!-times!-mod!-p(red u,k,v));
  2784. symbolic procedure spreadvar(u,v,slist);
  2785. % find all the powers of V in U and merge their degrees into SLIST.
  2786. % We ignore the constant term wrt V;
  2787. if domainp u then slist
  2788. else <<
  2789. if mvar u=v and not member(ldeg u,slist) then slist:=ldeg u . slist;
  2790. spreadvar(red u,v,spreadvar(lc u,v,slist)) >>;
  2791. %---------------------------------------------------------------------;
  2792. % The following would normally live in section: UNIHENS
  2793. %---------------------------------------------------------------------;
  2794. symbolic procedure root!-squares(u,sofar);
  2795. if null u then pmam!-sqrt sofar
  2796. else if domainp u then pmam!-sqrt(sofar+(u*u))
  2797. else root!-squares(red u,sofar+(lc u * lc u));
  2798. %---------------------------------------------------------------------;
  2799. % The following would normally live in section: VECPOLY
  2800. %---------------------------------------------------------------------;
  2801. symbolic procedure poly!-to!-vector p;
  2802. % spread the given univariate polynomial out into POLY-VECTOR;
  2803. if isdomain p then putv(poly!-vector,0,!*d2n p)
  2804. else <<
  2805. putv(poly!-vector,ldeg p,lc p);
  2806. poly!-to!-vector red p >>;
  2807. symbolic procedure vector!-to!-poly(p,d,v);
  2808. % Convert the vector P into a polynomial of degree D in variable V;
  2809. begin
  2810. scalar r;
  2811. if d#<0 then return nil;
  2812. r:=!*n2f getv(p,0);
  2813. for i:=1:d do
  2814. if getv(p,i) neq 0 then r:=((v to i) .* getv(p,i)) .+ r;
  2815. return r
  2816. end;
  2817. endmodule;
  2818. module linmodp;
  2819. % Authors: A. C. Norman and P. M. A. Moore, 1979;
  2820. fluid '(current!-modulus prime!-base);
  2821. %**********************************************************************;
  2822. %
  2823. % This section solves linear equations mod p;
  2824. symbolic procedure lu!-factorize!-mod!-p(a,n);
  2825. % A is a matrix of size N*N. Overwrite it with its LU factorization;
  2826. begin scalar w;
  2827. for i:=1:n do begin
  2828. scalar ii,pivot;
  2829. ii:=i;
  2830. while n>=ii and ((pivot:=getm2(a,ii,i))=0
  2831. or iremainder(pivot,prime!-base)=0) do ii := ii+1;
  2832. if ii>n then return 'singular;
  2833. if not ii=i then begin
  2834. scalar temp;
  2835. temp:=getv(a,i);
  2836. putv(a,i,getv(a,ii));
  2837. putv(a,ii,temp) end;
  2838. putm2(a,i,0,ii); % Remember pivoting information;
  2839. pivot:=modular!-reciprocal pivot;
  2840. putm2(a,i,i,pivot);
  2841. for j:=i+1:n do
  2842. putm2(a,i,j,modular!-times(pivot,getm2(a,i,j)));
  2843. for ii:=i+1:n do begin
  2844. scalar multiple;
  2845. multiple:=getm2(a,ii,i);
  2846. for j:=i+1:n do
  2847. putm2(a,ii,j,modular!-difference(getm2(a,ii,j),
  2848. modular!-times(multiple,getm2(a,i,j)))) end end;
  2849. return w
  2850. end;
  2851. symbolic procedure back!-substitute(a,v,n);
  2852. % A is an N*N matrix as produced by LU-FACTORIZE-MOD-P, and V is
  2853. % a vector of length N. Overwrite V with solution to linear equations;
  2854. begin
  2855. for i:=1:n do
  2856. begin scalar ii;
  2857. ii:=getm2(a,i,0); % Pivot control;
  2858. if ii neq i
  2859. then begin scalar temp;
  2860. temp:=getv(v,i);
  2861. putv(v,i,getv(v,ii));
  2862. putv(v,ii,temp)
  2863. end
  2864. end;
  2865. for i:=1:n do begin
  2866. putv(v,i,times!-mod!-p(!*n2f getm2(a,i,i),getv(v,i)));
  2867. for ii:=i+1:n do
  2868. putv(v,ii,difference!-mod!-p(getv(v,ii),
  2869. times!-mod!-p(getv(v,i),!*n2f getm2(a,ii,i)))) end;
  2870. % Now do the actual back substitution;
  2871. for i:=n-1 step -1 until 1 do
  2872. for j:=i+1:n do
  2873. putv(v,i,difference!-mod!-p(getv(v,i),
  2874. times!-mod!-p(!*n2f getm2(a,i,j),getv(v,j))));
  2875. return v
  2876. end;
  2877. endmodule;
  2878. module mhensfns;
  2879. % Authors: A. C. Norman and P. M. A. Moore, 1979;
  2880. fluid '(!*trfac
  2881. alphalist
  2882. current!-modulus
  2883. degree!-bounds
  2884. delfvec
  2885. factor!-level
  2886. factor!-trace!-list
  2887. forbidden!-primes
  2888. hensel!-growth!-size
  2889. image!-factors
  2890. max!-unknowns
  2891. multivariate!-input!-poly
  2892. non!-monic
  2893. number!-of!-factors
  2894. number!-of!-unknowns
  2895. polyzero
  2896. prime!-base
  2897. pt);
  2898. %**********************************************************************;
  2899. % This section contains some of the functions used in
  2900. % the multivariate hensel growth. (ie they are called from
  2901. % section MULTIHEN or function RECONSTRUCT-MULTIVARIATE-FACTORS). ;
  2902. symbolic procedure set!-degree!-bounds v;
  2903. degree!-bounds:=for each var in v collect
  2904. (car var . degree!-in!-variable(multivariate!-input!-poly,car var));
  2905. symbolic procedure get!-degree!-bound v;
  2906. begin scalar w;
  2907. w:=atsoc(v,degree!-bounds);
  2908. if null w then errorf(list("Degree bound not found for ",
  2909. v," in ",degree!-bounds));
  2910. return cdr w
  2911. end;
  2912. symbolic procedure choose!-larger!-prime n;
  2913. % our prime base in the multivariate hensel must be greater than n so
  2914. % this sets a new prime to be that (previous one was found to be no
  2915. % good). We also set up various fluids e.g. the Alphas;
  2916. % the primes we can choose are < 2**24 so if n is bigger
  2917. % we collapse;
  2918. if n > 2**24-1 then
  2919. errorf list("CANNOT CHOOSE PRIME > GIVEN NUMBER:",n)
  2920. else begin scalar p,flist!-mod!-p,k,fvec!-mod!-p,forbidden!-primes;
  2921. trynewprime:
  2922. if p then forbidden!-primes:=p . forbidden!-primes;
  2923. p:=random!-prime();
  2924. % this chooses a word-size prime (currently 24 bits);
  2925. set!-modulus p;
  2926. if not(p>n) or member(p,forbidden!-primes) or
  2927. polyzerop reduce!-mod!-p lc multivariate!-input!-poly then
  2928. goto trynewprime;
  2929. for i:=1:number!-of!-factors do
  2930. flist!-mod!-p:=(reduce!-mod!-p getv(image!-factors,i) .
  2931. flist!-mod!-p);
  2932. alphalist:=alphas(number!-of!-factors,flist!-mod!-p,1);
  2933. if alphalist='factors! not! coprime then goto trynewprime;
  2934. hensel!-growth!-size:=p;
  2935. prime!-base:=p;
  2936. factor!-trace <<
  2937. prin2!* "New prime chosen: ";
  2938. printstr hensel!-growth!-size >>;
  2939. k:=number!-of!-factors;
  2940. fvec!-mod!-p:=mkvect k;
  2941. for each w in flist!-mod!-p do <<
  2942. putv(fvec!-mod!-p,k,w); k:=isub1 k >>;
  2943. return fvec!-mod!-p
  2944. end;
  2945. symbolic procedure binomial!-coefft!-mod!-p(n,r);
  2946. if n<r then nil
  2947. else if n=r then 1
  2948. else if r=1 then !*num2f modular!-number n
  2949. else begin scalar n!-c!-r,b,j;
  2950. n!-c!-r:=1;
  2951. b:=min(r,n-r);
  2952. n:=modular!-number n;
  2953. r:=modular!-number r;
  2954. for i:=1:b do <<
  2955. j:=modular!-number i;
  2956. n!-c!-r:=modular!-quotient(
  2957. modular!-times(n!-c!-r,
  2958. modular!-difference(n,modular!-difference(j,1))),
  2959. j) >>;
  2960. return !*num2f n!-c!-r
  2961. end;
  2962. symbolic procedure make!-multivariate!-hatvec!-mod!-p(bvec,n);
  2963. % makes a vector whose ith elt is product over j [ BVEC(j) ] / BVEC(i);
  2964. % NB. we must NOT actually do the division here as we are likely
  2965. % to be working mod p**n (some n > 1) and the division can involve
  2966. % a division by p.;
  2967. begin scalar bhatvec,r;
  2968. bhatvec:=mkvect n;
  2969. for i:=1:n do <<
  2970. r:=1;
  2971. for j:=1:n do if not(j=i) then r:=times!-mod!-p(r,getv(bvec,j));
  2972. putv(bhatvec,i,r) >>;
  2973. return bhatvec
  2974. end;
  2975. symbolic procedure max!-degree!-in!-var(fvec,v);
  2976. begin scalar r,d;
  2977. r:=0;
  2978. for i:=1:number!-of!-factors do
  2979. if r<(d:=degree!-in!-variable(getv(fvec,i),v)) then r:=d;
  2980. return r
  2981. end;
  2982. symbolic procedure make!-growth!-factor pt;
  2983. % pt is of form (v . n) where v is a variable. we make the s.f. v-n;
  2984. if cdr pt=0 then !*f2mod !*k2f car pt
  2985. else plus!-mod!-p(!*f2mod !*k2f car pt,modular!-minus cdr pt);
  2986. symbolic procedure terms!-done!-mod!-p(fvec,delfvec,delfactor);
  2987. % calculate the terms introduced by the corrections in DELFVEC;
  2988. begin scalar flist,delflist;
  2989. for i:=1:number!-of!-factors do <<
  2990. flist:=getv(fvec,i) . flist;
  2991. delflist:=getv(delfvec,i) . delflist >>;
  2992. return terms!-done1!-mod!-p(number!-of!-factors,flist,delflist,
  2993. number!-of!-factors,delfactor)
  2994. end;
  2995. symbolic procedure terms!-done1!-mod!-p(n,flist,delflist,r,m);
  2996. if n=1 then (car flist) . (car delflist)
  2997. else begin scalar k,i,f1,f2,delf1,delf2;
  2998. k:=n/2; i:=1;
  2999. for each f in flist do
  3000. << if i>k then f2:=(f . f2)
  3001. else f1:=(f . f1);
  3002. i:=i+1 >>;
  3003. i:=1;
  3004. for each delf in delflist do
  3005. << if i>k then delf2:=(delf . delf2)
  3006. else delf1:=(delf . delf1);
  3007. i:=i+1 >>;
  3008. f1:=terms!-done1!-mod!-p(k,f1,delf1,r,m);
  3009. delf1:=cdr f1; f1:=car f1;
  3010. f2:=terms!-done1!-mod!-p(n-k,f2,delf2,r,m);
  3011. delf2:=cdr f2; f2:=car f2;
  3012. delf1:=
  3013. plus!-mod!-p(plus!-mod!-p(
  3014. times!-mod!-p(f1,delf2),
  3015. times!-mod!-p(f2,delf1)),
  3016. times!-mod!-p(times!-mod!-p(delf1,m),delf2));
  3017. if n=r then return delf1;
  3018. return (times!-mod!-p(f1,f2) . delf1)
  3019. end;
  3020. symbolic procedure primitive!.parts(flist,var,univariate!-inputs);
  3021. % finds the prim.part of each factor in flist wrt variable var;
  3022. % Note that FLIST may contain univariate or multivariate S.F.s
  3023. % (according to UNIVARIATE!-INPUTS) - in the former case we correct the
  3024. % ALPHALIST if necessary;
  3025. begin scalar c,primf;
  3026. if null var then
  3027. errorf "Must take primitive parts wrt some non-null variable";
  3028. if non!-monic then
  3029. factor!-trace <<
  3030. printstr "Because we multiplied the original primitive";
  3031. printstr "polynomial by a multiple of its leading coefficient";
  3032. printstr "(see (a) above), the factors we have now are not";
  3033. printstr "necessarily primitive. However the required factors";
  3034. printstr "are merely their primitive parts." >>;
  3035. return for each fw in flist collect
  3036. << if not depends!-on!-var(fw,var) then
  3037. errorf list("WRONG VARIABLE",var,fw);
  3038. c:=comfac fw;
  3039. if car c then errorf(list(
  3040. "FACTOR DIVISIBLE BY MAIN VARIABLE:",fw,car c));
  3041. primf:=quotfail(fw,cdr c);
  3042. if not(cdr c=1) and univariate!-inputs then
  3043. multiply!-alphas(cdr c,fw,primf);
  3044. primf >>
  3045. end;
  3046. symbolic procedure make!-predicted!-forms(pfs,v);
  3047. % PFS is a vector of S.F.s which represents the sparsity of
  3048. % the associated polynomials wrt V. Here PFS is adjusted to a
  3049. % suitable form for handling this sparsity. ie. we record the
  3050. % degrees of V in a vector for each poly in PFS. Each
  3051. % monomial (in V) represents an unknown (its coefft) in the predicted
  3052. % form of the associated poly. We count the maximum no of unknowns for
  3053. % each poly and return the maximum of these;
  3054. begin scalar l,n,pvec,j,w;
  3055. max!-unknowns:=0;
  3056. for i:=1:number!-of!-factors do <<
  3057. w:=getv(pfs,i); % get the ith poly;
  3058. l:=sort(spreadvar(w,v,nil),function lessp);
  3059. % Pick out the monomials in V from this poly and order
  3060. % them in increasing degree;
  3061. n:=iadd1 length l; % no of unknowns in predicted poly - we add
  3062. % one for the constant term;
  3063. number!-of!-unknowns:=(n . i) . number!-of!-unknowns;
  3064. if max!-unknowns<n then max!-unknowns:=n;
  3065. pvec:=mkvect isub1 n;
  3066. % get space for the info on this poly;
  3067. j:=0;
  3068. putv(pvec,j,isub1 n);
  3069. % put in the length of this vector which will vary
  3070. % from poly to poly;
  3071. for each m in l do putv(pvec,j:=iadd1 j,m);
  3072. % put in the monomial info;
  3073. putv(pfs,i,pvec);
  3074. % overwrite the S.F. in PFS with the more compact vector;
  3075. >>;
  3076. number!-of!-unknowns:=sort(number!-of!-unknowns,function lesspcar);
  3077. return max!-unknowns
  3078. end;
  3079. symbolic procedure make!-correction!-vectors(bfs,n);
  3080. % set up space for the vector of vectors to hold the correction
  3081. % terms as we generate them by the function SOLVE-FOR-CORRECTIONS.
  3082. % Also put in the starting values;
  3083. begin scalar cvs,cv;
  3084. cvs:=mkvect number!-of!-factors;
  3085. for i:=1:number!-of!-factors do <<
  3086. cv:=mkvect n;
  3087. % each CV will hold the corrections for the ith factor;
  3088. % the no of corrections we put in here depends on the
  3089. % maximum no of unknowns we have in the predicted
  3090. % forms, giving a set of soluble linear systems (hopefully);
  3091. putv(cv,1,getv(bfs,i));
  3092. % put in the first 'corrections';
  3093. putv(cvs,i,cv) >>;
  3094. return cvs
  3095. end;
  3096. symbolic procedure construct!-soln!-matrices(pfs,val);
  3097. % Here we construct the matrices - one for each linear system
  3098. % we will have to solve to see if our predicted forms of the
  3099. % answer are correct. Each matrix is a vector of row-vectors
  3100. % - the ijth elt is in jth slot of ith row-vector (ie zero slots
  3101. % are not used here);
  3102. begin scalar soln!-matrix,resvec,n,pv;
  3103. resvec:=mkvect number!-of!-factors;
  3104. for i:=1:number!-of!-factors do <<
  3105. pv:=getv(pfs,i);
  3106. soln!-matrix:=mkvect(n:=iadd1 getv(pv,0));
  3107. construct!-ith!-matrix(soln!-matrix,pv,n,val);
  3108. putv(resvec,i,soln!-matrix) >>;
  3109. return resvec
  3110. end;
  3111. symbolic procedure construct!-ith!-matrix(sm,pv,n,val);
  3112. begin scalar mv;
  3113. mv:=mkvect n; % this will be the first row;
  3114. putv(mv,1,1); % the first column represents the constant term;
  3115. for j:=2:n do putv(mv,j,modular!-expt(val,getv(pv,isub1 j)));
  3116. % first row is straight substitution;
  3117. putv(sm,1,mv);
  3118. % now for the rest of the rows: ;
  3119. for j:=2:n do <<
  3120. mv:=mkvect n;
  3121. putv(mv,1,0);
  3122. construct!-matrix!-row(mv,isub1 j,pv,n,val);
  3123. putv(sm,j,mv) >>
  3124. end;
  3125. symbolic procedure construct!-matrix!-row(mrow,j,pv,n,val);
  3126. begin scalar d;
  3127. for k:=2:n do <<
  3128. d:=getv(pv,isub1 k); % degree representing the monomial;
  3129. if d<j then putv(mrow,k,0)
  3130. else <<
  3131. d:=modular!-times(!*d2n binomial!-coefft!-mod!-p(d,j),
  3132. modular!-expt(val,idifference(d,j)));
  3133. % differentiate and substitute all at once;
  3134. putv(mrow,k,d) >> >>
  3135. end;
  3136. symbolic procedure print!-linear!-systems(soln!-m,correction!-v,
  3137. predicted!-f,v);
  3138. <<
  3139. for i:=1:number!-of!-factors do
  3140. print!-linear!-system(i,soln!-m,correction!-v,predicted!-f,v);
  3141. terpri!*(nil) >>;
  3142. symbolic procedure print!-linear!-system(i,soln!-m,correction!-v,
  3143. predicted!-f,v);
  3144. begin scalar pv,sm,cv,mr,n,tt;
  3145. terpri!*(t);
  3146. prin2!* " i = "; printstr i;
  3147. terpri!*(nil);
  3148. sm:=getv(soln!-m,i);
  3149. cv:=getv(correction!-v,i);
  3150. pv:=getv(predicted!-f,i);
  3151. n:=iadd1 getv(pv,0);
  3152. for j:=1:n do << % for each row in matrix ... ;
  3153. prin2!* "( ";
  3154. tt:=2;
  3155. mr:=getv(sm,j); % matrix row;
  3156. for k:=1:n do << % for each elt in row ... ;
  3157. prin2!* getv(mr,k);
  3158. ttab!* (tt:=tt+10) >>;
  3159. prin2!* ") ( [";
  3160. if j=1 then prin2!* 1
  3161. else prinsf adjoin!-term(mksp(v,getv(pv,isub1 j)),1,polyzero);
  3162. prin2!* "]";
  3163. ttab!* (tt:=tt+10);
  3164. prin2!* " )";
  3165. if j=(n/2) then prin2!* " = ( " else prin2!* " ( ";
  3166. prinsf getv(cv,j);
  3167. ttab!* (tt:=tt+30); printstr ")";
  3168. if not(j=n) then <<
  3169. tt:=2;
  3170. prin2!* "(";
  3171. ttab!* (tt:=tt+n*10);
  3172. prin2!* ") (";
  3173. ttab!* (tt:=tt+10);
  3174. prin2!* " ) (";
  3175. ttab!* (tt:=tt+30);
  3176. printstr ")" >> >>;
  3177. terpri!*(t)
  3178. end;
  3179. symbolic procedure try!-prediction(sm,cv,pv,n,i,poly,v,ff,ffhat);
  3180. begin scalar w,ffi,fhati;
  3181. sm:=getv(sm,i);
  3182. cv:=getv(cv,i);
  3183. pv:=getv(pv,i);
  3184. if not(n=iadd1 getv(pv,0)) then
  3185. errorf list("Predicted unknowns gone wrong? ",n,iadd1 getv(pv,0));
  3186. if null getm2(sm,1,0) then <<
  3187. w:=lu!-factorize!-mod!-p(sm,n);
  3188. if w='singular then <<
  3189. factor!-trace <<
  3190. prin2!* "Prediction for ";
  3191. prin2!* if null ff then 'f else 'a;
  3192. prin2!* "("; prin2!* i;
  3193. printstr ") failed due to singular matrix." >>;
  3194. return (w . i) >> >>;
  3195. back!-substitute(sm,cv,n);
  3196. w:=
  3197. if null ff then try!-factor(poly,cv,pv,n,v)
  3198. else <<
  3199. ffi := getv(ff,i);
  3200. fhati := getv(ffhat,i); % The unfolding here is to get round
  3201. % a bug in the PSL compiler 12/9/82. It
  3202. % will be tidied back up as soon as
  3203. % possible;
  3204. try!-alpha(poly,cv,pv,n,v,ffi,fhati) >>;
  3205. if w='bad!-prediction then <<
  3206. factor!-trace <<
  3207. prin2!* "Prediction for ";
  3208. prin2!* if null ff then 'f else 'a;
  3209. prin2!* "("; prin2!* i;
  3210. printstr ") was an inadequate guess." >>;
  3211. return (w . i) >>;
  3212. factor!-trace <<
  3213. prin2!* "Prediction for ";
  3214. prin2!* if null ff then 'f else 'a;
  3215. prin2!* "("; prin2!* i; prin2!* ") worked: ";
  3216. printsf car w >>;
  3217. return (i . w)
  3218. end;
  3219. symbolic procedure try!-factor(poly,testv,predictedf,n,v);
  3220. begin scalar r,w;
  3221. r:=getv(testv,1);
  3222. for j:=2:n do <<
  3223. w:=!*f2mod adjoin!-term(mksp(v,getv(predictedf,isub1 j)),1,
  3224. polyzero);
  3225. r:=plus!-mod!-p(r,times!-mod!-p(w,getv(testv,j))) >>;
  3226. w:=quotient!-mod!-p(poly,r);
  3227. if didntgo w or
  3228. not polyzerop difference!-mod!-p(poly,times!-mod!-p(w,r)) then
  3229. return 'bad!-prediction
  3230. else return list(r,w)
  3231. end;
  3232. symbolic procedure try!-alpha(poly,testv,predictedf,n,v,fi,fhati);
  3233. begin scalar r,w,wr;
  3234. r:=getv(testv,1);
  3235. for j:=2:n do <<
  3236. w:=!*f2mod adjoin!-term(mksp(v,getv(predictedf,isub1 j)),1,
  3237. polyzero);
  3238. r:=plus!-mod!-p(r,times!-mod!-p(w,getv(testv,j))) >>;
  3239. if polyzerop
  3240. (wr:=difference!-mod!-p(poly,times!-mod!-p(r,fhati))) then
  3241. return list (r,wr);
  3242. w:=quotient!-mod!-p(wr,fi);
  3243. if didntgo w or
  3244. not polyzerop difference!-mod!-p(wr,times!-mod!-p(w,fi)) then
  3245. return 'bad!-prediction
  3246. else return list(r,wr)
  3247. end;
  3248. endmodule;
  3249. module modpoly;
  3250. % Authors: A. C. Norman and P. M. A. Moore, 1979;
  3251. fluid '(current!-modulus
  3252. exact!-quotient!-flag
  3253. m!-image!-variable
  3254. modulus!/2
  3255. reduction!-count);
  3256. %**********************************************************************;
  3257. % routines for performing arithmetic on multivariate
  3258. % polynomials with coefficients that are modular
  3259. % numbers as defined by modular!-plus etc;
  3260. % note that the datastructure used is the same as that used in
  3261. % REDUCE except that it is assumed that domain elements are atomic;
  3262. symbolic procedure plus!-mod!-p(a,b);
  3263. % form the sum of the two polynomials a and b
  3264. % working over the ground domain defined by the routines
  3265. % modular!-plus, modular!-times etc. the inputs to this
  3266. % routine are assumed to have coefficients already
  3267. % in the required domain;
  3268. if null a then b
  3269. else if null b then a
  3270. else if isdomain a then
  3271. if isdomain b then !*num2f modular!-plus(a,b)
  3272. else (lt b) .+ plus!-mod!-p(a,red b)
  3273. else if isdomain b then (lt a) .+ plus!-mod!-p(red a,b)
  3274. else if lpow a = lpow b then
  3275. adjoin!-term(lpow a,
  3276. plus!-mod!-p(lc a,lc b),plus!-mod!-p(red a,red b))
  3277. else if comes!-before(lpow a,lpow b) then
  3278. (lt a) .+ plus!-mod!-p(red a,b)
  3279. else (lt b) .+ plus!-mod!-p(a,red b);
  3280. symbolic procedure times!-mod!-p(a,b);
  3281. if (null a) or (null b) then nil
  3282. else if isdomain a then multiply!-by!-constant!-mod!-p(b,a)
  3283. else if isdomain b then multiply!-by!-constant!-mod!-p(a,b)
  3284. else if mvar a=mvar b then plus!-mod!-p(
  3285. plus!-mod!-p(times!-term!-mod!-p(lt a,b),
  3286. times!-term!-mod!-p(lt b,red a)),
  3287. times!-mod!-p(red a,red b))
  3288. else if ordop(mvar a,mvar b) then
  3289. adjoin!-term(lpow a,times!-mod!-p(lc a,b),times!-mod!-p(red a,b))
  3290. else adjoin!-term(lpow b,
  3291. times!-mod!-p(a,lc b),times!-mod!-p(a,red b));
  3292. symbolic procedure times!-term!-mod!-p(term,b);
  3293. %multiply the given polynomial by the given term;
  3294. if null b then nil
  3295. else if isdomain b then
  3296. adjoin!-term(tpow term,
  3297. multiply!-by!-constant!-mod!-p(tc term,b),nil)
  3298. else if tvar term=mvar b then
  3299. adjoin!-term(mksp(tvar term,iplus(tdeg term,ldeg b)),
  3300. times!-mod!-p(tc term,lc b),
  3301. times!-term!-mod!-p(term,red b))
  3302. else if ordop(tvar term,mvar b) then
  3303. adjoin!-term(tpow term,times!-mod!-p(tc term,b),nil)
  3304. else adjoin!-term(lpow b,
  3305. times!-term!-mod!-p(term,lc b),
  3306. times!-term!-mod!-p(term,red b));
  3307. symbolic procedure difference!-mod!-p(a,b);
  3308. plus!-mod!-p(a,minus!-mod!-p b);
  3309. symbolic procedure minus!-mod!-p a;
  3310. if null a then nil
  3311. else if isdomain a then modular!-minus a
  3312. else (lpow a .* minus!-mod!-p lc a) .+ minus!-mod!-p red a;
  3313. symbolic procedure reduce!-mod!-p a;
  3314. %converts a multivariate poly from normal into modular polynomial;
  3315. if null a then nil
  3316. else if isdomain a then !*num2f modular!-number a
  3317. else adjoin!-term(lpow a,reduce!-mod!-p lc a,reduce!-mod!-p red a);
  3318. symbolic procedure monic!-mod!-p a;
  3319. % This procedure can only cope with polys that have a numeric
  3320. % leading coeff;
  3321. if a=nil then nil
  3322. else if isdomain a then 1
  3323. else if lc a = 1 then a
  3324. else if not domainp lc a then
  3325. errorf "LC NOT NUMERIC IN MONIC-MOD-P"
  3326. else multiply!-by!-constant!-mod!-p(a,
  3327. modular!-reciprocal lc a);
  3328. symbolic procedure quotfail!-mod!-p(a,b);
  3329. % Form quotient A/B, but complain if the division is
  3330. % not exact;
  3331. begin
  3332. scalar c;
  3333. exact!-quotient!-flag:=t;
  3334. c:=quotient!-mod!-p(a,b);
  3335. if exact!-quotient!-flag then return c
  3336. else errorf "QUOTIENT NOT EXACT (MOD P)"
  3337. end;
  3338. symbolic procedure quotient!-mod!-p(a,b);
  3339. % truncated quotient of a by b;
  3340. if null b then errorf "B=0 IN QUOTIENT-MOD-P"
  3341. else if isdomain b then multiply!-by!-constant!-mod!-p(a,
  3342. modular!-reciprocal b)
  3343. else if a=nil then nil
  3344. else if isdomain a then exact!-quotient!-flag:=nil
  3345. else if mvar a=mvar b then xquotient!-mod!-p(a,b,mvar b)
  3346. else if ordop(mvar a,mvar b) then
  3347. adjoin!-term(lpow a,
  3348. quotient!-mod!-p(lc a,b),
  3349. quotient!-mod!-p(red a,b))
  3350. else exact!-quotient!-flag:=nil;
  3351. symbolic procedure xquotient!-mod!-p(a,b,v);
  3352. % truncated quotient a/b given that b is nontrivial;
  3353. if a=nil then nil
  3354. else if (isdomain a) or (not mvar a=v) or
  3355. ilessp(ldeg a,ldeg b) then exact!-quotient!-flag:=nil
  3356. else if ldeg a = ldeg b then begin scalar w;
  3357. w:=quotient!-mod!-p(lc a,lc b);
  3358. if difference!-mod!-p(a,times!-mod!-p(w,b)) then
  3359. exact!-quotient!-flag:=nil;
  3360. return w
  3361. end
  3362. else begin scalar term;
  3363. term:=mksp(mvar a,idifference(ldeg a,ldeg b)) .*
  3364. quotient!-mod!-p(lc a,lc b);
  3365. %that is the leading term of the quotient. now subtract
  3366. %term*b from a;
  3367. a:=plus!-mod!-p(red a,
  3368. times!-term!-mod!-p(negate!-term term,red b));
  3369. % or a:=a-b*term given leading terms must cancel;
  3370. return term .+ xquotient!-mod!-p(a,b,v)
  3371. end;
  3372. symbolic procedure negate!-term term;
  3373. % negate a term;
  3374. tpow term .* minus!-mod!-p tc term;
  3375. symbolic procedure remainder!-mod!-p(a,b);
  3376. % remainder when a is divided by b;
  3377. if null b then errorf "B=0 IN REMAINDER-MOD-P"
  3378. else if isdomain b then nil
  3379. else if isdomain a then a
  3380. else xremainder!-mod!-p(a,b,mvar b);
  3381. symbolic procedure xremainder!-mod!-p(a,b,v);
  3382. % remainder when the modular polynomial a is
  3383. % divided by b, given that b is non degenerate;
  3384. if (isdomain a) or (not mvar a=v) or ilessp(ldeg a,ldeg b) then a
  3385. else begin
  3386. scalar q,w;
  3387. q:=quotient!-mod!-p(minus!-mod!-p lc a,lc b);
  3388. % compute -lc of quotient;
  3389. w:=idifference(ldeg a,ldeg b); %ldeg of quotient;
  3390. if w=0 then a:=plus!-mod!-p(red a,
  3391. multiply!-by!-constant!-mod!-p(red b,q))
  3392. else
  3393. a:=plus!-mod!-p(red a,times!-term!-mod!-p(
  3394. mksp(mvar b,w) .* q,red b));
  3395. % the above lines of code use red a and red b because
  3396. % by construction the leading terms of the required
  3397. % answers will cancel out;
  3398. return xremainder!-mod!-p(a,b,v)
  3399. end;
  3400. symbolic procedure multiply!-by!-constant!-mod!-p(a,n);
  3401. % multiply the polynomial a by the constant n;
  3402. if null a then nil
  3403. else if n=1 then a
  3404. else if isdomain a then !*num2f modular!-times(a,n)
  3405. else adjoin!-term(lpow a,multiply!-by!-constant!-mod!-p(lc a,n),
  3406. multiply!-by!-constant!-mod!-p(red a,n));
  3407. symbolic procedure gcd!-mod!-p(a,b);
  3408. % return the monic gcd of the two modular univariate
  3409. % polynomials a and b. Set REDUCTION-COUNT to the number
  3410. % of steps taken in the process;
  3411. << reduction!-count := 0;
  3412. if null a then monic!-mod!-p b
  3413. else if null b then monic!-mod!-p a
  3414. else if isdomain a then 1
  3415. else if isdomain b then 1
  3416. else if igreaterp(ldeg a,ldeg b) then
  3417. ordered!-gcd!-mod!-p(a,b)
  3418. else ordered!-gcd!-mod!-p(b,a) >>;
  3419. symbolic procedure ordered!-gcd!-mod!-p(a,b);
  3420. % as above, but deg a > deg b;
  3421. begin
  3422. scalar steps;
  3423. steps := 0;
  3424. top:
  3425. a := reduce!-degree!-mod!-p(a,b);
  3426. if null a then return monic!-mod!-p b;
  3427. steps := steps + 1;
  3428. if domainp a then <<
  3429. reduction!-count := reduction!-count+steps;
  3430. return 1 >>
  3431. else if ldeg a<ldeg b then begin
  3432. scalar w;
  3433. reduction!-count := reduction!-count + steps;
  3434. steps := 0;
  3435. w := a; a := b; b := w
  3436. end;
  3437. go to top
  3438. end;
  3439. symbolic procedure reduce!-degree!-mod!-p(a,b);
  3440. % Compute A-Q*B where Q is a single term chosen so that the result
  3441. % has lower degree than A did;
  3442. begin
  3443. scalar q,w;
  3444. q:=modular!-quotient(modular!-minus lc a,lc b);
  3445. % compute -lc of quotient;
  3446. w:=idifference(ldeg a,ldeg b); %ldeg of quotient;
  3447. % the next lines of code use red a and red b because
  3448. % by construction the leading terms of the required
  3449. % answers will cancel out;
  3450. if w=0 then return plus!-mod!-p(red a,
  3451. multiply!-by!-constant!-mod!-p(red b,q))
  3452. else
  3453. return plus!-mod!-p(red a,times!-term!-mod!-p(
  3454. mksp(mvar b,w) .* q,red b))
  3455. end;
  3456. symbolic procedure derivative!-mod!-p a;
  3457. % derivative of a wrt its main variable;
  3458. if isdomain a then nil
  3459. else if ldeg a=1 then lc a
  3460. else derivative!-mod!-p!-1(a,mvar a);
  3461. symbolic procedure derivative!-mod!-p!-1(a,v);
  3462. if isdomain a then nil
  3463. else if not mvar a=v then nil
  3464. else if ldeg a=1 then lc a
  3465. else adjoin!-term(mksp(v,isub1 ldeg a),
  3466. multiply!-by!-constant!-mod!-p(lc a,
  3467. modular!-number ldeg a),
  3468. derivative!-mod!-p!-1(red a,v));
  3469. symbolic procedure square!-free!-mod!-p a;
  3470. % predicate that tests if a is square-free as a modular
  3471. % univariate polynomial;
  3472. if isdomain a then t
  3473. else isdomain gcd!-mod!-p(a,derivative!-mod!-p a);
  3474. symbolic procedure evaluate!-mod!-p(a,v,n);
  3475. % evaluate polynomial A at the point V=N;
  3476. if isdomain a then a
  3477. else if n=0 then evaluate!-mod!-p(a,v,nil)
  3478. else if v=nil then errorf "Variable=NIL in EVALUATE-MOD-P"
  3479. else if mvar a=v then horner!-rule!-mod!-p(lc a,ldeg a,red a,n,v)
  3480. else adjoin!-term(lpow a,
  3481. evaluate!-mod!-p(lc a,v,n),
  3482. evaluate!-mod!-p(red a,v,n));
  3483. symbolic procedure horner!-rule!-mod!-p(v,degg,a,n,var);
  3484. % v is the running total, and it must be multiplied by
  3485. % n**deg and added to the value of a at n;
  3486. if isdomain a or not mvar a=var
  3487. then if null n or zerop n then a
  3488. else <<v:=times!-mod!-p(v,expt!-mod!-p(n,degg));
  3489. plus!-mod!-p(a,v)>>
  3490. else begin
  3491. scalar newdeg;
  3492. newdeg:=ldeg a;
  3493. return horner!-rule!-mod!-p(if null n or zerop n then lc a
  3494. else plus!-mod!-p(lc a,
  3495. times!-mod!-p(v,expt!-mod!-p(n,idifference(degg,newdeg)))),
  3496. newdeg,red a,n,var)
  3497. end;
  3498. symbolic procedure expt!-mod!-p(a,n);
  3499. % a**n;
  3500. if n=0 then 1
  3501. else if n=1 then a
  3502. else begin
  3503. scalar w,x;
  3504. w:=divide(n,2);
  3505. x:=expt!-mod!-p(a,car w);
  3506. x:=times!-mod!-p(x,x);
  3507. if not (cdr w = 0) then x:=times!-mod!-p(x,a);
  3508. return x
  3509. end;
  3510. symbolic procedure make!-bivariate!-mod!-p(u,imset,v);
  3511. % Substitute into U for all variables in IMSET which should result in
  3512. % a bivariate poly. One variable is M-IMAGE-VARIABLE and V is the other
  3513. % U is modular multivariate with these two variables at top 2 levels
  3514. % - V at 2nd level;
  3515. if domainp u then u
  3516. else if mvar u = m!-image!-variable then
  3517. adjoin!-term(lpow u,make!-univariate!-mod!-p(lc u,imset,v),
  3518. make!-bivariate!-mod!-p(red u,imset,v))
  3519. else make!-univariate!-mod!-p(u,imset,v);
  3520. symbolic procedure make!-univariate!-mod!-p(u,imset,v);
  3521. % Substitute into U for all variables in IMSET giving a univariate
  3522. % poly in V. U is modular multivariate with V at top level;
  3523. if domainp u then u
  3524. else if mvar u = v then
  3525. adjoin!-term(lpow u,!*num2f evaluate!-in!-order!-mod!-p(lc u,imset),
  3526. make!-univariate!-mod!-p(red u,imset,v))
  3527. else !*num2f evaluate!-in!-order!-mod!-p(u,imset);
  3528. symbolic procedure evaluate!-in!-order!-mod!-p(u,imset);
  3529. % makes an image of u wrt imageset, imset, using horner's rule. result
  3530. % should be purely numeric (and modular);
  3531. if domainp u then !*d2n u
  3532. else if mvar u=caar imset then
  3533. horner!-rule!-in!-order!-mod!-p(
  3534. evaluate!-in!-order!-mod!-p(lc u,cdr imset),ldeg u,red u,imset)
  3535. else evaluate!-in!-order!-mod!-p(u,cdr imset);
  3536. symbolic procedure horner!-rule!-in!-order!-mod!-p(c,degg,a,vset);
  3537. % c is running total and a is what is left;
  3538. if domainp a then modular!-plus(!*d2n a,
  3539. modular!-times(c,modular!-expt(cdar vset,degg)))
  3540. else if not(mvar a=caar vset) then
  3541. modular!-plus(
  3542. evaluate!-in!-order!-mod!-p(a,cdr vset),
  3543. modular!-times(c,modular!-expt(cdar vset,degg)))
  3544. else begin scalar newdeg;
  3545. newdeg:=ldeg a;
  3546. return horner!-rule!-in!-order!-mod!-p(
  3547. modular!-plus(
  3548. evaluate!-in!-order!-mod!-p(lc a,cdr vset),
  3549. modular!-times(c,
  3550. modular!-expt(cdar vset,(idifference(degg,newdeg))))),
  3551. newdeg,red a,vset)
  3552. end;
  3553. symbolic procedure make!-modular!-symmetric a;
  3554. % input is a multivariate MODULAR poly A with nos in the range 0->(p-1).
  3555. % This folds it onto the symmetric range (-p/2)->(p/2);
  3556. if null a then nil
  3557. else if domainp a then
  3558. if a>modulus!/2 then !*num2f(a - current!-modulus)
  3559. else a
  3560. else adjoin!-term(lpow a,make!-modular!-symmetric lc a,
  3561. make!-modular!-symmetric red a);
  3562. endmodule;
  3563. module multihen;
  3564. % Authors: A. C. Norman and P. M. A. Moore, 1979.
  3565. fluid '(!*overshoot
  3566. !*trfac
  3567. alphavec
  3568. bad!-case
  3569. factor!-level
  3570. factor!-trace!-list
  3571. fhatvec
  3572. hensel!-growth!-size
  3573. max!-unknowns
  3574. number!-of!-factors
  3575. number!-of!-unknowns
  3576. predictions
  3577. residue);
  3578. %**********************************************************************;
  3579. % hensel construction for the multivariate case
  3580. % (this version is highly recursive);
  3581. symbolic procedure find!-multivariate!-factors!-mod!-p(poly,
  3582. best!-factors,variable!-set);
  3583. % All arithmetic is done mod p, best-factors is overwritten;
  3584. if null variable!-set then best!-factors
  3585. else (lambda factor!-level; begin
  3586. scalar growth!-factor,b0s,res,correction!-factor,v,
  3587. bhat0s,w,degbd,first!-time,redpoly,
  3588. predicted!-forms,number!-of!-unknowns,solve!-count,
  3589. correction!-vectors,soln!-matrices,max!-unknowns,
  3590. unknowns!-count!-list,test!-prediction,poly!-remaining,
  3591. prediction!-results,one!-prediction!-failed;
  3592. v:=car variable!-set;
  3593. degbd:=get!-degree!-bound car v;
  3594. first!-time:=t;
  3595. growth!-factor:=make!-growth!-factor v;
  3596. poly!-remaining:=poly;
  3597. prediction!-results:=mkvect number!-of!-factors;
  3598. find!-msg1(best!-factors,growth!-factor,poly);
  3599. b0s:=reduce!-vec!-by!-one!-var!-mod!-p(best!-factors,
  3600. v,number!-of!-factors);
  3601. % The above made a copy of the vector;
  3602. for i:=1:number!-of!-factors do
  3603. putv(best!-factors,i,
  3604. difference!-mod!-p(getv(best!-factors,i),getv(b0s,i)));
  3605. redpoly:=evaluate!-mod!-p(poly,car v,cdr v);
  3606. find!-msg2(v,variable!-set);
  3607. find!-multivariate!-factors!-mod!-p(redpoly,b0s,cdr variable!-set);
  3608. % answers in b0s;
  3609. if bad!-case then return;
  3610. for i:=1:number!-of!-factors do
  3611. putv(best!-factors,i,
  3612. plus!-mod!-p(getv(b0s,i),getv(best!-factors,i)));
  3613. find!-msg3(best!-factors,v);
  3614. res:=diff!-over!-k!-mod!-p(
  3615. difference!-mod!-p(poly,
  3616. times!-vector!-mod!-p(best!-factors,number!-of!-factors)),
  3617. 1,car v);
  3618. % RES is the residue and must eventually be reduced to zero;
  3619. factor!-trace << printsf res; terpri!*(nil) >>;
  3620. if not polyzerop res and
  3621. cdr variable!-set and not zerop cdr v then <<
  3622. predicted!-forms:=make!-bivariate!-vec!-mod!-p(best!-factors,
  3623. cdr variable!-set,car v,number!-of!-factors);
  3624. find!-multivariate!-factors!-mod!-p(
  3625. make!-bivariate!-mod!-p(poly,cdr variable!-set,car v),
  3626. predicted!-forms,list v);
  3627. % Answers in PREDICTED!-FORMS.
  3628. find!-msg4(predicted!-forms,v);
  3629. make!-predicted!-forms(predicted!-forms,car v);
  3630. % Sets max!-unknowns and number!-of!-unknowns.
  3631. find!-msg5();
  3632. unknowns!-count!-list:=number!-of!-unknowns;
  3633. while unknowns!-count!-list and
  3634. (car (w:=car unknowns!-count!-list))=1 do
  3635. begin scalar i,r;
  3636. unknowns!-count!-list:=cdr unknowns!-count!-list;
  3637. i:=cdr w;
  3638. w:=quotient!-mod!-p(poly!-remaining,r:=getv(best!-factors,i));
  3639. if didntgo w or
  3640. not polyzerop difference!-mod!-p(poly!-remaining,
  3641. times!-mod!-p(w,r)) then
  3642. if one!-prediction!-failed then <<
  3643. factor!-trace printstr "Predictions are no good";
  3644. max!-unknowns:=nil >>
  3645. else <<
  3646. factor!-trace <<
  3647. prin2!* "Guess for f(";
  3648. prin2!* i;
  3649. printstr ") was bad." >>;
  3650. one!-prediction!-failed:=i >>
  3651. else <<
  3652. putv(prediction!-results,i,r);
  3653. factor!-trace <<
  3654. prin2!* "Prediction for f("; prin2!* i;
  3655. prin2!* ") worked: ";
  3656. printsf r >>;
  3657. poly!-remaining:=w >>
  3658. end;
  3659. w:=length unknowns!-count!-list;
  3660. if w=1 and not one!-prediction!-failed then <<
  3661. putv(best!-factors,cdar unknowns!-count!-list,poly!-remaining);
  3662. go to exit >>
  3663. else if w=0 and one!-prediction!-failed then <<
  3664. putv(best!-factors,one!-prediction!-failed,poly!-remaining);
  3665. go to exit >>;
  3666. solve!-count:=1;
  3667. if max!-unknowns then
  3668. correction!-vectors:=
  3669. make!-correction!-vectors(best!-factors,max!-unknowns) >>;
  3670. bhat0s:=make!-multivariate!-hatvec!-mod!-p(b0s,number!-of!-factors);
  3671. correction!-factor:=growth!-factor;
  3672. % next power of growth-factor we are
  3673. % adding to the factors;
  3674. % Now branch to another function to make this one not so huge.
  3675. return find!-multi1(list(res,
  3676. test!-prediction,
  3677. growth!-factor,
  3678. first!-time,
  3679. bhat0s,
  3680. b0s,
  3681. variable!-set,
  3682. solve!-count,
  3683. correction!-vectors,
  3684. unknowns!-count!-list,
  3685. correction!-factor,
  3686. best!-factors,
  3687. v,
  3688. degbd,
  3689. soln!-matrices,
  3690. predicted!-forms,
  3691. poly!-remaining,
  3692. prediction!-results,
  3693. one!-prediction!-failed));
  3694. exit:
  3695. find!-exit(best!-factors,first!-time);
  3696. end) (factor!-level+1);
  3697. symbolic procedure find!-multi1(u);
  3698. begin scalar res,test!-prediction,growth!-factor,first!-time,bhat0s,
  3699. b0s,variable!-set,solve!-count,correction!-vectors,
  3700. unknowns!-count!-list,correction!-factor,best!-factors,v,
  3701. degbd,soln!-matrices,predicted!-forms,poly!-remaining,
  3702. prediction!-results,one!-prediction!-failed,
  3703. b1,bool,d,k,kk,substres,w;
  3704. res := car u; u := cdr u;
  3705. test!-prediction := car u; u := cdr u;
  3706. growth!-factor := car u; u := cdr u;
  3707. first!-time := car u; u := cdr u;
  3708. bhat0s := car u; u := cdr u;
  3709. b0s := car u; u := cdr u;
  3710. variable!-set := car u; u := cdr u;
  3711. solve!-count := car u; u := cdr u;
  3712. correction!-vectors := car u; u := cdr u;
  3713. unknowns!-count!-list := car u; u := cdr u;
  3714. correction!-factor := car u; u := cdr u;
  3715. best!-factors := car u; u := cdr u;
  3716. v := car u; u := cdr u;
  3717. degbd := car u; u := cdr u;
  3718. soln!-matrices := car u; u := cdr u;
  3719. predicted!-forms := car u; u := cdr u;
  3720. poly!-remaining := car u; u := cdr u;
  3721. prediction!-results := car u; u := cdr u;
  3722. one!-prediction!-failed := car u;
  3723. b1:=mkvect number!-of!-factors;
  3724. k:=1;
  3725. kk:=0;
  3726. temploop:
  3727. bool := nil;
  3728. while not bool and not polyzerop res and (null max!-unknowns
  3729. or null test!-prediction) do
  3730. if k>degbd then <<
  3731. factor!-trace <<
  3732. prin2!* "We have overshot the degree bound for ";
  3733. printvar car v >>;
  3734. if !*overshoot then
  3735. printc "Multivariate degree bound overshoot -> restart";
  3736. bad!-case:= bool := t >>
  3737. else
  3738. if polyzerop(substres:=evaluate!-mod!-p(res,car v,cdr v))
  3739. then <<
  3740. k:=iadd1 k;
  3741. res:=diff!-over!-k!-mod!-p(res,k,car v);
  3742. correction!-factor:=
  3743. times!-mod!-p(correction!-factor,growth!-factor) >>
  3744. else begin
  3745. find!-msg6(growth!-factor,first!-time,k,kk,substres);
  3746. kk := kk#+1;
  3747. if first!-time then first!-time := nil;
  3748. solve!-for!-corrections(substres,bhat0s,b0s,b1,
  3749. cdr variable!-set);
  3750. % Answers left in B1;
  3751. if bad!-case then return (bool := t);
  3752. if max!-unknowns then <<
  3753. solve!-count:=iadd1 solve!-count;
  3754. for i:=1:number!-of!-factors do
  3755. putv(getv(correction!-vectors,i),solve!-count,getv(b1,i));
  3756. if solve!-count=caar unknowns!-count!-list then
  3757. test!-prediction:=t >>;
  3758. factor!-trace <<
  3759. printstr " Giving:";
  3760. printvec(" f(",number!-of!-factors,",1) = ",b1) >>;
  3761. d:=times!-mod!-p(correction!-factor,
  3762. terms!-done!-mod!-p(best!-factors,b1,correction!-factor));
  3763. if degree!-in!-variable(d,car v)>degbd then <<
  3764. factor!-trace <<
  3765. prin2!* "We have overshot the degree bound for ";
  3766. printvar car v >>;
  3767. if !*overshoot then
  3768. printc "Multivariate degree bound overshoot -> restart";
  3769. bad!-case:=t;
  3770. return (bool := t)>>;
  3771. d:=diff!-k!-times!-mod!-p(d,k,car v);
  3772. for i:=1:number!-of!-factors do
  3773. putv(best!-factors,i,
  3774. plus!-mod!-p(getv(best!-factors,i),
  3775. times!-mod!-p(getv(b1,i),correction!-factor)));
  3776. k:=iadd1 k;
  3777. res:=diff!-over!-k!-mod!-p(difference!-mod!-p(res,d),k,car v);
  3778. factor!-trace <<
  3779. printstr " New factors are now:";
  3780. printvec(" f(",number!-of!-factors,") = ",best!-factors);
  3781. prin2!* " and residue = ";
  3782. printsf res;
  3783. printstr "-------------"
  3784. >>;
  3785. correction!-factor:=
  3786. times!-mod!-p(correction!-factor,growth!-factor) end;
  3787. if not polyzerop res and not bad!-case then <<
  3788. soln!-matrices:=construct!-soln!-matrices(predicted!-forms,cdr v);
  3789. factor!-trace <<
  3790. printstr "We use the results from the Hensel growth to";
  3791. printstr "produce a set of linear equations to solve";
  3792. printstr "for coefficients in the relevent factors:" >>;
  3793. bool := nil;
  3794. while not bool and unknowns!-count!-list and
  3795. (car (w:=car unknowns!-count!-list))=solve!-count do <<
  3796. unknowns!-count!-list:=cdr unknowns!-count!-list;
  3797. factor!-trace
  3798. print!-linear!-system(cdr w,soln!-matrices,
  3799. correction!-vectors,predicted!-forms,car v);
  3800. w:=try!-prediction(soln!-matrices,correction!-vectors,
  3801. predicted!-forms,car w,cdr w,poly!-remaining,car v,
  3802. nil,nil);
  3803. if car w='singular or car w='bad!-prediction then
  3804. if one!-prediction!-failed then <<
  3805. factor!-trace printstr "Predictions were no help.";
  3806. max!-unknowns:=nil;
  3807. bool := t>>
  3808. else one!-prediction!-failed:=cdr w
  3809. else <<
  3810. putv(prediction!-results,car w,cadr w);
  3811. poly!-remaining:=caddr w >> >>;
  3812. if null max!-unknowns then goto temploop;
  3813. w:=length unknowns!-count!-list;
  3814. if w>1 or (w=1 and one!-prediction!-failed) then <<
  3815. test!-prediction:=nil;
  3816. goto temploop >>;
  3817. if w=1 or one!-prediction!-failed then <<
  3818. w:=if one!-prediction!-failed then one!-prediction!-failed
  3819. else cdar unknowns!-count!-list;
  3820. putv(prediction!-results,w,poly!-remaining) >>;
  3821. for i:=1:number!-of!-factors do
  3822. putv(best!-factors,i,getv(prediction!-results,i));
  3823. if not one!-prediction!-failed then
  3824. predictions:=
  3825. (car v .
  3826. list(soln!-matrices,predicted!-forms,max!-unknowns,
  3827. number!-of!-unknowns))
  3828. . predictions >>;
  3829. find!-exit(best!-factors,first!-time);
  3830. end;
  3831. symbolic procedure find!-msg1(best!-factors,growth!-factor,poly);
  3832. factor!-trace <<
  3833. printstr "Want f(i) s.t.";
  3834. prin2!* " product over i [ f(i) ] = ";
  3835. prinsf poly;
  3836. prin2!* " mod ";
  3837. printstr hensel!-growth!-size;
  3838. terpri!*(nil);
  3839. printstr "We know f(i) as follows:";
  3840. printvec(" f(",number!-of!-factors,") = ",best!-factors);
  3841. prin2!* " and we shall put in powers of ";
  3842. prinsf growth!-factor;
  3843. printstr " to find them fully."
  3844. >>;
  3845. symbolic procedure find!-msg2(v,variable!-set);
  3846. factor!-trace <<
  3847. prin2!*
  3848. "First solve the problem in one less variable by putting ";
  3849. prinvar car v; prin2!* "="; printstr cdr v;
  3850. if cdr variable!-set then <<
  3851. prin2!* "and growing wrt ";
  3852. printvar caadr variable!-set
  3853. >>;
  3854. terpri!*(nil)
  3855. >>;
  3856. symbolic procedure find!-msg3(best!-factors,v);
  3857. factor!-trace <<
  3858. prin2!* "After putting back any knowledge of ";
  3859. prinvar car v;
  3860. printstr ", we have the";
  3861. printstr "factors so far as:";
  3862. printvec(" f(",number!-of!-factors,") = ",best!-factors);
  3863. printstr "Subtracting the product of these from the polynomial";
  3864. prin2!* "and differentiating wrt "; prinvar car v;
  3865. printstr " gives a residue:"
  3866. >>;
  3867. symbolic procedure find!-msg4(predicted!-forms,v);
  3868. factor!-trace <<
  3869. printstr "To help reduce the number of Hensel steps we try";
  3870. prin2!* "predicting how many terms each factor will have wrt ";
  3871. prinvar car v; printstr ".";
  3872. printstr
  3873. "Predictions are based on the bivariate factors :";
  3874. printvec(" f(",number!-of!-factors,") = ",predicted!-forms)
  3875. >>;
  3876. symbolic procedure find!-msg5;
  3877. factor!-trace <<
  3878. terpri!*(nil);
  3879. printstr "We predict :";
  3880. for each w in number!-of!-unknowns do <<
  3881. prin2!* car w;
  3882. prin2!* " terms in f("; prin2!* cdr w; printstr '!) >>;
  3883. if (caar number!-of!-unknowns)=1 then <<
  3884. prin2!* "Since we predict only one term for f(";
  3885. prin2!* cdar number!-of!-unknowns;
  3886. printstr "), we can try";
  3887. printstr "dividing it out now:" >>
  3888. else <<
  3889. prin2!* "So we shall do at least ";
  3890. prin2!* isub1 caar number!-of!-unknowns;
  3891. prin2!* " Hensel step";
  3892. if (caar number!-of!-unknowns)=2 then printstr "."
  3893. else printstr "s." >>;
  3894. terpri!*(nil) >>;
  3895. symbolic procedure find!-msg6(growth!-factor,first!-time,k,kk,substres);
  3896. factor!-trace <<
  3897. prin2!* "Hensel Step "; printstr (kk:=kk #+ 1);
  3898. prin2!* "-------------";
  3899. if kk>10 then printstr "-" else terpri!*(t);
  3900. prin2!* "Next corrections are for (";
  3901. prinsf growth!-factor;
  3902. if not (k=1) then <<
  3903. prin2!* ") ** ";
  3904. prin2!* k >> else prin2!* '!);
  3905. printstr ". To find these we solve:";
  3906. prin2!* " sum over i [ f(i,1)*fhat(i,0) ] = ";
  3907. prinsf substres;
  3908. prin2!* " mod ";
  3909. prin2!* hensel!-growth!-size;
  3910. printstr " for f(i,1), ";
  3911. if first!-time then <<
  3912. prin2!*
  3913. " where fhat(i,0) = product over j [ f(j,0) ]";
  3914. prin2!* " / f(i,0) mod ";
  3915. printstr hensel!-growth!-size >>;
  3916. terpri!*(nil)
  3917. >>;
  3918. symbolic procedure find!-exit(best!-factors,first!-time);
  3919. factor!-trace <<
  3920. if not bad!-case then
  3921. if first!-time then
  3922. printstr "Therefore these factors are already correct."
  3923. else <<
  3924. printstr "Correct factors are:";
  3925. printvec(" f(",number!-of!-factors,") = ",best!-factors)
  3926. >>;
  3927. terpri!*(nil);
  3928. printstr "******************************************************";
  3929. terpri!*(nil) >>;
  3930. symbolic procedure solve!-for!-corrections(c,fhatvec,fvec,resvec,vset);
  3931. % ....;
  3932. if null vset then
  3933. for i:=1:number!-of!-factors do
  3934. putv(resvec,i,
  3935. remainder!-mod!-p(
  3936. times!-mod!-p(c,getv(alphavec,i)),
  3937. getv(fvec,i)))
  3938. else (lambda factor!-level; begin
  3939. scalar residue,growth!-factor,f0s,fhat0s,v,
  3940. correction!-factor,degbd,first!-time,redc,
  3941. predicted!-forms,max!-unknowns,solve!-count,number!-of!-unknowns,
  3942. correction!-vectors,soln!-matrices,w,previous!-prediction!-holds,
  3943. unknowns!-count!-list,test!-prediction,poly!-remaining,
  3944. prediction!-results,one!-prediction!-failed;
  3945. v:=car vset;
  3946. degbd:=get!-degree!-bound car v;
  3947. first!-time:=t;
  3948. growth!-factor:=make!-growth!-factor v;
  3949. poly!-remaining:=c;
  3950. prediction!-results:=mkvect number!-of!-factors;
  3951. redc:=evaluate!-mod!-p(c,car v,cdr v);
  3952. solve!-msg1(c,fvec,v);
  3953. solve!-for!-corrections(redc,
  3954. fhat0s:=reduce!-vec!-by!-one!-var!-mod!-p(
  3955. fhatvec,v,number!-of!-factors),
  3956. f0s:=reduce!-vec!-by!-one!-var!-mod!-p(
  3957. fvec,v,number!-of!-factors),
  3958. resvec,
  3959. cdr vset); % Results left in RESVEC;
  3960. if bad!-case then return;
  3961. solve!-msg2(resvec,v);
  3962. residue:=diff!-over!-k!-mod!-p(difference!-mod!-p(c,
  3963. form!-sum!-and!-product!-mod!-p(resvec,fhatvec,
  3964. number!-of!-factors)),1,car v);
  3965. factor!-trace <<
  3966. printsf residue;
  3967. prin2!* " Now we shall put in the powers of ";
  3968. prinsf growth!-factor;
  3969. printstr " to find the a's fully."
  3970. >>;
  3971. if not polyzerop residue and not zerop cdr v then <<
  3972. w:=atsoc(car v,predictions);
  3973. if w then <<
  3974. previous!-prediction!-holds:=t;
  3975. factor!-trace <<
  3976. printstr
  3977. "We shall use the previous prediction for the form of";
  3978. prin2!* "polynomials wrt "; printvar car v >>;
  3979. w:=cdr w;
  3980. soln!-matrices:=car w;
  3981. predicted!-forms:=cadr w;
  3982. max!-unknowns:=caddr w;
  3983. number!-of!-unknowns:=cadr cddr w >>
  3984. else <<
  3985. factor!-trace <<
  3986. printstr
  3987. "We shall use a new prediction for the form of polynomials ";
  3988. prin2!* "wrt "; printvar car v >>;
  3989. predicted!-forms:=mkvect number!-of!-factors;
  3990. for i:=1:number!-of!-factors do
  3991. putv(predicted!-forms,i,getv(fvec,i));
  3992. % make a copy of the factors in a vector that we shall
  3993. % overwrite;
  3994. make!-predicted!-forms(predicted!-forms,car v);
  3995. % sets max!-unknowns and number!-of!-unknowns;
  3996. >>;
  3997. solve!-msg3();
  3998. unknowns!-count!-list:=number!-of!-unknowns;
  3999. while unknowns!-count!-list and
  4000. (car (w:=car unknowns!-count!-list))=1 do
  4001. begin scalar i,r,wr,fi;
  4002. unknowns!-count!-list:=cdr unknowns!-count!-list;
  4003. i:=cdr w;
  4004. w:=quotient!-mod!-p(
  4005. wr:=difference!-mod!-p(poly!-remaining,
  4006. times!-mod!-p(r:=getv(resvec,i),getv(fhatvec,i))),
  4007. fi:=getv(fvec,i));
  4008. if didntgo w or not polyzerop
  4009. difference!-mod!-p(wr,times!-mod!-p(w,fi)) then
  4010. if one!-prediction!-failed then <<
  4011. factor!-trace printstr "Predictions are no good.";
  4012. max!-unknowns:=nil >>
  4013. else <<
  4014. factor!-trace <<
  4015. prin2!* "Guess for a(";
  4016. prin2!* i;
  4017. printstr ") was bad." >>;
  4018. one!-prediction!-failed:=i >>
  4019. else <<
  4020. putv(prediction!-results,i,r);
  4021. factor!-trace <<
  4022. prin2!* "Prediction for a("; prin2!* i;
  4023. prin2!* ") worked: ";
  4024. printsf r >>;
  4025. poly!-remaining:=wr >>
  4026. end;
  4027. w:=length unknowns!-count!-list;
  4028. if w=1 and not one!-prediction!-failed then <<
  4029. putv(resvec,cdar unknowns!-count!-list,
  4030. quotfail!-mod!-p(poly!-remaining,getv(fhatvec,
  4031. cdar unknowns!-count!-list)));
  4032. go to exit >>
  4033. else if w=0 and one!-prediction!-failed then <<
  4034. putv(resvec,one!-prediction!-failed,
  4035. quotfail!-mod!-p(poly!-remaining,getv(fhatvec,
  4036. one!-prediction!-failed)));
  4037. go to exit >>;
  4038. solve!-count:=1;
  4039. if max!-unknowns then
  4040. correction!-vectors:=
  4041. make!-correction!-vectors(resvec,max!-unknowns) >>;
  4042. correction!-factor:=growth!-factor;
  4043. if not polyzerop residue then first!-time:=nil;
  4044. % Now branch to another function to make this one not so huge.
  4045. return solve!-for1(list(test!-prediction,
  4046. growth!-factor,
  4047. first!-time,
  4048. fhat0s,
  4049. f0s,
  4050. vset,
  4051. solve!-count,
  4052. correction!-vectors,
  4053. unknowns!-count!-list,
  4054. resvec,
  4055. correction!-factor,
  4056. v,
  4057. degbd,
  4058. soln!-matrices,
  4059. predicted!-forms,
  4060. poly!-remaining,
  4061. fvec,
  4062. prediction!-results,
  4063. previous!-prediction!-holds,
  4064. one!-prediction!-failed));
  4065. exit:
  4066. solve!-exit(bad!-case,first!-time,resvec);
  4067. end) (factor!-level+1);
  4068. symbolic procedure solve!-for1 u;
  4069. begin scalar test!-prediction,growth!-factor,first!-time,fhat0s,f0s,
  4070. vset,solve!-count,correction!-vectors,unknowns!-count!-list,
  4071. resvec,correction!-factor,v,degbd,soln!-matrices,
  4072. predicted!-forms,poly!-remaining,fvec,prediction!-results,
  4073. previous!-prediction!-holds,one!-prediction!-failed,
  4074. bool,d,f1,k,kk,substres,w;
  4075. test!-prediction := car u; u := cdr u;
  4076. growth!-factor := car u; u := cdr u;
  4077. first!-time := car u; u := cdr u;
  4078. fhat0s := car u; u := cdr u;
  4079. f0s := car u; u := cdr u;
  4080. vset := car u; u := cdr u;
  4081. solve!-count := car u; u := cdr u;
  4082. correction!-vectors := car u; u := cdr u;
  4083. unknowns!-count!-list := car u; u := cdr u;
  4084. resvec := car u; u := cdr u;
  4085. correction!-factor := car u; u := cdr u;
  4086. v := car u; u := cdr u;
  4087. degbd := car u; u := cdr u;
  4088. soln!-matrices := car u; u := cdr u;
  4089. predicted!-forms := car u; u := cdr u;
  4090. poly!-remaining := car u; u := cdr u;
  4091. fvec := car u; u := cdr u;
  4092. prediction!-results := car u; u := cdr u;
  4093. previous!-prediction!-holds := car u; u := cdr u;
  4094. one!-prediction!-failed := car u;
  4095. f1:=mkvect number!-of!-factors;
  4096. k:=1;
  4097. kk:=0;
  4098. temploop:
  4099. bool := nil;
  4100. while not bool and not polyzerop residue and (null max!-unknowns
  4101. or null test!-prediction) do
  4102. if k>degbd then <<
  4103. factor!-trace <<
  4104. prin2!* "We have overshot the degree bound for ";
  4105. printvar car v >>;
  4106. if !*overshoot then
  4107. printc "Multivariate degree bound overshoot -> restart";
  4108. bad!-case:= bool := t >>
  4109. else
  4110. if polyzerop(substres:=evaluate!-mod!-p(residue,car v,cdr v))
  4111. then <<
  4112. k:=iadd1 k;
  4113. residue:=diff!-over!-k!-mod!-p(residue,k,car v);
  4114. correction!-factor:=
  4115. times!-mod!-p(correction!-factor,growth!-factor) >>
  4116. else begin
  4117. solve!-msg4(growth!-factor,k,kk,substres);
  4118. solve!-for!-corrections(substres,fhat0s,f0s,f1,cdr vset);
  4119. % answers in f1;
  4120. if bad!-case then return (bool := t);
  4121. if max!-unknowns then <<
  4122. solve!-count:=iadd1 solve!-count;
  4123. for i:=1:number!-of!-factors do
  4124. putv(getv(correction!-vectors,i),solve!-count,getv(f1,i));
  4125. if solve!-count=caar unknowns!-count!-list then
  4126. test!-prediction:=t >>;
  4127. for i:=1:number!-of!-factors do
  4128. putv(resvec,i,plus!-mod!-p(getv(resvec,i),times!-mod!-p(
  4129. getv(f1,i),correction!-factor)));
  4130. factor!-trace <<
  4131. printstr " Giving:";
  4132. printvec(" a(",number!-of!-factors,",1) = ",f1);
  4133. printstr " New a's are now:";
  4134. printvec(" a(",number!-of!-factors,") = ",resvec)
  4135. >>;
  4136. d:=times!-mod!-p(correction!-factor,
  4137. form!-sum!-and!-product!-mod!-p(f1,fhatvec,
  4138. number!-of!-factors));
  4139. if degree!-in!-variable(d,car v)>degbd then <<
  4140. factor!-trace <<
  4141. prin2!* "We have overshot the degree bound for ";
  4142. printvar car v >>;
  4143. if !*overshoot then
  4144. printc "Multivariate degree bound overshoot -> restart";
  4145. bad!-case:=t;
  4146. return (bool := t)>>;
  4147. d:=diff!-k!-times!-mod!-p(d,k,car v);
  4148. k:=iadd1 k;
  4149. residue:=diff!-over!-k!-mod!-p(
  4150. difference!-mod!-p(residue,d),k,car v);
  4151. factor!-trace <<
  4152. prin2!* " and residue = ";
  4153. printsf residue;
  4154. printstr "-------------"
  4155. >>;
  4156. correction!-factor:=
  4157. times!-mod!-p(correction!-factor,growth!-factor) end;
  4158. if not polyzerop residue and not bad!-case then <<
  4159. if null soln!-matrices then
  4160. soln!-matrices:=
  4161. construct!-soln!-matrices(predicted!-forms,cdr v);
  4162. factor!-trace <<
  4163. printstr "The Hensel growth so far allows us to test some of";
  4164. printstr "our predictions:" >>;
  4165. bool := nil;
  4166. while not bool and unknowns!-count!-list and
  4167. (car (w:=car unknowns!-count!-list))=solve!-count do <<
  4168. unknowns!-count!-list:=cdr unknowns!-count!-list;
  4169. factor!-trace
  4170. print!-linear!-system(cdr w,soln!-matrices,
  4171. correction!-vectors,predicted!-forms,car v);
  4172. w:=try!-prediction(soln!-matrices,correction!-vectors,
  4173. predicted!-forms,car w,cdr w,poly!-remaining,car v,fvec,
  4174. fhatvec);
  4175. if car w='singular or car w='bad!-prediction then
  4176. if one!-prediction!-failed then <<
  4177. factor!-trace printstr "Predictions were no help.";
  4178. max!-unknowns:=nil;
  4179. bool := t>>
  4180. else <<
  4181. if previous!-prediction!-holds then <<
  4182. predictions:=delasc(car v,predictions);
  4183. previous!-prediction!-holds:=nil >>;
  4184. one!-prediction!-failed:=cdr w >>
  4185. else <<
  4186. putv(prediction!-results,car w,cadr w);
  4187. poly!-remaining:=caddr w >> >>;
  4188. if null max!-unknowns then <<
  4189. if previous!-prediction!-holds then
  4190. predictions:=delasc(car v,predictions);
  4191. goto temploop >>;
  4192. w:=length unknowns!-count!-list;
  4193. if w>1 or (w=1 and one!-prediction!-failed) then <<
  4194. test!-prediction:=nil;
  4195. goto temploop >>;
  4196. if w=1 or one!-prediction!-failed then <<
  4197. w:=if one!-prediction!-failed then one!-prediction!-failed
  4198. else cdar unknowns!-count!-list;
  4199. putv(prediction!-results,w,quotfail!-mod!-p(
  4200. poly!-remaining,getv(fhatvec,w))) >>;
  4201. for i:=1:number!-of!-factors do
  4202. putv(resvec,i,getv(prediction!-results,i));
  4203. if not previous!-prediction!-holds
  4204. and not one!-prediction!-failed then
  4205. predictions:=
  4206. (car v .
  4207. list(soln!-matrices,predicted!-forms,max!-unknowns,
  4208. number!-of!-unknowns))
  4209. . predictions >>;
  4210. solve!-exit(bad!-case,first!-time,resvec)
  4211. end;
  4212. symbolic procedure solve!-msg1(c,fvec,v);
  4213. factor!-trace <<
  4214. printstr "Want a(i) s.t.";
  4215. prin2!* "(*) sum over i [ a(i)*fhat(i) ] = ";
  4216. prinsf c;
  4217. prin2!* " mod ";
  4218. printstr hensel!-growth!-size;
  4219. prin2!* " where fhat(i) = product over j [ f(j) ]";
  4220. prin2!* " / f(i) mod ";
  4221. printstr hensel!-growth!-size;
  4222. printstr " and";
  4223. printvec(" f(",number!-of!-factors,") = ",fvec);
  4224. terpri!*(nil);
  4225. prin2!*
  4226. "First solve the problem in one less variable by putting ";
  4227. prinvar car v; prin2!* '!=; printstr cdr v;
  4228. terpri!*(nil)
  4229. >>;
  4230. symbolic procedure solve!-msg2(resvec,v);
  4231. factor!-trace <<
  4232. printstr "Giving:";
  4233. printvec(" a(",number!-of!-factors,",0) = ",resvec);
  4234. printstr "Subtracting the contributions these give in (*) from";
  4235. prin2!* "the R.H.S. of (*) ";
  4236. prin2!* "and differentiating wrt "; prinvar car v;
  4237. printstr " gives a residue:"
  4238. >>;
  4239. symbolic procedure solve!-msg3;
  4240. factor!-trace <<
  4241. terpri!*(nil);
  4242. printstr "We predict :";
  4243. for each w in number!-of!-unknowns do <<
  4244. prin2!* car w;
  4245. prin2!* " terms in a("; prin2!* cdr w; printstr '!) >>;
  4246. if (caar number!-of!-unknowns)=1 then <<
  4247. prin2!* "Since we predict only one term for a(";
  4248. prin2!* cdar number!-of!-unknowns;
  4249. printstr "), we can test it right away:" >>
  4250. else <<
  4251. prin2!* "So we shall do at least ";
  4252. prin2!* isub1 caar number!-of!-unknowns;
  4253. prin2!* " Hensel step";
  4254. if (caar number!-of!-unknowns)=2 then printstr "."
  4255. else printstr "s." >>;
  4256. terpri!*(nil) >>;
  4257. symbolic procedure solve!-msg4(growth!-factor,k,kk,substres);
  4258. factor!-trace <<
  4259. prin2!* "Hensel Step "; printstr (kk:=kk #+ 1);
  4260. prin2!* "-------------";
  4261. if kk>10 then printstr "-" else terpri!*(t);
  4262. prin2!* "Next corrections are for (";
  4263. prinsf growth!-factor;
  4264. if not (k=1) then <<
  4265. prin2!* ") ** ";
  4266. prin2!* k >> else prin2!* '!);
  4267. printstr ". To find these we solve:";
  4268. prin2!* " sum over i [ a(i,1)*fhat(i,0) ] = ";
  4269. prinsf substres;
  4270. prin2!* " mod ";
  4271. prin2!* hensel!-growth!-size;
  4272. printstr " for a(i,1). ";
  4273. terpri!*(nil)
  4274. >>;
  4275. symbolic procedure solve!-exit(bad!-case,first!-time,resvec);
  4276. factor!-trace <<
  4277. if not bad!-case then
  4278. if first!-time then
  4279. printstr "But these a's are already correct."
  4280. else <<
  4281. printstr "Correct a's are:";
  4282. printvec(" a(",number!-of!-factors,") = ",resvec)
  4283. >>;
  4284. terpri!*(nil);
  4285. printstr "**************************************************";
  4286. terpri!*(nil) >>;
  4287. endmodule;
  4288. module unihens; % Univariate case of Hensel code with quadratic growth.
  4289. % Author: P. M. A. Moore, 1979.
  4290. fluid '(!*linear
  4291. !*overshoot
  4292. !*overview
  4293. !*trfac
  4294. alphalist
  4295. alphavec
  4296. coefftbd
  4297. current!-factor!-product
  4298. current!-modulus
  4299. delfvec
  4300. deltam
  4301. factor!-level
  4302. factor!-trace!-list
  4303. factors!-done
  4304. factorvec
  4305. facvec
  4306. fhatvec
  4307. hensel!-growth!-size
  4308. hensel!-poly
  4309. irreducible
  4310. m!-image!-variable
  4311. modfvec
  4312. multivariate!-input!-poly
  4313. non!-monic
  4314. number!-of!-factors
  4315. polyzero
  4316. prime!-base
  4317. reconstructing!-gcd);
  4318. global '(largest!-small!-modulus);
  4319. symbolic procedure uhensel!.extend(poly,best!-flist,lclist,p);
  4320. % Extend poly=product(factors in best!-flist) mod p even if poly is
  4321. % non-monic. Return a list (ok. list of factors) if factors can be
  4322. % extended to be correct over the integers, otherwise return a list
  4323. % (failed <reason> <reason>).
  4324. begin scalar w,k,old!-modulus,alphavec,modular!-flist,factorvec,
  4325. modfvec,coefftbd,fcount,fhatvec,deltam,mod!-symm!-flist,
  4326. current!-factor!-product,facvec,factors!-done,hensel!-poly;
  4327. prime!-base:=p;
  4328. old!-modulus:=set!-modulus p;
  4329. % timer:=readtime();
  4330. number!-of!-factors:=length best!-flist;
  4331. w:=expt(lc poly,number!-of!-factors -1);
  4332. if lc poly < 0 then errorf list("LC SHOULD NOT BE -VE",poly);
  4333. coefftbd:=max(110,p+1,lc poly*get!-coefft!-bound(poly,ldeg poly));
  4334. poly:=multf(poly,w);
  4335. modular!-flist:=for each ff in best!-flist collect
  4336. reduce!-mod!-p ff;
  4337. % Modular factors have been multiplied by a constant to
  4338. % fix the l.c.'s, so they may be out of range - this
  4339. % fixes that.
  4340. if not(w=1) then factor!-trace <<
  4341. prin2!* "Altered univariate polynomial: "; printsf poly >>;
  4342. % Make sure the leading coefft will not cause trouble
  4343. % in the hensel construction.
  4344. mod!-symm!-flist:=for each ff in modular!-flist collect
  4345. make!-modular!-symmetric ff;
  4346. if not !*overview then factor!-trace <<
  4347. prin2!* "The factors mod "; prin2!* p;
  4348. printstr " to start from are:";
  4349. fcount:=1;
  4350. for each ff in mod!-symm!-flist do <<
  4351. prin2!* " f("; prin2!* fcount; prin2!* ")=";
  4352. printsf ff; fcount:=iadd1 fcount >>;
  4353. terpri!*(nil) >>;
  4354. alphalist:=alphas(number!-of!-factors,modular!-flist,1);
  4355. % 'magic' polynomials associated with the image factors.
  4356. if not !*overview then factor!-trace <<
  4357. printstr
  4358. "The following modular polynomials are chosen such that:";
  4359. terpri();
  4360. prin2!* " a(1)*h(1) + ... + a(";
  4361. prin2!* number!-of!-factors;
  4362. prin2!* ")*h("; prin2!* number!-of!-factors;
  4363. prin2!* ") = 1 mod "; printstr p;
  4364. terpri();
  4365. printstr " where h(i)=(product of all f(j) [see below])/f(i)";
  4366. printstr " and degree of a(i) < degree of f(i).";
  4367. fcount:=1;
  4368. for each a in modular!-flist do <<
  4369. prin2!* " a("; prin2!* fcount; prin2!* ")=";
  4370. printsf cdr get!-alpha a;
  4371. prin2!* " f("; prin2!* fcount; prin2!* ")=";
  4372. printsf a;
  4373. fcount:=iadd1 fcount >>
  4374. >>;
  4375. k:=0;
  4376. factorvec:=mkvect number!-of!-factors;
  4377. modfvec:=mkvect number!-of!-factors;
  4378. alphavec:=mkvect number!-of!-factors;
  4379. for each modsymmf in mod!-symm!-flist do
  4380. << putv(factorvec,k:=k+1,force!-lc(modsymmf,car lclist));
  4381. lclist:=cdr lclist
  4382. >>;
  4383. k:=0;
  4384. for each modfactor in modular!-flist do
  4385. << putv(modfvec,k:=k+1,modfactor);
  4386. putv(alphavec,k,cdr get!-alpha modfactor);
  4387. >>;
  4388. % best!-fvec is now a vector of factors of poly correct
  4389. % mod p with true l.c.s forced in.
  4390. fhatvec:=mkvect number!-of!-factors;
  4391. w:=hensel!-mod!-p(poly,modfvec,factorvec,coefftbd,nil,p);
  4392. if car w='overshot then w := uhensel!.extend1(poly,w)
  4393. else w := uhensel!.extend2 w;
  4394. set!-modulus old!-modulus;
  4395. if irreducible then <<
  4396. factor!-trace
  4397. printstr "Two factors and overshooting means irreducible";
  4398. return t >>;
  4399. factor!-trace begin scalar k;
  4400. k:=0;
  4401. printstr "Univariate factors, possibly with adjusted leading";
  4402. printstr "coefficients, are:";
  4403. for each ww in cdr w do <<
  4404. prin2!* " f("; prin2!* (k:=k #+ 1);
  4405. prin2!* ")="; printsf ww >>
  4406. end;
  4407. return if non!-monic then
  4408. (car w . primitive!.parts(cdr w,m!-image!-variable,t))
  4409. else w
  4410. end;
  4411. symbolic procedure uhensel!.extend1(poly,w);
  4412. begin scalar oklist,badlist,m,r,ff,om,pol;
  4413. m:=cadr w; % the modulus.
  4414. r:=getv(factorvec,0); % the number of factors.
  4415. if r=2 then return (irreducible:=t);
  4416. if factors!-done then <<
  4417. poly:=hensel!-poly;
  4418. for each ww in factors!-done do
  4419. poly:=multf(poly,ww) >>;
  4420. pol:=poly;
  4421. om:=set!-modulus hensel!-growth!-size;
  4422. alphalist:=nil;
  4423. for i:=r step -1 until 1 do
  4424. alphalist:=
  4425. (reduce!-mod!-p getv(factorvec,i) . getv(alphavec,i))
  4426. . alphalist;
  4427. set!-modulus om;
  4428. % bring alphalist up to date.
  4429. for i:=1:r do <<
  4430. ff:=getv(factorvec,i);
  4431. if not didntgo(w:=quotf(pol,ff)) then
  4432. << oklist:=ff . oklist; pol:=w>>
  4433. else badlist:=(i . ff) . badlist >>;
  4434. if null badlist then w:='ok . oklist
  4435. else <<
  4436. if not !*overview then factor!-trace <<
  4437. printstr "Overshot factors are:";
  4438. for each f in badlist do <<
  4439. prin2!* " f("; prin2!* car f; prin2!* ")=";
  4440. printsf cdr f >>
  4441. >>;
  4442. w:=try!.combining(badlist,pol,m,nil);
  4443. if car w='one! bad! factor then begin scalar x;
  4444. w:=append(oklist,cdr w);
  4445. x:=1;
  4446. for each v in w do x:=multf(x,v);
  4447. w:='ok . (quotfail(pol,x) . w)
  4448. end
  4449. else w:='ok . append(oklist,w) >>;
  4450. if (not !*linear) and multivariate!-input!-poly then <<
  4451. poly:=1;
  4452. number!-of!-factors:=0;
  4453. for each facc in cdr w do <<
  4454. poly:=multf(poly,facc);
  4455. number!-of!-factors:=1 #+ number!-of!-factors >>;
  4456. % make sure poly is the product of the factors we have,
  4457. % we recalculate it this way because we may have the wrong
  4458. % lc in old value of poly.
  4459. reset!-quadratic!-step!-fluids(poly,cdr w,
  4460. number!-of!-factors);
  4461. if m=deltam then errorf list("Coefft bound < prime ?",
  4462. coefftbd,m);
  4463. m:=deltam*deltam;
  4464. while m<largest!-small!-modulus do <<
  4465. quadratic!-step(m,number!-of!-factors);
  4466. m:=m*deltam >>;
  4467. hensel!-growth!-size:=deltam;
  4468. om:=set!-modulus hensel!-growth!-size;
  4469. alphalist:=nil;
  4470. for i:=number!-of!-factors step -1 until 1 do
  4471. alphalist:=
  4472. (reduce!-mod!-p getv(factorvec,i) . getv(alphavec,i))
  4473. . alphalist;
  4474. set!-modulus om >>;
  4475. return w
  4476. end;
  4477. symbolic procedure uhensel!.extend2 w;
  4478. begin scalar r,faclist,om;
  4479. r:=getv(factorvec,0); % no of factors.
  4480. om:=set!-modulus hensel!-growth!-size;
  4481. alphalist:=nil;
  4482. for i:=r step -1 until 1 do
  4483. alphalist:=(reduce!-mod!-p getv(factorvec,i) . getv(alphavec,i))
  4484. . alphalist;
  4485. set!-modulus om;
  4486. % bring alphalist up to date.
  4487. for i:=r step -1 until 1 do
  4488. faclist:=getv(factorvec,i) . faclist;
  4489. return (car w . faclist)
  4490. end;
  4491. symbolic procedure get!-coefft!-bound(poly,ddeg);
  4492. % This uses Mignotte's bound which is minimal I believe.
  4493. % NB. poly had better be univariate as bound only valid for this.
  4494. binomial!-coefft(ddeg/2,ddeg/4) * root!-squares(poly,0);
  4495. symbolic procedure binomial!-coefft(n,r);
  4496. if n<r then nil
  4497. else if n=r then 1
  4498. else if r=1 then n
  4499. else begin scalar n!-c!-r,b;
  4500. n!-c!-r:=1;
  4501. b:=min(r,n-r);
  4502. for i:=1:b do
  4503. n!-c!-r:=(n!-c!-r * (n - i + 1)) / i;
  4504. return n!-c!-r
  4505. end;
  4506. symbolic procedure pmam!-sqrt n;
  4507. % Find the square root of n and return integer part + 1. N is fixed pt
  4508. % on input as it may be very large, i.e. > largest allowed floating pt
  4509. % number so I scale it appropriately.
  4510. begin scalar s,ten!*!*6,ten!*!*12,ten!*!*14;
  4511. s:=0;
  4512. ten!*!*6:=10**6;
  4513. ten!*!*12:=ten!*!*6**2;
  4514. ten!*!*14:=100*ten!*!*12;
  4515. while n>ten!*!*14 do << s:=iadd1 s; n:=1+n/ten!*!*12 >>;
  4516. return ((fix sqrt!-float float n) + 1) * 10**(6*s)
  4517. end;
  4518. symbolic procedure find!-alphas!-in!-a!-ring(n,mflist,fhatlist,gamma);
  4519. % Find the alphas (as below) given that the modulus may not be prime
  4520. % but is a prime power.
  4521. begin scalar gg,m,ppow,i,gg!-mod!-p,modflist,wvec,alpha,alphazeros,w;
  4522. if null prime!-base then errorf
  4523. list("Prime base not set for finding alphas",
  4524. current!-modulus,n,mflist);
  4525. m:=set!-modulus prime!-base;
  4526. modflist:= if m=prime!-base then mflist
  4527. else for each fthing in mflist collect
  4528. reduce!-mod!-p !*mod2f fthing;
  4529. alphalist:=alphas(n,modflist,gamma);
  4530. if m=prime!-base then <<
  4531. set!-modulus m;
  4532. return alphalist >>;
  4533. i:=0;
  4534. alphazeros:=mkvect n;
  4535. wvec:=mkvect n;
  4536. for each modfthing in modflist do <<
  4537. putv(modfvec,i:=iadd1 i,modfthing);
  4538. putv(alphavec,i,!*f2mod(alpha:=cdr get!-alpha modfthing));
  4539. putv(alphazeros,i,alpha);
  4540. putv(wvec,i,alpha);
  4541. putv(fhatvec,i,car fhatlist);
  4542. fhatlist:=cdr fhatlist >>;
  4543. gg:=gamma;
  4544. ppow:=prime!-base;
  4545. while ppow<m do <<
  4546. set!-modulus m;
  4547. gg:=!*f2mod quotfail(!*mod2f difference!-mod!-p(gg,
  4548. form!-sum!-and!-product!-mod!-m(wvec,fhatvec,n)),prime!-base);
  4549. set!-modulus prime!-base;
  4550. gg!-mod!-p:=reduce!-mod!-p !*mod2f gg;
  4551. for k:=1:n do <<
  4552. putv(wvec,k,w:=remainder!-mod!-p(
  4553. times!-mod!-p(getv(alphazeros,k),gg!-mod!-p),
  4554. getv(modfvec,k)));
  4555. putv(alphavec,k,addf(getv(alphavec,k),multf(!*mod2f w,ppow)))>>;
  4556. ppow:=ppow*prime!-base >>;
  4557. set!-modulus m;
  4558. i:=0;
  4559. return (for each fthing in mflist collect
  4560. (fthing . !*f2mod getv(alphavec,i:=iadd1 i)))
  4561. end;
  4562. symbolic procedure alphas(n,flist,gamma);
  4563. % Finds alpha,beta,delta,... wrt factors f(i) in flist s.t.
  4564. % alpha*g(1) + beta*g(2) + delta*g(3) + ... = gamma mod p,
  4565. % where g(i)=product(all the f(j) except f(i) itself).
  4566. % (cf. xgcd!-mod!-p below). n is number of factors in flist.
  4567. if n=1 then list(car flist . gamma)
  4568. else begin scalar k,w,f1,f2,i,gamma1,gamma2;
  4569. k:=n/2;
  4570. f1:=1; f2:=1;
  4571. i:=1;
  4572. for each f in flist do
  4573. << if i>k then f2:=times!-mod!-p(f,f2)
  4574. else f1:=times!-mod!-p(f,f1);
  4575. i:=i+1 >>;
  4576. w:=xgcd!-mod!-p(f1,f2,1,polyzero,polyzero,1);
  4577. if atom w then
  4578. return 'factors! not! coprime;
  4579. gamma1:=remainder!-mod!-p(times!-mod!-p(cdr w,gamma),f1);
  4580. gamma2:=remainder!-mod!-p(times!-mod!-p(car w,gamma),f2);
  4581. i:=1; f1:=nil; f2:=nil;
  4582. for each f in flist do
  4583. << if i>k then f2:=f . f2
  4584. else f1:=f . f1;
  4585. i:=i+1 >>;
  4586. return append(
  4587. alphas(k,f1,gamma1),
  4588. alphas(n-k,f2,gamma2))
  4589. end;
  4590. symbolic procedure xgcd!-mod!-p(a,b,x1,y1,x2,y2);
  4591. % Finds alpha and beta s.t. alpha*a+beta*b=1.
  4592. % Returns alpha . beta or nil if a and b are not coprime.
  4593. if null b then nil
  4594. else if isdomain b then begin
  4595. b:=modular!-reciprocal b;
  4596. x2:=multiply!-by!-constant!-mod!-p(x2,b);
  4597. y2:=multiply!-by!-constant!-mod!-p(y2,b);
  4598. return x2 . y2 end
  4599. else begin scalar q;
  4600. q:=quotient!-mod!-p(a,b); % Truncated quotient here.
  4601. return xgcd!-mod!-p(b,difference!-mod!-p(a,times!-mod!-p(b,q)),
  4602. x2,y2,
  4603. difference!-mod!-p(x1,times!-mod!-p(x2,q)),
  4604. difference!-mod!-p(y1,times!-mod!-p(y2,q)))
  4605. end;
  4606. symbolic procedure hensel!-mod!-p(poly,mvec,fvec,cbd,vset,p);
  4607. % Hensel construction building up in powers of p.
  4608. % Given that poly=product(factors in factorvec) mod p, find the full
  4609. % factors over the integers. Mvec contains the univariate factors mod p
  4610. % while fvec contains our best knowledge of the factors to date.
  4611. % Fvec includes leading coeffts (and in multivariate case possibly other
  4612. % coeffts) of the factors. return a list whose first element is a flag
  4613. % with one of the following values:
  4614. % ok construction worked, the cdr of the result is a list of
  4615. % the correct factors.
  4616. % failed inputs must have been incorrect
  4617. % overshot factors are correct mod some power of p (say p**m),
  4618. % but are not correct over the integers.
  4619. % result is (overshot,p**m,list of factors so far).
  4620. begin scalar w,u0,delfvec,old!.mod,res,m;
  4621. u0:=initialize!-hensel(number!-of!-factors,p,poly,mvec,fvec,cbd);
  4622. % u0 contains the product (over integers) of factors mod p.
  4623. m := p;
  4624. old!.mod := set!-modulus nil;
  4625. if number!-of!-factors=1
  4626. then <<putv(fvec,1,current!-factor!-product:=poly);
  4627. % Added JHD 28.9.87
  4628. return hensel!-exit(m,old!.mod,p,vset,w)>>;
  4629. % only one factor to grow! but need to go this deep to
  4630. % construct the alphas and set things up for the
  4631. % multivariate growth which may follow.
  4632. hensel!-msg1(p,u0);
  4633. old!.mod:=set!-modulus p;
  4634. res:=addf(hensel!-poly,negf u0);
  4635. % calculate the residue. from now on this is always
  4636. % kept in res.
  4637. m:=p;
  4638. % measure of how far we have built up factors - at this
  4639. % stage we know the constant terms mod p in the factors.
  4640. a: if polyzerop res then return hensel!-exit(m,old!.mod,p,vset,w);
  4641. if (m/2)>coefftbd then
  4642. <<
  4643. % we started with a false split of the image so some
  4644. % of the factors we have built up must amalgamate in
  4645. % the complete factorization.
  4646. if !*overshoot then <<
  4647. prin2 if null vset then "Univariate " else "Multivariate ";
  4648. printc "coefft bound overshoot" >>;
  4649. if not !*overview then
  4650. factor!-trace printstr "We have overshot the coefficient bound";
  4651. return hensel!-exit(m,old!.mod,p,vset,'overshot)>>;
  4652. res:=quotfail(res,deltam);
  4653. % next term in residue.
  4654. if not !*overview then factor!-trace <<
  4655. prin2!* "Residue divided by "; prin2!* m; prin2!* " is ";
  4656. printsf res >>;
  4657. if (not !*linear) and null vset
  4658. and m<=largest!-small!-modulus and m>p then
  4659. quadratic!-step(m,number!-of!-factors);
  4660. w:=reduce!-mod!-p res;
  4661. if not !*overview then factor!-trace <<
  4662. prin2!* "Next term in residue to kill is:";
  4663. prinsf w; prin2!* " which is of size ";
  4664. printsf (deltam*m);
  4665. >>;
  4666. solve!-for!-corrections(w,fhatvec,modfvec,delfvec,vset);
  4667. % delfvec is vector of next correction terms to factors.
  4668. make!-vec!-modular!-symmetric(delfvec,number!-of!-factors);
  4669. if not !*overview then factor!-trace <<
  4670. printstr "Correction terms are:";
  4671. w:=1;
  4672. for i:=1:number!-of!-factors do <<
  4673. prin2!* " To f("; prin2!* w; prin2!* "): ";
  4674. printsf multf(m,getv(delfvec,i));
  4675. w:=iadd1 w >>;
  4676. >>;
  4677. w:=terms!-done(factorvec,delfvec,m);
  4678. res:=addf(res,negf w);
  4679. % subtract out the terms generated by these corrections
  4680. % from the residue.
  4681. current!-factor!-product:=
  4682. addf(current!-factor!-product,multf(m,w));
  4683. % add in the correction terms to give new factor product.
  4684. for i:=1:number!-of!-factors do
  4685. putv(factorvec,i,
  4686. addf(getv(factorvec,i),multf(getv(delfvec,i),m)));
  4687. % add the corrections into the factors.
  4688. if not !*overview then factor!-trace <<
  4689. printstr " giving new factors as:";
  4690. w:=1;
  4691. for i:=1:number!-of!-factors do <<
  4692. prin2!* " f("; prin2!* w; prin2!* ")=";
  4693. printsf getv(factorvec,i); w:=iadd1 w >>
  4694. >>;
  4695. m:=m*deltam;
  4696. if not polyzerop res and null vset and
  4697. not reconstructing!-gcd then
  4698. begin scalar j,u,fac;
  4699. j:=0;
  4700. while (j:=j #+ 1)<=number!-of!-factors do
  4701. % IF NULL GETV(DELFVEC,J) AND
  4702. % - Try dividing out every time for now.
  4703. if not didntgo
  4704. (u:=quotf(hensel!-poly,fac:=getv(factorvec,j))) then <<
  4705. hensel!-poly:=u;
  4706. res:=adjust!-growth(fac,j,m);
  4707. j:=number!-of!-factors >>
  4708. end;
  4709. go to a
  4710. end;
  4711. symbolic procedure hensel!-exit(m,old!.mod,p,vset,w);
  4712. begin
  4713. if factors!-done then <<
  4714. if not(w='overshot) then m:=p*p;
  4715. set!-hensel!-fluids!-back p >>;
  4716. if (not (w='overshot)) and null vset
  4717. and (not !*linear) and multivariate!-input!-poly then
  4718. while m<largest!-small!-modulus do <<
  4719. if not(m=deltam) then quadratic!-step(m,number!-of!-factors);
  4720. m:=m*deltam >>;
  4721. % set up the alphas etc so that multivariate growth can
  4722. % use a Hensel growth size of about word size.
  4723. set!-modulus old!.mod;
  4724. % reset the old modulus.
  4725. hensel!-growth!-size:=deltam;
  4726. putv(factorvec,0,number!-of!-factors);
  4727. return
  4728. if w='overshot then list('overshot,m,factorvec)
  4729. else 'ok . factorvec
  4730. end;
  4731. symbolic procedure hensel!-msg1(p,u0);
  4732. begin scalar w;
  4733. factor!-trace <<
  4734. printstr
  4735. "We are now ready to use the Hensel construction to grow";
  4736. prin2!* "in powers of "; printstr current!-modulus;
  4737. if not !*overview then <<prin2!* "Polynomial to factor (=U): ";
  4738. printsf hensel!-poly>>;
  4739. prin2!* "Initial factors mod "; prin2!* p;
  4740. printstr " with some correct coefficients:";
  4741. w:=1;
  4742. for i:=1:number!-of!-factors do <<
  4743. prin2!* " f("; prin2!* w; prin2!* ")=";
  4744. printsf getv(factorvec,i); w:=iadd1 w >>;
  4745. if not !*overview then << prin2!* "Coefficient bound = ";
  4746. prin2!* coefftbd;
  4747. terpri!*(nil);
  4748. prin2!* "The product of factors over the integers is ";
  4749. printsf u0;
  4750. printstr "In each step below, the residue is U - (product of the";
  4751. printstr
  4752. "factors as far as we know them). The correction to each";
  4753. printstr "factor, f(i), is (a(i)*v) mod f0(i) where f0(i) is";
  4754. prin2!* "f(i) mod "; prin2!* p;
  4755. printstr "(ie. the f(i) used in calculating the a(i))"
  4756. >>>>
  4757. end;
  4758. symbolic procedure initialize!-hensel(r,p,poly,mvec,fvec,cbd);
  4759. % Set up the vectors and initialize the fluids.
  4760. begin scalar u0;
  4761. delfvec:=mkvect r;
  4762. facvec:=mkvect r;
  4763. hensel!-poly:=poly;
  4764. modfvec:=mvec;
  4765. factorvec:=fvec;
  4766. coefftbd:=cbd;
  4767. factors!-done:=nil;
  4768. deltam:=p;
  4769. u0:=1;
  4770. for i:=1:r do u0:=multf(getv(factorvec,i),u0);
  4771. current!-factor!-product:=u0;
  4772. return u0
  4773. end;
  4774. % symbolic procedure reset!-quadratic!-step!-fluids(poly,faclist,n);
  4775. % begin scalar i,om,modf;
  4776. % current!-factor!-product:=poly;
  4777. % om:=set!-modulus hensel!-growth!-size;
  4778. % i:=0;
  4779. % for each fac in faclist do <<
  4780. % putv(factorvec,i:=iadd1 i,fac);
  4781. % putv(modfvec,i,modf:=reduce!-mod!-p fac);
  4782. % putv(alphavec,i,cdr get!-alpha modf) >>;
  4783. % for i:=1:n do <<
  4784. % prin2 "F("; % prin2 i; % prin2 ") = ";
  4785. % printsf getv(factorvec,i);
  4786. % prin2 "F("; % prin2 i; % prin2 ") MOD P = ";
  4787. % printsf getv(modfvec,i);
  4788. % prin2 "A("; % prin2 i; % prin2 ") = ";
  4789. % printsf getv(alphavec,i) >>;
  4790. % set!-modulus om
  4791. % end;
  4792. symbolic procedure reset!-quadratic!-step!-fluids(poly,faclist,n);
  4793. begin scalar i,om,facpairlist,cfp!-mod!-p,fhatlist;
  4794. current!-factor!-product:=poly;
  4795. om:=set!-modulus hensel!-growth!-size;
  4796. cfp!-mod!-p:=reduce!-mod!-p current!-factor!-product;
  4797. i:=0;
  4798. facpairlist:=for each fac in faclist collect <<
  4799. i:= i #+ 1;
  4800. (fac . reduce!-mod!-p fac) >>;
  4801. fhatlist:=for each facc in facpairlist collect
  4802. quotfail!-mod!-p(cfp!-mod!-p,cdr facc);
  4803. if factors!-done then alphalist:=
  4804. find!-alphas!-in!-a!-ring(i,
  4805. for each facpr in facpairlist collect cdr facpr,
  4806. fhatlist,1);
  4807. % a bug has surfaced such that the alphas get out of step.
  4808. % In this case so recalculate them to stop the error for now.
  4809. i:=0;
  4810. for each facpair in facpairlist do <<
  4811. putv(factorvec,i:=iadd1 i,car facpair);
  4812. putv(modfvec,i,cdr facpair);
  4813. putv(alphavec,i,cdr get!-alpha cdr facpair) >>;
  4814. % for i:=1:n do <<
  4815. % prin2 "f("; % prin2 i; % prin2 ") = ";
  4816. % printsf getv(factorvec,i);
  4817. % prin2 "f("; % prin2 i; % prin2 ") mod p = ";
  4818. % printsf getv(modfvec,i);
  4819. % prin2 "a("; % prin2 i; % prin2 ") = ";
  4820. % printsf getv(alphavec,i) >>;
  4821. set!-modulus om
  4822. end;
  4823. symbolic procedure quadratic!-step(m,r);
  4824. % Code for adjusting the hensel variables to take quadratic steps in
  4825. % the growing process.
  4826. begin scalar w,s,cfp!-mod!-p;
  4827. set!-modulus m;
  4828. cfp!-mod!-p:=reduce!-mod!-p current!-factor!-product;
  4829. for i:=1:r do putv(facvec,i,reduce!-mod!-p getv(factorvec,i));
  4830. for i:=1:r do putv(fhatvec,i,
  4831. quotfail!-mod!-p(cfp!-mod!-p,getv(facvec,i)));
  4832. w:=form!-sum!-and!-product!-mod!-m(alphavec,fhatvec,r);
  4833. w:=!*mod2f plus!-mod!-p(1,minus!-mod!-p w);
  4834. s:=quotfail(w,deltam);
  4835. set!-modulus deltam;
  4836. s:=!*f2mod s;
  4837. % Boxes S up to look like a poly mod deltam.
  4838. for i:=1:r do <<
  4839. w:=remainder!-mod!-p(times!-mod!-p(s,getv(alphavec,i)),
  4840. getv(modfvec,i));
  4841. putv(alphavec,i,
  4842. addf(!*mod2f getv(alphavec,i),multf(!*mod2f w,deltam))) >>;
  4843. s:=modfvec;
  4844. modfvec:=facvec;
  4845. facvec:=s;
  4846. deltam:=m;
  4847. % this is our new growth rate.
  4848. set!-modulus deltam;
  4849. for i:=1:r do <<
  4850. putv(facvec,i,"RUBBISH");
  4851. % we will want to overwrite facvec next time so we
  4852. % had better point it to the old (no longer needed)
  4853. % modvec. Also mark it as containing rubbish for safety.
  4854. putv(alphavec,i,!*f2mod getv(alphavec,i)) >>;
  4855. % Make sure the alphas are boxed up as being mod new deltam.
  4856. if not !*overview then factor!-trace <<
  4857. printstr "The new modular polynomials are chosen such that:";
  4858. terpri();
  4859. prin2!* " a(1)*h(1) + ... + a(";
  4860. prin2!* r;
  4861. prin2!* ")*h("; prin2!* r;
  4862. prin2!* ") = 1 mod "; printstr m;
  4863. terpri();
  4864. printstr " where h(i)=(product of all f(j) [see below])/f(i)";
  4865. printstr " and degree of a(i) < degree of f(i).";
  4866. for i:=1:r do <<
  4867. prin2!* " a("; prin2!* i; prin2!* ")=";
  4868. printsf getv(alphavec,i);
  4869. prin2!* " f("; prin2!* i; prin2!* ")=";
  4870. printsf getv(modfvec,i) >>
  4871. >>
  4872. end;
  4873. symbolic procedure terms!-done(fvec,delfvec,m);
  4874. begin scalar flist,delflist;
  4875. for i:=1:number!-of!-factors do <<
  4876. flist:=getv(fvec,i) . flist;
  4877. delflist:=getv(delfvec,i) . delflist >>;
  4878. return terms!.done(number!-of!-factors,flist,delflist,
  4879. number!-of!-factors,m)
  4880. end;
  4881. symbolic procedure terms!.done(n,flist,delflist,r,m);
  4882. if n=1 then (car flist) . (car delflist)
  4883. else begin scalar k,i,f1,f2,delf1,delf2;
  4884. k:=n/2; i:=1;
  4885. for each f in flist do
  4886. << if i>k then f2:=(f . f2)
  4887. else f1:=(f . f1);
  4888. i:=i+1 >>;
  4889. i:=1;
  4890. for each delf in delflist do
  4891. << if i>k then delf2:=(delf . delf2)
  4892. else delf1:=(delf . delf1);
  4893. i:=i+1 >>;
  4894. f1:=terms!.done(k,f1,delf1,r,m);
  4895. delf1:=cdr f1; f1:=car f1;
  4896. f2:=terms!.done(n-k,f2,delf2,r,m);
  4897. delf2:=cdr f2; f2:=car f2;
  4898. delf1:=
  4899. addf(addf(
  4900. multf(f1,delf2),
  4901. multf(f2,delf1)),
  4902. multf(multf(delf1,m),delf2));
  4903. if n=r then return delf1;
  4904. return (multf(f1,f2) . delf1)
  4905. end;
  4906. symbolic procedure try!.combining(l,poly,m,sofar);
  4907. % l is a list of factors, f(i), s.t. (product of the f(i) mod m) = poly
  4908. % but no f(i) divides poly over the integers. We find the combinations
  4909. % of the f(i) that yield the true factors of poly over the integers.
  4910. % Sofar is a list of these factors found so far.
  4911. if poly=1 then
  4912. if null l then sofar
  4913. else errorf(list("TOO MANY BAD FACTORS:",l))
  4914. else begin scalar k,n,res,ff,v,w,w1,combined!.factors,ll;
  4915. n:=length l;
  4916. if n=1 then
  4917. if ldeg car l > (ldeg poly)/2 then
  4918. return ('one! bad! factor . sofar)
  4919. else errorf(list("ONE BAD FACTOR DOES NOT FIT:",l));
  4920. if n=2 or n=3 then <<
  4921. w:=lc cdar l; % The LC of all the factors is the same.
  4922. while not (w=lc poly) do poly:=quotfail(poly,w);
  4923. % poly's LC may be a higher power of w than we want
  4924. % and we must return a result with the same
  4925. % LC as each of the combined factors.
  4926. if not !*overview then factor!-trace <<
  4927. printstr "We combine:";
  4928. for each lf in l do printsf cdr lf;
  4929. prin2!* " mod "; prin2!* m;
  4930. printstr " to give correct factor:";
  4931. printsf poly >>;
  4932. combine!.alphas(l,t);
  4933. return (poly . sofar) >>;
  4934. ll:=for each ff in l collect (cdr ff . car ff);
  4935. k := 2;
  4936. loop1:
  4937. if k > n/2 then go to exit;
  4938. w:=koutof(k,if 2*k=n then cdr l else l,nil);
  4939. while w and (v:=factor!-trialdiv(poly,car w,m,ll))='didntgo do
  4940. << w:=cdr w;
  4941. while w and
  4942. ((car w = '!*lazyadjoin) or (car w = '!*lazykoutof)) do
  4943. if car w= '!*lazyadjoin then
  4944. w:=lazy!-adjoin(cadr w,caddr w,cadr cddr w)
  4945. else w:=koutof(cadr w,caddr w,cadr cddr w)
  4946. >>;
  4947. if not(v='didntgo) then <<
  4948. ff:=car v; v:=cdr v;
  4949. if not !*overview then factor!-trace <<
  4950. printstr "We combine:";
  4951. for each a in car w do printsf a;
  4952. prin2!* " mod "; prin2!* m;
  4953. printstr " to give correct factor:";
  4954. printsf ff >>;
  4955. for each a in car w do <<
  4956. w1:=l;
  4957. while not (a = cdar w1) do w1:=cdr w1;
  4958. combined!.factors:=car w1 . combined!.factors;
  4959. l:=delete(car w1,l) >>;
  4960. combine!.alphas(combined!.factors,t);
  4961. res:=try!.combining(l,v,m,ff . sofar);
  4962. go to exit>>;
  4963. k := k + 1;
  4964. go to loop1;
  4965. exit:
  4966. if res then return res
  4967. else <<
  4968. w:=lc cdar l; % The LC of all the factors is the same.
  4969. while not (w=lc poly) do poly:=quotfail(poly,w);
  4970. % poly's LC may be a higher power of w than we want
  4971. % and we must return a result with the same
  4972. % LC as each of the combined factors.
  4973. if not !*overview then factor!-trace <<
  4974. printstr "We combine:";
  4975. for each ff in l do printsf cdr ff;
  4976. prin2!* " mod "; prin2!* m;
  4977. printstr " to give correct factor:";
  4978. printsf poly >>;
  4979. combine!.alphas(l,t);
  4980. return (poly . sofar) >>
  4981. end;
  4982. symbolic procedure koutof(k,l,sofar);
  4983. % Produces all permutations of length k from list l accumulating them
  4984. % in sofar as we go. We use lazy evaluation in that this results in
  4985. % a permutation dotted with:
  4986. % ( '!*lazy . (argument for eval) )
  4987. % except when k=1 when the permutations are explicitly given.
  4988. if k=1 then append(
  4989. for each f in l collect list cdr f,sofar)
  4990. else if k>length l then sofar
  4991. else <<
  4992. while eqcar(l,'!*lazyadjoin) or eqcar(l,'!*lazykoutof) do
  4993. if car l='!*lazyadjoin then
  4994. l := lazy!-adjoin(cadr l,caddr l,cadr cddr l)
  4995. else l := koutof(cadr l,caddr l,cadr cddr l);
  4996. if k=length l then
  4997. (for each ll in l collect cdr ll ) . sofar
  4998. else koutof(k,cdr l,
  4999. list('!*lazyadjoin,cdar l,
  5000. list('!*lazykoutof,(k-1),cdr l,nil),
  5001. sofar)) >>;
  5002. symbolic procedure lazy!-adjoin(item,l,tail);
  5003. % Dots item with each element in l using lazy evaluation on l.
  5004. % If l is null tail results.
  5005. << while eqcar(l,'!*lazyadjoin) or eqcar(l,'!*lazykoutof) do
  5006. if car l ='!*lazyadjoin then
  5007. l:=lazy!-adjoin(cadr l,caddr l,cadr cddr l)
  5008. else l:=koutof(cadr l,caddr l,cadr cddr l);
  5009. if null l then tail
  5010. else (item . car l) .
  5011. if null cdr l then tail
  5012. else list('!*lazyadjoin,item,cdr l,tail) >>;
  5013. symbolic procedure factor!-trialdiv(poly,flist,m,llist);
  5014. % Combines the factors in FLIST mod M and test divides the result
  5015. % into POLY (over integers) to see if it goes. If it doesn't
  5016. % then DIDNTGO is returned, else the pair (D . Q) is
  5017. % returned where Q is the quotient obtained and D is the product
  5018. % of the factors mod M.
  5019. if polyzerop poly then errorf "Test dividing into zero?"
  5020. else begin scalar d,q;
  5021. d:=combine(flist,m,llist);
  5022. if didntgo(q:=quotf(poly,car d)) then <<
  5023. factor!-trace printstr " it didn't go (division fail)";
  5024. return 'didntgo >>
  5025. else <<
  5026. factor!-trace printstr " it worked !";
  5027. return (car d . quotf(q,cdr d)) >>
  5028. end;
  5029. symbolic procedure combine(flist,m,l);
  5030. % Multiply factors in flist mod m.
  5031. % L is a list of the factors for use in FACTOR!-TRACE.
  5032. begin scalar om,res,w,lcf,lcfinv,lcfprod;
  5033. factor!-trace <<
  5034. prin2!* "We combine factors ";
  5035. for each ff in flist do <<
  5036. w:=assoc(ff,l);
  5037. prin2!* "f(";
  5038. prin2!* cdr w;
  5039. prin2!* "), " >> ;
  5040. prin2!* "and try dividing : " >>;
  5041. lcf := lc car flist; % all leading coeffts should be the same.
  5042. lcfprod := 1;
  5043. % This is one of only two places in the entire factorizer where
  5044. % it is ever necessary to use a modulus larger than word-size.
  5045. if m>largest!-small!-modulus then <<
  5046. om:=set!-general!-modulus m;
  5047. lcfinv := general!-modular!-reciprocal lcf;
  5048. res:=general!-reduce!-mod!-p car flist;
  5049. for each ff in cdr flist do <<
  5050. if not lcf=lc ff then errorf "BAD LC IN FLIST";
  5051. res:=general!-times!-mod!-p(
  5052. general!-times!-mod!-p(lcfinv,
  5053. general!-reduce!-mod!-p ff),res);
  5054. lcfprod := lcfprod*lcf >>;
  5055. res:=general!-make!-modular!-symmetric res;
  5056. set!-modulus om;
  5057. return (res . lcfprod) >>
  5058. else <<
  5059. om:=set!-modulus m;
  5060. lcfinv := modular!-reciprocal lcf;
  5061. res:=reduce!-mod!-p car flist;
  5062. for each ff in cdr flist do <<
  5063. if not lcf=lc ff then errorf "BAD LC IN FLIST";
  5064. res:=times!-mod!-p(times!-mod!-p(lcfinv,reduce!-mod!-p ff),res);
  5065. lcfprod := lcfprod*lcf >>;
  5066. res:=make!-modular!-symmetric res;
  5067. set!-modulus om;
  5068. return (res . lcfprod) >>
  5069. end;
  5070. symbolic procedure combine!.alphas(flist,fixlcs);
  5071. % Combine the alphas associated with each of these factors to
  5072. % give the one alpha for their combination.
  5073. begin scalar f1,a1,ff,aa,oldm,lcfac,lcfinv,saveflist;
  5074. oldm:=set!-modulus hensel!-growth!-size;
  5075. flist:=for each fac in flist collect <<
  5076. saveflist:= (reduce!-mod!-p cdr fac) . saveflist;
  5077. (car fac) . car saveflist >>;
  5078. if fixlcs then <<
  5079. lcfinv:=modular!-reciprocal lc cdar flist;
  5080. lcfac:=modular!-expt(lc cdar flist,sub1 length flist)
  5081. >>
  5082. else << lcfinv:=1; lcfac:=1 >>;
  5083. % If FIXLCS is set then we have combined n factors
  5084. % (each with the same l.c.) to give one and we only need one
  5085. % l.c. in the result, we have divided the combination by
  5086. % lc**(n-1) and we must be sure to do the same for the
  5087. % alphas.
  5088. ff:=cdar flist;
  5089. aa:=cdr get!-alpha ff;
  5090. flist:=cdr flist;
  5091. while flist do <<
  5092. f1:=cdar flist;
  5093. a1:=cdr get!-alpha f1;
  5094. flist:=cdr flist;
  5095. aa:=plus!-mod!-p(times!-mod!-p(aa,f1),times!-mod!-p(a1,ff));
  5096. ff:=times!-mod!-p(ff,f1)
  5097. >>;
  5098. for each a in alphalist do
  5099. if not member(car a,saveflist) then
  5100. flist:=(car a . times!-mod!-p(cdr a,lcfac)) . flist;
  5101. alphalist:=(quotient!-mod!-p(ff, lcfac) . aa) . flist;
  5102. set!-modulus oldm
  5103. end;
  5104. % The following code is for dividing out factors in the middle
  5105. % of the Hensel construction and adjusting all the associated
  5106. % variables that go with it.
  5107. symbolic procedure adjust!-growth(facdone,k,m);
  5108. % One factor (at least) divides out so we can reconfigure the
  5109. % problem for Hensel constrn giving a smaller growth and hopefully
  5110. % reducing the coefficient bound considerably.
  5111. begin scalar w,u,bound!-scale,modflist,factorlist,fhatlist,
  5112. modfdone,b;
  5113. factorlist:=vec2list!-without!-k(factorvec,k);
  5114. modflist:=vec2list!-without!-k(modfvec,k);
  5115. fhatlist:=vec2list!-without!-k(fhatvec,k);
  5116. w:=number!-of!-factors;
  5117. modfdone:=getv(modfvec,k);
  5118. top:
  5119. factors!-done:=facdone . factors!-done;
  5120. if (number!-of!-factors:=number!-of!-factors #- 1)=1 then <<
  5121. factors!-done:=hensel!-poly . factors!-done;
  5122. number!-of!-factors:=0;
  5123. hensel!-poly:=1;
  5124. if not !*overview then factor!-trace <<
  5125. printstr " All factors found:";
  5126. for each fd in factors!-done do printsf fd >>;
  5127. return polyzero >>;
  5128. fhatlist:=for each fhat in fhatlist collect
  5129. quotfail!-mod!-p(if null fhat then polyzero else fhat,modfdone);
  5130. u:=comfac facdone; % Take contents and prim. parts.
  5131. if car u then
  5132. errorf(list("Factor divisible by main variable: ",facdone,car u));
  5133. facdone:=quotfail(facdone,cdr u);
  5134. bound!-scale:=cdr u;
  5135. if not((b:=lc facdone)=1) then begin scalar b!-inv,old!-m;
  5136. hensel!-poly:=quotfail(hensel!-poly,b**number!-of!-factors);
  5137. b!-inv:=modular!-reciprocal modular!-number b;
  5138. modflist:=for each modf in modflist collect
  5139. times!-mod!-p(b!-inv,modf);
  5140. % This is one of only two places in the entire factorizer where
  5141. % it is ever necessary to use a modulus larger than word-size.
  5142. if m>largest!-small!-modulus then <<
  5143. old!-m:=set!-general!-modulus m;
  5144. factorlist:=for each facc in factorlist collect
  5145. adjoin!-term(lpow facc,quotfail(lc facc,b),
  5146. general!-make!-modular!-symmetric(
  5147. general!-times!-mod!-p(
  5148. general!-modular!-reciprocal general!-modular!-number b,
  5149. general!-reduce!-mod!-p red facc))) >>
  5150. else <<
  5151. old!-m:=set!-modulus m;
  5152. factorlist:=for each facc in factorlist collect
  5153. adjoin!-term(lpow facc,quotfail(lc facc,b),
  5154. make!-modular!-symmetric(
  5155. times!-mod!-p(modular!-reciprocal modular!-number b,
  5156. reduce!-mod!-p red facc))) >>;
  5157. % We must be careful not to destroy the information
  5158. % that we have about the leading coefft.
  5159. set!-modulus old!-m;
  5160. fhatlist:=for each fhat in fhatlist collect
  5161. times!-mod!-p(
  5162. modular!-expt(b!-inv,number!-of!-factors #- 1),fhat)
  5163. end;
  5164. try!-another!-factor:
  5165. if (w:=w #- 1)>0 then
  5166. if not didntgo
  5167. (u:=quotf(hensel!-poly,facdone:=car factorlist)) then <<
  5168. hensel!-poly:=u;
  5169. factorlist:=cdr factorlist;
  5170. modfdone:=car modflist;
  5171. modflist:=cdr modflist;
  5172. fhatlist:=cdr fhatlist;
  5173. goto top >>
  5174. else <<
  5175. factorlist:=append(cdr factorlist,list car factorlist);
  5176. modflist:=append(cdr modflist,list car modflist);
  5177. fhatlist:=append(cdr fhatlist,list car fhatlist);
  5178. goto try!-another!-factor >>;
  5179. set!-fluids!-for!-newhensel(factorlist,fhatlist,modflist);
  5180. bound!-scale:=
  5181. bound!-scale * get!-coefft!-bound(
  5182. quotfail(hensel!-poly,bound!-scale**(number!-of!-factors #- 1)),
  5183. ldeg hensel!-poly);
  5184. % We expect the new coefficient bound to be smaller, but on
  5185. % dividing out a factor our polynomial's height may have grown
  5186. % more than enough to compensate in the bound formula for
  5187. % the drop in degree. Anyway, the bound we computed last time
  5188. % will still be valid, so let's stick with the smaller.
  5189. if bound!-scale < coefftbd then coefftbd := bound!-scale;
  5190. w:=quotfail(addf(hensel!-poly,negf current!-factor!-product),
  5191. m/deltam);
  5192. if not !*overview then factor!-trace <<
  5193. printstr " Factors found to be correct:";
  5194. for each fd in factors!-done do
  5195. printsf fd;
  5196. printstr "Remaining factors are:";
  5197. printvec(" f(",number!-of!-factors,") = ",factorvec);
  5198. prin2!* "New coefficient bound is "; printstr coefftbd;
  5199. prin2!* " and the residue is now "; printsf w >>;
  5200. return w
  5201. end;
  5202. symbolic procedure vec2list!-without!-k(v,k);
  5203. % Turn a vector into a list leaving out Kth element.
  5204. begin scalar w;
  5205. for i:=1:number!-of!-factors do
  5206. if not(i=k) then w:=getv(v,i) . w;
  5207. return w
  5208. end;
  5209. symbolic procedure set!-fluids!-for!-newhensel(flist,fhatlist,modflist);
  5210. << current!-factor!-product:=1;
  5211. alphalist:=
  5212. find!-alphas!-in!-a!-ring(number!-of!-factors,modflist,fhatlist,1);
  5213. for i:=number!-of!-factors step -1 until 1 do <<
  5214. putv(factorvec,i,car flist);
  5215. putv(modfvec,i,car modflist);
  5216. putv(fhatvec,i,car fhatlist);
  5217. putv(alphavec,i,cdr get!-alpha car modflist);
  5218. current!-factor!-product:=multf(car flist,current!-factor!-product);
  5219. flist:=cdr flist;
  5220. modflist:=cdr modflist;
  5221. fhatlist:=cdr fhatlist >>
  5222. >>;
  5223. symbolic procedure set!-hensel!-fluids!-back p;
  5224. % After the Hensel growth we must be careful to set back any fluids
  5225. % that have been changed when we divided out a factor in the middle
  5226. % of growing. Since calculating the alphas involves modular division
  5227. % we cannot do it mod DELTAM which is generally a non-trivial power of
  5228. % P (prime). So we calculate them mod P and if necessary we can do a
  5229. % few quadratic growth steps later.
  5230. begin scalar n,fd,modflist,fullf,modf;
  5231. set!-modulus p;
  5232. deltam:=p;
  5233. n:=number!-of!-factors #+ length (fd:=factors!-done);
  5234. current!-factor!-product:=hensel!-poly;
  5235. for i:=(number!-of!-factors #+ 1):n do <<
  5236. putv(factorvec,i,fullf:=car fd);
  5237. putv(modfvec,i,modf:=reduce!-mod!-p fullf);
  5238. current!-factor!-product:=multf(fullf,current!-factor!-product);
  5239. modflist:=modf . modflist;
  5240. fd:=cdr fd >>;
  5241. for i:=1:number!-of!-factors do <<
  5242. modf:=reduce!-mod!-p !*mod2f getv(modfvec,i);
  5243. % need to 'unbox' a modpoly before reducing it mod p as we
  5244. % know that the input modpoly is wrt a larger modulus
  5245. % (otherwise this would be a stupid thing to do anyway!)
  5246. % and so we are just pretending it is a full poly.
  5247. modflist:=modf . modflist;
  5248. putv(modfvec,i,modf) >>;
  5249. alphalist:=alphas(n,modflist,1);
  5250. for i:=1:n do putv(alphavec,i,cdr get!-alpha getv(modfvec,i));
  5251. number!-of!-factors:=n
  5252. end;
  5253. endmodule;
  5254. end;