int.red 151 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800
  1. module int!-intro; % General support for REDUCE integrator.
  2. % Authors: A. C. Norman and P. M. A. Moore.
  3. % Modified by: J. Davenport, J. P. Fitch, A. C. Hearn.
  4. % Note that at one point, INT had been flagged SIMP0FN. However, that
  5. % lead to problems when the arguments of INT contained pattern
  6. % variables.
  7. fluid '(!*conscount !*noextend !*pvar gaussiani);
  8. global '(btrlevel frlis!* gensymcount initl!*);
  9. !*conscount:=10000; % default maximum number of conses in certain
  10. % operations.
  11. !*pvar:='!_a;
  12. btrlevel := 5; %default to a reasonably full backtrace.
  13. % The next smacro is needed at this point to define gaussiani.
  14. symbolic smacro procedure !*kk2f u; !*p2f mksp(u,1);
  15. gaussiani := !*kk2f '(sqrt -1);
  16. gensymcount := 0;
  17. initl!* := append('(!*noextend), initl!*);
  18. flag('(interr),'transfer); %For the compiler;
  19. flag ('(atan dilog erf expint expt log tan),'transcendental);
  20. comment Kludge to define derivative of an integral and integral of
  21. a derivative;
  22. frlis!* := union('(!=x !=y),frlis!*);
  23. put('df,'opmtch,'(((int !=y !=x) !=x) (nil . t)
  24. (evl!* !=y) nil) . get('df,'opmtch));
  25. put('int,'opmtch,'(((df !=y !=x) !=x) (nil . t)
  26. (evl!* !=y) nil) . get('int,'opmtch));
  27. put('evl!*,'opmtch,'(((!=x) (nil . t) !=x nil)));
  28. put('evl!*,'simpfn,'simpiden);
  29. %Various functions used throughout the integrator.
  30. smacro procedure !*kk2q a; ((mksp(a,1) .* 1) .+ nil) ./ 1;
  31. symbolic smacro procedure divsf(u,v); sqrt2top(u ./ v);
  32. symbolic procedure flatten u;
  33. if null u then nil
  34. else if atom u then list u
  35. else if atom car u then car u . flatten cdr u
  36. else nconc(flatten car u,flatten cdr u);
  37. symbolic procedure int!-gensym1 u;
  38. << gensymcount:=gensymcount+1;
  39. compress append(explode u,explode gensymcount) >>;
  40. symbolic smacro procedure maninp(u,v,w);
  41. interr "MANINP called -- not implemented";
  42. symbolic procedure mknill n; if n=0 then nil else nil . mknill(n-1);
  43. % Various selectors written as macros.
  44. smacro procedure argof u;
  45. % Argument of a unary function.
  46. cadr u;
  47. smacro procedure firstsubs u;
  48. % The first substitution in a substitution list.
  49. car u;
  50. smacro procedure lsubs u; car u;
  51. smacro procedure rsubs u; cdr u;
  52. smacro procedure lfirstsubs u; caar u;
  53. smacro procedure rfirstsubs u; cdar u;
  54. put('nthroot,'simpfn,'simpiden);
  55. % The binary n-th root operator nthroot(x,2)=sqrt(x)
  56. % no simplification is used here.
  57. % Hope is that pbuild introduces it, and simplog removes it.
  58. % Selectors for the taylor series structure.
  59. % Format is:
  60. %function.((first.last computed so far) . assoc list of computed terms).
  61. % ***store-hack-1***:
  62. % remove this macro if more store is available.
  63. smacro procedure tayshorten u;nil;
  64. smacro procedure taylordefn u; car u;
  65. symbolic smacro procedure taylorfunction u; caar u;
  66. smacro procedure taylornumbers u; cadr u;
  67. smacro procedure taylorfirst u; caadr u;
  68. smacro procedure taylorlast u; cdadr u;
  69. smacro procedure taylorlist u; cddr u;
  70. smacro procedure taylormake(fn,nums,alist); fn.(nums.alist);
  71. endmodule;
  72. module contents;
  73. % Authors: Mary Ann Moore and Arthur C. Norman
  74. fluid '(clogflag content indexlist sqfr varlist zlist);
  75. exports contents,contentsmv,dfnumr,difflogs,factorlistlist,multsqfree,
  76. multup,sqfree,sqmerge;
  77. imports int!-fac,fquotf,gcdf,interr,!*multf,partialdiff,quotf,ordop,
  78. addf,negf,domainp,difff,mksp,negsq,invsq,addsq,!*multsq,diffsq;
  79. comment we assume no power substitution is necessary in this module;
  80. symbolic procedure contents(p,v);
  81. % Find the contents of the polynomial p wrt variable v;
  82. % Note that v may not be the main variable of p;
  83. if domainp(p) then p
  84. else if v=mvar p then contentsmv(p,v,nil)
  85. else if ordop(v,mvar p) then p
  86. else contentsmv(makemainvar(p,v),v,nil);
  87. symbolic procedure contentsmv(p,v,sofar);
  88. % Find contents of polynomial P;
  89. % V is main variable of P;
  90. % SOFAR is partial result;
  91. if sofar=1 then 1
  92. else if domainp p then gcdf(p,sofar)
  93. else if not v=mvar p then gcdf(p,sofar)
  94. else contentsmv(red p,v,gcdf(lc p,sofar));
  95. symbolic procedure makemainvar(p,v);
  96. % Bring v up to be the main variable in polynomial p;
  97. % Note that the reconstructed p must be used with care since;
  98. % it does not conform to the normal reduce ordering rules;
  99. if domainp p then p
  100. else if v=mvar p then p
  101. else mergeadd(mulcoeffsby(makemainvar(lc p,v),lpow p,v),
  102. makemainvar(red p,v),v);
  103. symbolic procedure mulcoeffsby(p,pow,v);
  104. % Multiply each coefficient in p by the standard power pow;
  105. if null p then nil
  106. else if domainp p or not v=mvar p then ((pow .* p) .+ nil)
  107. else (lpow p .* ((pow .* lc p) .+ nil)) .+ mulcoeffsby(red p,pow,v);
  108. symbolic procedure mergeadd(a,b,v);
  109. % Add polynomials a and b given that they have same main variable v;
  110. if domainp a or not v=mvar a then
  111. if domainp b or not v=mvar b then addf(a,b)
  112. else lt b .+ mergeadd(a,red b,v)
  113. else if domainp b or not v=mvar b then
  114. lt a .+ mergeadd(red a,b,v)
  115. else (lambda xc;
  116. if xc=0 then (lpow a .* addf(lc a,lc b)) .+
  117. mergeadd(red a,red b,v)
  118. else if xc>0 then lt a .+ mergeadd(red a,b,v)
  119. else lt b .+ mergeadd(a,red b,v))
  120. (tdeg lt a-tdeg lt b);
  121. symbolic procedure sqfree(p,vl);
  122. if (null vl) or (domainp p) then
  123. <<content:=p; nil>>
  124. else begin scalar w,v,dp,gg,pg,dpg,p1,w1;
  125. w:=contents(p,car vl); % content of p ;
  126. p:=quotf(p,w); % make p primitive;
  127. w:=sqfree(w,cdr vl); % process content by recursion;
  128. if p=1 then return w;
  129. v:=car vl; % pick out variable from list;
  130. while not (p=1) do <<
  131. dp:=partialdiff(p,v);
  132. gg:=gcdf(p,dp);
  133. pg:=quotf(p,gg);
  134. dpg:=negf partialdiff(pg,v);
  135. p1:=gcdf(pg,addf(quotf(dp,gg),dpg));
  136. w1:=p1.w1;
  137. p:=gg>>;
  138. return sqmerge(reverse w1,w,t)
  139. end;
  140. symbolic procedure sqmerge(w1,w,simplew1);
  141. % w and w1 are lists of factors of each power. if simplew1 is true
  142. % then w1 contains only single factors for each power. ;
  143. if null w1 then w
  144. else if null w then if car w1=1 then nil.sqmerge(cdr w1,w,simplew1)
  145. else (if simplew1 then list car w1 else car w1).
  146. sqmerge(cdr w1,w,simplew1)
  147. else if car w1=1 then (car w).sqmerge(cdr w1,cdr w,simplew1) else
  148. append(if simplew1 then list car w1 else car w1,car w).
  149. sqmerge(cdr w1,cdr w,simplew1);
  150. symbolic procedure multup l;
  151. % l is a list of s.f.'s. result is s.f. for product of elements of l;
  152. begin scalar res;
  153. res:=1;
  154. while not null l do <<
  155. res:=multf(res,car l);
  156. l:=cdr l >>;
  157. return res
  158. end;
  159. symbolic procedure diflist(l,cl,x,rl);
  160. % Differentiates l (list of s.f.'s) wrt x to produce the sum of
  161. % terms for the derivative of numr of 1st part of answer. cl is
  162. % coefficient list (s.f.'s) & rl is list of derivatives we have
  163. % dealt with so far. Result is s.q.;
  164. if null l then nil ./ 1
  165. else begin scalar temp;
  166. temp:=!*multf(multup rl,multup cdr l);
  167. temp:=!*multsq(difff(car l,x),!*f2q temp);
  168. temp:=!*multsq(temp,(car cl) ./ 1);
  169. return addsq(temp,diflist(cdr l,cdr cl,x,(car l).rl))
  170. end;
  171. symbolic procedure multsqfree w;
  172. % W is list of sqfree factors. result is product of each LIST IN W
  173. % to give one polynomial for each sqfree power;
  174. if null w then nil
  175. else (multup car w).multsqfree cdr w;
  176. symbolic procedure l2lsf l;
  177. % L is a list of kernels. result is a list of same members as s.f.'s;
  178. if null l then nil
  179. else ((mksp(car l,1) .* 1) .+ nil).l2lsf cdr l;
  180. symbolic procedure dfnumr(x,dl);
  181. % Gives the derivative of the numr of the 1st part of answer.
  182. % dl is list of any exponential or 1+tan**2 that occur in integrand
  183. % denr. these are divided out from result before handing it back.
  184. % result is s.q., ready for printing.
  185. begin scalar temp1,temp2,coeflist,qlist,count;
  186. if not null sqfr then <<
  187. count:=0;
  188. qlist:=cdr sqfr;
  189. coeflist:=nil;
  190. while not null qlist do <<
  191. count:=count+1;
  192. coeflist:=count.coeflist;
  193. qlist:=cdr qlist >>;
  194. coeflist:=reverse coeflist >>;
  195. temp1:=!*multsq(diflist(l2lsf zlist,l2lsf indexlist,x,nil),
  196. !*f2q multup sqfr);
  197. if not null sqfr and not null cdr sqfr then <<
  198. temp2:=!*multsq(diflist(cdr sqfr,coeflist,x,nil),
  199. !*f2q multup l2lsf zlist);
  200. temp2:=!*multsq(temp2,(car sqfr) ./ 1) >>
  201. else temp2:=nil ./ 1;
  202. temp1:=addsq(temp1,negsq temp2);
  203. temp2:=cdr temp1;
  204. temp1:=car temp1;
  205. qlist:=nil;
  206. while not null dl do <<
  207. if not car dl member qlist then qlist:=(car dl).qlist;
  208. dl:=cdr dl >>;
  209. while not null qlist do <<
  210. temp1:=quotf(temp1,car qlist);
  211. qlist:=cdr qlist >>;
  212. return temp1 ./ temp2
  213. end;
  214. symbolic procedure difflogs(ll,denm1,x);
  215. % LL is list of log terms (with coeffts), den is common denominator
  216. % over which they are to be put. Result is s.q. for derivative of all
  217. % these wrt x.
  218. if null ll then nil ./ 1
  219. else begin scalar temp,qu,cvar,logoratan,arg;
  220. logoratan:=caar ll;
  221. cvar:=cadar ll;
  222. arg:=cddar ll;
  223. temp:=!*multsq(cvar ./ 1,diffsq(arg,x));
  224. if logoratan='iden then qu:=1 ./ 1
  225. else if logoratan='log then qu:=arg
  226. else if logoratan='atan then qu:=addsq(1 ./ 1,!*multsq(arg,arg))
  227. else interr "Logoratan=? in difflogs";
  228. %Note call to special division routine;
  229. qu:=fquotf(!*multf(!*multf(denm1,numr temp),
  230. denr qu),numr qu);
  231. %*MUST* GO EXACTLY;
  232. temp:=!*multsq(!*invsq (denr temp ./ 1),qu);
  233. %result of fquotf is a s.q;
  234. return !*addsq(temp,difflogs(cdr ll,denm1,x))
  235. end;
  236. symbolic procedure factorlistlist (w,clogflag);
  237. % W is list of lists of sqfree factors in s.f. result is list of log
  238. % terms required for integral answer. the arguments for each log fn
  239. % are in s.q.;
  240. begin scalar res,x,y;
  241. while not null w do <<
  242. x:=car w;
  243. while not null x do <<
  244. y:=facbypp(car x,varlist);
  245. while not null y do <<
  246. res:=append(int!-fac car y,res);
  247. y:=cdr y >>;
  248. x:=cdr x >>;
  249. w:=cdr w >>;
  250. return res
  251. end;
  252. symbolic procedure facbypp(p,vl);
  253. % Use contents/primitive parts to try to factor p.
  254. if null vl then list p
  255. else begin scalar princilap!-part,co;
  256. co:=contents(p,car vl);
  257. vl:=cdr vl;
  258. if co=1 then return facbypp(p,vl); %this var no help.
  259. princilap!-part:=quotf(p,co); %primitive part.
  260. if princilap!-part=1 then return facbypp(p,vl); %again no help;
  261. return nconc(facbypp(princilap!-part,vl),facbypp(co,vl))
  262. end;
  263. endmodule;
  264. module csolve; % routines to do with the C constants.
  265. % Author: John P. Fitch.
  266. fluid '(ccount cmap cmatrix cval loglist neweqn);
  267. global '(!*trint);
  268. exports backsubst4cs,createcmap,findpivot,printspreadc,printvecsq,
  269. spreadc,subst4eliminateds;
  270. imports nth,interr,!*multf,printsf,printsq,quotf,putv,negf,invsq,
  271. negsq,addsq,multsq,mksp,addf,domainp,pnth;
  272. symbolic procedure findpivot cvec;
  273. % Finds first non-zero element in CVEC and returns its cell number.
  274. % If no such element exists, result is nil.
  275. begin scalar i,x;
  276. i:=1;
  277. x:=getv(cvec,i);
  278. while i<ccount and null x do
  279. << i:=i+1;
  280. x:=getv(cvec,i) >>;
  281. if null x then return nil;
  282. return i
  283. end;
  284. symbolic procedure subst4eliminatedcs(neweqn,substorder,ceqns);
  285. % Substitutes into NEWEQN for all the C's that have been eliminated so
  286. % far. These are given by CEQNS. SUBSTORDER gives the order of
  287. % substitution as well as the constant multipliers. Result is the
  288. % transformed NEWEQN.
  289. if null substorder then neweqn
  290. else begin scalar nxt,row,cvar,temp;
  291. row:=car ceqns;
  292. nxt:=car substorder;
  293. if null (cvar:=getv(neweqn,nxt)) then
  294. return subst4eliminatedcs(neweqn,cdr substorder,cdr ceqns);
  295. nxt:=getv(row,nxt);
  296. for i:=0 : ccount do
  297. << temp:=!*multf(nxt,getv(neweqn,i));
  298. temp:=addf(temp,negf !*multf(cvar,getv(row,i)));
  299. putv(neweqn,i,temp) >>;
  300. return subst4eliminatedcs(neweqn,cdr substorder,cdr ceqns)
  301. end;
  302. symbolic procedure backsubst4cs(cs2subst,cs2solve,cmatrix);
  303. % Solves the C-eqns and sets vector CVAL to the C-constant values
  304. % CMATRIX is a list of matrix rows for C-eqns after Gaussian
  305. % elimination has been performed. CS2SOLVE is a list of the remaining
  306. % C's to evaluate and CS2SUBST are the C's we have evaluated already.
  307. if null cmatrix then nil
  308. else begin scalar eqnn,cvar,already,substlist,temp,temp2;
  309. eqnn:=car cmatrix;
  310. cvar:=car cs2solve;
  311. already:=nil ./ 1; % The S.Q. nil.
  312. substlist:=cs2subst;
  313. % Now substitute for previously evaluated c's:
  314. while not null substlist do
  315. << temp:=car substlist;
  316. if not null getv(eqnn,temp) then
  317. already:=addsq(already,multsq(getv(eqnn,temp) ./ 1,
  318. getv(cval,temp)));
  319. substlist:=cdr substlist >>;
  320. % Now solve for the c given by cvar (any remaining c's assumed zero).
  321. temp:=negsq addsq(getv(eqnn,0) ./ 1,already);
  322. if not null (temp2:=quotf(numr temp,getv(eqnn,cvar))) then
  323. temp:=temp2 ./ denr temp
  324. else temp:=multsq(temp,invsq(getv(eqnn,cvar) ./ 1));
  325. if not null numr temp then putv(cval,cvar,
  326. resimp rootextractsq subs2q temp);
  327. backsubst4cs(reversewoc(cvar . reversewoc cs2subst),
  328. cdr cs2solve,cdr cmatrix)
  329. end;
  330. %**********************************************************************
  331. % Routines to deal with linear equations for the constants C.
  332. %**********************************************************************
  333. symbolic procedure createcmap;
  334. %Sets LOGLIST to list of things of form (LOG C-constant f), where f is
  335. % function linear in one of the z-variables and C-constant is in S.F.
  336. % When creating these C-constant names, the CMAP is also set up and
  337. % returned as the result.
  338. begin scalar i,l,c;
  339. l:=loglist;
  340. i:=1;
  341. while not null l do <<
  342. c:=(int!-gensym1('c) . i) . c;
  343. i:=i+1;
  344. rplacd(car l,((mksp(caar c,1) .* 1) .+ nil) . cdar l);
  345. l:=cdr l >>;
  346. if !*trint then printc ("Constants Map" . c);
  347. return c
  348. end;
  349. symbolic procedure spreadc(eqnn,cvec1,w);
  350. % Sets a vector 'cvec1' to coefficients of c<i> in eqnn.
  351. if domainp eqnn then putv(cvec1,0,addf(getv(cvec1,0),
  352. !*multf(eqnn,w)))
  353. else begin scalar mv,t1,t2;
  354. spreadc(red eqnn,cvec1,w);
  355. mv:=mvar eqnn;
  356. t1:=assoc(mv,cmap); %tests if it is a c var.
  357. if not null t1 then return <<
  358. t1:=cdr t1; %loc in vector for this c.
  359. if not (tdeg lt eqnn=1) then interr "Not linear in c eqn";
  360. t2:=addf(getv(cvec1,t1),!*multf(w,lc eqnn));
  361. putv(cvec1,t1,t2) >>;
  362. t1:=((lpow eqnn) .* 1) .+ nil; %this main var as sf.
  363. spreadc(lc eqnn,cvec1,!*multf(w,t1))
  364. end;
  365. symbolic procedure printspreadc cvec1;
  366. begin
  367. for i:=0 : ccount do <<
  368. prin2 i;
  369. printc ":";
  370. printsf(getv(cvec1,i)) >>;
  371. printc "End of printspreadc output"
  372. end;
  373. %symbolic procedure printvecsq cvec;
  374. %% Print contents of cvec which contains s.q.'s (not s.f.'s).
  375. %% Starts from cell 1 not 0 as above routine (printspreadc).
  376. % begin
  377. % for i:=1 : ccount do <<
  378. % prin2 i;
  379. % printc ":";
  380. % if null getv(cvec,i) then printc "0"
  381. % else printsq(getv(cvec,i)) >>;
  382. % printc "End of printvecsq output"
  383. % end;
  384. endmodule;
  385. module cuberoot; % Cube roots of standard forms.
  386. % Authors: Mary Ann Moore and Arthur C. Norman.
  387. fluid '(cuberootflag);
  388. exports cuberootdf;
  389. imports contentsmv,gcdf,!*multf,nrootn,partialdiff,printdf,quotf,vp2,
  390. mksp,mk!*sq,domainp;
  391. symbolic procedure cuberootsq a;
  392. cuberootf numr a ./ cuberootf denr a;
  393. symbolic procedure cuberootf p;
  394. begin scalar ip,qp;
  395. if null p then return nil;
  396. ip:=cuberootf1 p;
  397. qp:=cdr ip;
  398. ip:=car ip; %respectable and nasty parts of the cuberoot.
  399. if numberp qp and onep qp then return ip; %exact root found.
  400. qp:=list('expt,prepf qp,'(quotient 1 3));
  401. cuberootflag:=t; %symbolic cube-root introduced.
  402. qp:=(mksp(qp,1).* 1) .+ nil;
  403. return !*multf(ip,qp)
  404. end;
  405. symbolic procedure cuberootf1 p;
  406. % Returns a . b with p=a**2*b.
  407. % Does this need power reduction?
  408. if domainp p then nrootn(p,3)
  409. else begin scalar co,ppp,g,pg;
  410. co:=contentsmv(p,mvar p,nil); %contents of p.
  411. ppp:=quotf(p,co); %primitive part.
  412. % now consider ppp=p1*p2**2*p3**3*p4**4*...
  413. co:=cuberootf1(co); %process contents via recursion.
  414. g:=gcdf(ppp,partialdiff(ppp,mvar ppp));
  415. % g=p2*p3**2*p4**3*...
  416. if not domainp g then <<
  417. pg:=quotf(ppp,g);
  418. %pg=p1*p2*p3*p4*...
  419. g:=gcdf(g,partialdiff(g,mvar g));
  420. % g=g3*g4**2*g5**3*...
  421. g:=gcdf(g,pg)>>; %a triple factor of ppp.
  422. if domainp g then pg:=1 . ppp
  423. else <<
  424. pg:=quotf(ppp,!*multf(g,!*multf(g,g))); %what's left.
  425. pg:=cuberootf1 pg; %split that up.
  426. rplaca(pg,!*multf(car pg,g))>>;
  427. %put in the thing found here.
  428. rplaca(pg,!*multf(car pg,car co));
  429. rplacd(pg,!*multf(cdr pg,cdr co));
  430. return pg
  431. end;
  432. endmodule;
  433. module idepend; % Routines for considering dependency among variables.
  434. % Authors: Mary Ann Moore and Arthur C. Norman.
  435. fluid '(taylorvariable);
  436. exports dependspl,dependsp,involvesq,involvsf;
  437. imports taylorp,domainp;
  438. symbolic procedure dependsp(x,v);
  439. if null v then t
  440. else if depends(x,v) then x
  441. else if atom x then if x eq v then x else nil
  442. else if car x = '!*sq then involvesq(cadr x,v)
  443. else if taylorp x
  444. then if v eq taylorvariable then taylorvariable else nil
  445. else begin scalar w;
  446. if x=v then return v;
  447. % Check if a prefix form expression depends on the variable v.
  448. % Note this assumes the form x is in normal prefix notation;
  449. w := x; % preserve the dependency;
  450. x := cdr x; % ready to recursively check arguments;
  451. scan: if null x then return nil; % no dependency found;
  452. if dependsp(car x,v) then return w;
  453. x:=cdr x;
  454. go to scan
  455. end;
  456. symbolic procedure involvesq(sq,term);
  457. involvesf(numr sq,term) or involvesf(denr sq,term);
  458. symbolic procedure involvesf(sf,term);
  459. if domainp sf or null sf then nil
  460. else dependsp(mvar sf,term)
  461. or involvesf(lc sf,term)
  462. or involvesf(red sf,term);
  463. symbolic procedure dependspl(dep!-list,var);
  464. % True if any member of deplist (a list of prefix forms) depends on
  465. % var.
  466. dep!-list
  467. and (dependsp(car dep!-list,var) or dependspl(cdr dep!-list,var));
  468. symbolic procedure taylorp exxpr;
  469. % Sees if a random entity is a taylor expression.
  470. not atom exxpr
  471. and not atom car exxpr
  472. and flagp(taylorfunction exxpr,'taylor);
  473. endmodule;
  474. module df2q; % Conversion from distributive to standard forms.
  475. % Authors: Mary Ann Moore and Arthur C. Norman.
  476. fluid '(indexlist zlist);
  477. exports df2q;
  478. imports addf,gcdf,mksp,!*multf,quotf;
  479. comment We assume that results already have reduced powers, so
  480. that no power substitution is necessary;
  481. symbolic procedure df2q p;
  482. % Converts distributed form P to standard quotient;
  483. begin scalar n,d,gg,w;
  484. if null p then return nil ./ 1;
  485. d:=denr lc p;
  486. w:=red p;
  487. while not null w do <<
  488. gg:=gcdf(d,denr lc w); %get denominator of answer...
  489. d:=!*multf(d,quotf(denr lc w,gg));
  490. %..as lcm of denoms in input
  491. w:=red w >>;
  492. n:=nil; %place to build numerator of answer
  493. while not null p do <<
  494. n:=addf(n,!*multf(xl2f(lpow p,zlist,indexlist),
  495. !*multf(numr lc p,quotf(d,denr lc p))));
  496. p:=red p >>;
  497. return n ./ d
  498. end;
  499. symbolic procedure xl2f(l,z,il);
  500. % L is an exponent list from a D.F., Z is the Z-list,
  501. % IL is the list of indices.
  502. % Value is L converted to standard form. ;
  503. if null z then 1
  504. else if car l=0 then xl2f(cdr l,cdr z,cdr il)
  505. else if not atom car l then
  506. begin scalar temp;
  507. if caar l=0 then temp:= car il
  508. else temp:=list('plus,car il,caar l);
  509. temp:=mksp(list('expt,car z,temp),1);
  510. return !*multf(((temp .* 1) .+ nil),
  511. xl2f(cdr l,cdr z,cdr il))
  512. end
  513. % else if minusp car l then ;
  514. % multsq(invsq (((mksp(car z,-car l) .* 1) .+ nil)), ;
  515. % xl2f(cdr l,cdr z,cdr il)) ;
  516. else !*multf((mksp(car z,car l) .* 1) .+ nil,
  517. xl2f(cdr l,cdr z,cdr il));
  518. endmodule;
  519. module distrib; % Routines for manipulating distributed forms.
  520. % Authors: Mary Ann Moore and Arthur C. Norman.
  521. fluid '(indexlist sqrtlist zlist);
  522. exports dfprintform,multbyarbpowers,negdf,quotdfconst,sub1ind,vp1,
  523. vp2,plusdf,multdf,multdfconst,orddf;
  524. imports interr,addsq,negsq,exptsq,simp,domainp,mk!*sq,addf,
  525. multsq,invsq,minusp,mksp,sub1;
  526. %***********************************************************************
  527. % NOTE: The expressions lt,red,lc,lpow have been used on distributed
  528. % forms as the latter's structure is sufficiently similar to
  529. % s.f.'s. However lc df is a s.q. not a s.f. and lpow df is a
  530. % list of the exponents of the variables. This also makes
  531. % lt df different. Red df is d.f. as expected.
  532. %**********************************************************************;
  533. symbolic procedure plusdf(u,v);
  534. % U and V are D.F.'s. Value is D.F. for U+V;
  535. if null u then v
  536. else if null v then u
  537. else if lpow u=lpow v then
  538. (lambda(x,y); if null numr x then y else (lpow u .* x) .+ y)
  539. (!*addsq(lc u,lc v),plusdf(red u,red v))
  540. else if orddf(lpow u,lpow v) then lt u .+ plusdf(red u,v)
  541. else (lt v) .+ plusdf(u,red v);
  542. symbolic procedure orddf(u,v);
  543. % U and V are the LPOW of a D.F. - i.e. the list of exponents ;
  544. % Value is true if LPOW U '>' LPOW V and false otherwise ;
  545. if null u then if null v then interr "Orddf = case"
  546. else interr "Orddf v longer than u"
  547. else if null v then interr "Orddf u longer than v"
  548. else if exptcompare(car u,car v) then t
  549. else if exptcompare(car v,car u) then nil
  550. else orddf(cdr u,cdr v);
  551. symbolic procedure exptcompare(x,y);
  552. if atom x then if atom y then x>y else nil
  553. else if atom y then t
  554. else car x > car y;
  555. symbolic procedure negdf u;
  556. if null u then nil
  557. else (lpow u .* negsq lc u) .+ negdf red u;
  558. symbolic procedure multdf(u,v);
  559. % U and V are D.F.'s. Value is D.F. for U*V;
  560. % reduces squares of square-roots as it goes;
  561. if null u or null v then nil
  562. else begin scalar y;
  563. %use (a+b)*(c+d) = (a*c) + a*(c+d) + b*(c+d);
  564. y:=multerm(lt u,lt v); %leading terms;
  565. y:=plusdf(y,multdf(red u,v));
  566. y:=plusdf(y,multdf((lt u) .+ nil,red v));
  567. return y
  568. end;
  569. symbolic procedure multerm(u,v);
  570. %multiply two terms to give a D.F.;
  571. begin scalar coef;
  572. coef:=!*multsq(cdr u,cdr v); %coefficient part;
  573. return multdfconst(coef,mulpower(car u,car v))
  574. end;
  575. symbolic procedure mulpower(u,v);
  576. % u and v are exponent lists. multiply corresponding forms;
  577. begin scalar r,s;
  578. r:=addexptsdf(u,v);
  579. if not null sqrtlist then s:=reduceroots(r,zlist);
  580. r:=(r .* (1 ./ 1)) .+ nil;
  581. if not (s=nil) then r:=multdf(r,s);
  582. return r
  583. end;
  584. symbolic procedure reduceroots(r,zl);
  585. begin scalar s;
  586. while not null r do <<
  587. if eqcar(car zl,'sqrt) then
  588. s:=tryreduction(r,car zl,s);
  589. r:=cdr r; zl:=cdr zl >>;
  590. return s
  591. end;
  592. symbolic procedure tryreduction(r,var,s);
  593. begin scalar x;
  594. x:=car r; %current exponent
  595. if not atom x then << r:=x; x:=car r >>; %numeric part
  596. if (x=0) or (x=1) then return s; %no reduction possible
  597. x:=divide(x,2);
  598. rplaca(r,cdr x); %reduce exponent as redorded
  599. x:=car x;
  600. var:=simp cadr var; %sqrt arg as a s q
  601. var:=!*exptsq(var,x);
  602. x:=multdfconst(1 ./ denr var,f2df numr var); %distribute
  603. if s=nil then s:=x
  604. else s:=multdf(s,x);
  605. return s
  606. end;
  607. symbolic procedure addexptsdf(x,y);
  608. % X and Y are LPOW's of D.F. Value is list of sum of exponents;
  609. if null x then if null y then nil else interr "X too long"
  610. else if null y then interr "Y too long"
  611. else exptplus(car x,car y).addexptsdf(cdr x,cdr y);
  612. symbolic procedure exptplus(x,y);
  613. if atom x then if atom y then x+y else list (x+car y)
  614. else if atom y then list (car x +y)
  615. else interr "Bad exponent sum";
  616. symbolic procedure multdfconst(x,u);
  617. % X is S.Q. not involving Z variables of D.F. U. Value is D.F.;
  618. % for X*U;
  619. if (null u) or (null numr x) then nil
  620. else lpow u .* !*multsq(x,lc u) .+ multdfconst(x,red u);
  621. %symbolic procedure quotdfconst(x,u);
  622. % multdfconst(!*invsq x,u);
  623. symbolic procedure f2df p;
  624. % P is standard form. Value is P in D.F.;
  625. if domainp p then dfconst(p ./ 1)
  626. else if mvar p member zlist then
  627. plusdf(multdf(vp2df(mvar p,tdeg lt p,zlist),f2df lc p),
  628. f2df red p)
  629. else plusdf(multdfconst(((lpow p .* 1) .+ nil) ./ 1,f2df lc p),
  630. f2df red p);
  631. symbolic procedure vp1(var,degg,z);
  632. % Takes VAR and finds it in Z (=list), raises it to power DEGG and puts
  633. % the result in exponent list form for use in a distributed form.
  634. if null z then interr "Var not in z-list after all"
  635. else if var=car z then degg.vp2 cdr z
  636. else 0 . vp1(var,degg,cdr z);
  637. symbolic procedure vp2 z;
  638. % Makes exponent list of zeroes.
  639. if null z then nil
  640. else 0 . vp2 cdr z;
  641. symbolic procedure vp2df(var,exprn,z);
  642. % Makes VAR**EXPRN into exponent list and then converts the resulting
  643. % power into a distributed form.
  644. % Special care with square-roots.
  645. if eqcar(var,'sqrt) and (exprn>1) then
  646. mulpower(vp1(var,exprn,z),vp2 z)
  647. else (vp1(var,exprn,z) .* (1 ./ 1)) .+ nil;
  648. symbolic procedure dfconst q;
  649. % Makes a distributed form from standard quotient constant Q;
  650. if numr q=nil then nil
  651. else ((vp2 zlist) .* q) .+ nil;
  652. %df2q moved to a section of its own.
  653. symbolic procedure df2printform p;
  654. %Convert to a standard form good enough for printing.
  655. if null p then nil
  656. else begin
  657. scalar mv,co;
  658. mv:=xl2q(lpow p,zlist,indexlist);
  659. if mv=(1 ./ 1) then <<
  660. co:=lc p;
  661. if denr co=1 then return addf(numr co,
  662. df2printform red p);
  663. co:=mksp(mk!*sq co,1);
  664. return (co .* 1) .+ df2printform red p >>;
  665. co:=lc p;
  666. if not (denr co=1) then mv:=!*multsq(mv,1 ./ denr co);
  667. mv:=mksp(mk!*sq mv,1) .* numr co;
  668. return mv .+ df2printform red p
  669. end;
  670. symbolic procedure xl2q(l,z,il);
  671. % L is an exponent list from a D.F.,Z is the Z-list, IL is the list of
  672. % indices. Value is L converted to standard quotient. ;
  673. if null z then 1 ./ 1
  674. else if car l=0 then xl2q(cdr l,cdr z,cdr il)
  675. else if not atom car l then
  676. begin scalar temp;
  677. if caar l=0 then temp:= car il
  678. else temp:=list('plus,car il,caar l);
  679. temp:=mksp(list('expt,car z,temp),1);
  680. return !*multsq(((temp .* 1) .+ nil) ./ 1,
  681. xl2q(cdr l,cdr z,cdr il))
  682. end
  683. else if minusp car l then
  684. !*multsq(!*invsq(((mksp(car z,-car l) .* 1) .+ nil) ./ 1),
  685. xl2q(cdr l,cdr z,cdr il))
  686. else !*multsq(((mksp(car z,car l) .* 1) .+ nil) ./ 1,
  687. xl2q(cdr l,cdr z,cdr il));
  688. %symbolic procedure sub1ind power;
  689. % if atom power then power-1
  690. % else list sub1 car power;
  691. symbolic procedure multbyarbpowers u;
  692. % Multiplies the ordinary D.F., U, by arbitrary powers
  693. % of the z-variables;
  694. % i-1 j-1 k-1
  695. % i.e. x z z ... so result is D.F. with the exponent list
  696. % 1 2
  697. %appropriately altered to contain list elements instead of numeric ones.
  698. if null u then nil
  699. else ((addarbexptsdf lpow u) .* lc u) .+ multbyarbpowers red u;
  700. symbolic procedure addarbexptsdf x;
  701. % Adds the arbitrary powers to powers in exponent list, X, to produce
  702. % new exponent list. e.g. 3 -> (2) to represent x**3 now becoming :
  703. % 3 i-1 i+2 ;
  704. % x * x = x . ;
  705. if null x then nil
  706. else list exptplus(car x,-1) . addarbexptsdf cdr x;
  707. endmodule;
  708. module divide; % Exact division of standard forms to give a S Q.
  709. % Authors: Mary Ann Moore and Arthur C. Norman.
  710. fluid '(residue sqrtlist zlist);
  711. global '(!*trdiv !*trint);
  712. exports fquotf,testdivdf,dfquotdf;
  713. imports df2q,f2df,gcdf,interr,multdf,negdf,plusdf,printdf,printsf,
  714. quotf,multsq,invsq,negsq;
  715. % Intended for dividing out known factors as produced by the
  716. % integration program. horrible and slow, i expect!!
  717. symbolic procedure dfquotdf(a,b);
  718. begin scalar residue;
  719. if (!*trint or !*trdiv) then <<
  720. printc "Dfquotdf called on ";
  721. printdf a; printdf b>>;
  722. a:=dfquotdf1(a,b);
  723. if (!*trint or !*trdiv) then << printc "Quotient given as ";
  724. printdf a >>;
  725. if not null residue then begin
  726. scalar gres,w;
  727. if !*trint or !*trdiv then <<
  728. printc "Residue in dfquotdf =";
  729. printdf residue;
  730. printc "Which should be zero";
  731. w:=residue;
  732. gres:=numr lc w; w:=red w;
  733. while not null w do <<
  734. gres:=gcdf(gres,numr lc w);
  735. w:=red w >>;
  736. printc "I.e. the following vanishes";
  737. printsf gres>>;
  738. interr "Non-exact division due to a log term"
  739. end;
  740. return a
  741. end;
  742. symbolic procedure fquotf(a,b);
  743. % Input: a and b standard quotients with (a/b) an exact
  744. % division with respect to the variables in zlist,
  745. % but not necessarily obviously so. the 'non-obvious' problems
  746. % will be because of (e.g.) square-root symbols in b
  747. % output: standard quotient for (a/b)
  748. % (prints message if remainder is not 'clearly' zero.
  749. % A must not be zero.
  750. begin scalar t1;
  751. if null a then interr "A=0 in fquotf";
  752. t1:=quotf(a,b); %try it the easy way
  753. if not null t1 then return t1 ./ 1; %ok
  754. return df2q dfquotdf(f2df a,f2df b)
  755. end;
  756. symbolic procedure dfquotdf1(a,b);
  757. begin scalar q;
  758. if null b then interr "Attempt to divide by zero";
  759. q:=sqrtlist; %remove sqrts from denominator, maybe.
  760. while not null q do begin
  761. scalar conj;
  762. conj:=conjsqrt(b,car q); %conjugate wrt given sqrt
  763. if not (b=conj) then <<
  764. a:=multdf(a,conj);
  765. b:=multdf(b,conj) >>;
  766. q:=cdr q end;
  767. q:=dfquotdf2(a,b);
  768. residue:=reversewoc residue;
  769. return q
  770. end;
  771. symbolic procedure dfquotdf2(a,b);
  772. % As above but a and b are distributed forms, as is the result.
  773. if null a then nil
  774. else begin scalar xd,lcd;
  775. xd:=xpdiff(lpow a,lpow b);
  776. if xd='failed then <<
  777. xd:=lt a; a:=red a;
  778. residue:=xd .+ residue;
  779. return dfquotdf2(a,b) >>;
  780. lcd:= !*multsq(lc a,!*invsq lc b);
  781. if null numr lcd then return dfquotdf2(red a,b);
  782. % Should not be necessary;
  783. lcd := xd .* lcd;
  784. xd:=plusdf(a,multdf(negdf (lcd .+ nil),b));
  785. if xd and (lpow xd = lpow a % Again, should not be necessary;
  786. or xpdiff(lpow xd,lpow b) = 'failed)
  787. then <<if !*trint or !*trdiv
  788. then <<printc "Dfquotdf trouble:"; printdf xd>>;
  789. xd := rootextractdf xd;
  790. if !*trint or !*trdiv then printdf xd>>;
  791. return lcd .+ dfquotdf2(xd,b)
  792. end;
  793. symbolic procedure rootextractdf u;
  794. if null u then nil
  795. else begin scalar v;
  796. v := resimp rootextractsq lc u;
  797. return if null numr v then rootextractdf red u
  798. else (lpow u .* v) .+ rootextractdf red u
  799. end;
  800. symbolic procedure rootextractsq u;
  801. if null numr u then u
  802. else rootextractf numr u ./ rootextractf denr u;
  803. symbolic procedure rootextractf v;
  804. if domainp v then v
  805. else begin scalar u,r,c,x,p;
  806. u := mvar v; p := ldeg v;
  807. r := rootextractf red v;
  808. c := rootextractf lc v;
  809. if null c then return r
  810. else if atom u then return (lpow v .* c) .+ r
  811. else if car u eq 'sqrt
  812. or car u eq 'expt and eqcar(caddr u,'quotient)
  813. and car cdaddr u = 1 and numberp cadr cdaddr u
  814. then <<p := divide(p,if car u eq 'sqrt then 2
  815. else cadr cdaddr u);
  816. if car p = 0
  817. then return if null c then r else (lpow v .* c) .+ r
  818. else if numberp cadr u
  819. then <<c := multd(cadr u ** car p,c); p := cdr p>>
  820. else <<x := simpexpt list(cadr u,car p);
  821. if denr x = 1
  822. then <<c := multf(numr x,c); p := cdr p>>>>>>;
  823. return if p=0 then addf(c,r)
  824. else if null c then r
  825. else ((u to p) .* c) .+ r
  826. end;
  827. % The following hack makes sure that the results of differentiation
  828. % gets passed through ROOTEXTRACT
  829. % a) This should not be done this way, since the effect is global
  830. % b) Should this be done via TIDYSQRT?
  831. put('df,'simpfn,'simpdf!*);
  832. symbolic procedure simpdf!* u;
  833. begin scalar v,v1;
  834. v:=simpdf u;
  835. v1:=rootextractsq v;
  836. if not(v1=v) then return resimp v1
  837. else return v
  838. end;
  839. symbolic procedure xpdiff(a,b);
  840. %Result is list a-b, or 'failed' if a member of this would be negative.
  841. if null a then if null b then nil
  842. else interr "B too long in xpdiff"
  843. else if null b then interr "A too long in xpdiff"
  844. else if car b>car a then 'failed
  845. else (lambda r;
  846. if r='failed then 'failed
  847. else (car a-car b) . r) (xpdiff(cdr a,cdr b));
  848. symbolic procedure conjsqrt(b,var);
  849. % Subst(var=-var,b).
  850. if null b then nil
  851. else conjterm(lpow b,lc b,var) .+ conjsqrt(red b,var);
  852. symbolic procedure conjterm(xl,coef,var);
  853. % Ditto but working on a term.
  854. if involvesp(xl,var,zlist) then xl .* negsq coef
  855. else xl .* coef;
  856. symbolic procedure involvesp(xl,var,zl);
  857. % Check if exponent list has non-zero power for variable.
  858. if null xl then interr "Var not found in involvesp"
  859. else if car zl=var then (not zerop car xl)
  860. else involvesp(cdr xl,var,cdr zl);
  861. endmodule;
  862. module driver; % Driving routines for integration program.
  863. % Author: Mary Ann Moore and Arthur C. Norman.
  864. % Modifications by: John P. Fitch.
  865. fluid '(!*backtrace
  866. !*exp
  867. !*gcd
  868. !*keepsqrts
  869. !*mcd
  870. !*nolnr
  871. !*purerisch
  872. !*rationalize
  873. !*sqrt
  874. !*structure
  875. !*uncached
  876. basic!-listofnewsqrts
  877. basic!-listofallsqrts
  878. expression
  879. gaussiani
  880. intvar
  881. listofnewsqrts
  882. listofallsqrts
  883. loglist
  884. sqrt!-intvar
  885. sqrt!-places!-alist
  886. variable
  887. varlist
  888. xlogs
  889. zlist);
  890. global '(!*algint !*failhard !*trint);
  891. exports integratesq,simpint,purge,simpint1;
  892. imports algebraiccase,algfnpl,findzvars,getvariables,interr,printsq,
  893. transcendentalcase,varsinlist,kernp,simpcar,prepsq,mksq,simp,
  894. opmtch,formlnr;
  895. switch algint,nolnr,trint;
  896. % Form is int(expr,var,x1,x2,...);
  897. % meaning is integrate expr wrt var, given that the result may
  898. % contain logs of x1,x2,...
  899. % x1, etc are intended for use when the system has to be helped
  900. % in the case that expr is algebraic.
  901. % Extended arguments x1, x2, etc., are not currently supported.
  902. symbolic procedure simpint u;
  903. % Simplifies an integral. First two components of U are the integrand
  904. % and integration variable respectively. Optional succeeding components
  905. % are log forms for the final integral;
  906. begin scalar ans,expression,variable,loglist,w,
  907. !*purerisch,intvar,listofnewsqrts,listofallsqrts,
  908. sqrtfn,sqrt!-intvar,sqrt!-places!-alist,
  909. basic!-listofallsqrts,basic!-listofnewsqrts;
  910. if atom u or null cdr u then rederr "Not enough arguments for INT";
  911. variable := !*a2k cadr u;
  912. w := cddr u;
  913. if w then rederr "Too many arguments to INT";
  914. listofnewsqrts:= list mvar gaussiani; % Initialize for SIMPSQRT.
  915. listofallsqrts:= list (argof mvar gaussiani . gaussiani);
  916. sqrtfn := get('sqrt,'simpfn);
  917. put('sqrt,'simpfn,'proper!-simpsqrt);
  918. % We need explicit settings of several switches during integral
  919. % evaluation. In addition, the current code cannot handle domains
  920. % like floating point, so we suppress it while the integral is
  921. % calculated. UNCACHED is turned on since integrator does its own
  922. % caching.
  923. begin scalar dmode!*,!*exp,!*gcd,!*keepsqrts,!*mcd,!*sqrt,
  924. !*rationalize,!*structure,!*uncached;
  925. !*keepsqrts := !*sqrt := t;
  926. !*exp := !*gcd := !*mcd := !*structure := !*uncached := t;
  927. dmode!* := nil;
  928. if !*algint
  929. then <<intvar:=variable; % until fix JHD code
  930. % Start a clean slate (in terms of SQRTSAVE) for this integral
  931. sqrt!-intvar:=!*q2f simpsqrti variable;
  932. if (red sqrt!-intvar) or (lc sqrt!-intvar neq 1)
  933. or (ldeg sqrt!-intvar neq 1)
  934. then interr "Sqrt(x) not properly formed"
  935. else sqrt!-intvar:=mvar sqrt!-intvar;
  936. basic!-listofallsqrts:=listofallsqrts;
  937. basic!-listofnewsqrts:=listofnewsqrts;
  938. sqrtsave(basic!-listofallsqrts,basic!-listofnewsqrts,
  939. list(variable . variable))>>;
  940. expression := int!-simp car u;
  941. % loglist := for each x in w collect int!-simp x;
  942. ans := errorset('(integratesq expression variable loglist),
  943. !*backtrace,!*backtrace);
  944. end;
  945. if errorp ans
  946. then return <<put('sqrt,'simpfn,sqrtfn);
  947. if !*failhard then error1();
  948. simpint1(expression . variable . w)>>
  949. else ans := car ans;
  950. expression := sqrtchk numr ans ./ sqrtchk denr ans;
  951. % We now need to check that all simplifications have been done
  952. % but we have to make sure INT is not resimplified.
  953. put('int,'simpfn,'simpiden);
  954. ans := errorset('(resimp expression),t,!*backtrace);
  955. put('int,'simpfn,'simpint);
  956. put('sqrt,'simpfn,sqrtfn);
  957. return if errorp ans then error1() else car ans
  958. end;
  959. symbolic procedure sqrtchk u;
  960. % U is a standard form. Result is another standard form with square
  961. % roots replaced by half powers.
  962. if domainp u then u
  963. else if not eqcar(mvar u,'sqrt)
  964. then addf(multpf(lpow u,sqrtchk lc u),sqrtchk red u)
  965. else addf(multpf(mksp(list('expt,cadr mvar u,'(quotient 1 2)),
  966. ldeg u),
  967. sqrtchk lc u),
  968. sqrtchk red u);
  969. symbolic procedure int!-simp u;
  970. %converts U to canonical form, including the resimplification of
  971. % *sq forms;
  972. subs2 resimp simp!* u;
  973. put('int,'simpfn,'simpint);
  974. symbolic procedure integratesq(integrand,var,xlogs);
  975. begin scalar varlist,zlist;
  976. if !*trint then <<
  977. printc "Integrand is...";
  978. printsq integrand >>;
  979. varlist:=getvariables integrand;
  980. varlist:=varsinlist(xlogs,varlist); %in case more exist in xlogs
  981. zlist:=findzvars(varlist,list var,var,nil); %important kernels
  982. %the next section causes problems with nested exponentials or logs;
  983. begin scalar oldzlist;
  984. while oldzlist neq zlist do <<
  985. oldzlist:=zlist;
  986. foreach zz in oldzlist do
  987. zlist:=findzvars(distexp(pseudodiff(zz,var)),zlist,var,t)>>
  988. end;
  989. if !*trint then <<
  990. printc "with 'new' functions :";
  991. print zlist >>;
  992. if !*purerisch and not allowedfns zlist
  993. then return simpint1 (integrand . var.nil);
  994. % If it is not suitable for Risch;
  995. varlist:=purge(zlist,varlist);
  996. % Now zlist is list of things that depend on x, and varlist is list
  997. % of constant kernels in integrand;
  998. if !*algint and cdr zlist and algfnpl(zlist,var)
  999. then return algebraiccase(integrand,zlist,varlist)
  1000. else return transcendentalcase(integrand,var,xlogs,zlist,varlist)
  1001. end;
  1002. symbolic procedure distexp(l);
  1003. if null l then nil
  1004. else if atom car l then car l . distexp cdr l
  1005. else if (caar l = 'expt) and (cadar l = 'e) then
  1006. begin scalar ll;
  1007. ll:=caddr car l;
  1008. if eqcar(ll,'plus) then <<
  1009. ll:=foreach x in cdr ll collect list('expt,'e,x);
  1010. return ('times . ll) . distexp cdr l >>
  1011. else return car l . distexp cdr l
  1012. end
  1013. else distexp car l . distexp cdr l;
  1014. symbolic procedure pseudodiff(a,var);
  1015. if atom a then nil
  1016. else if car a memq '(atan equal log plus quotient sqrt times)
  1017. then begin scalar aa,bb;
  1018. foreach zz in cdr a do <<
  1019. bb:=pseudodiff(zz,var);
  1020. if aa then aa:=bb . aa else bb >>;
  1021. return aa
  1022. end
  1023. else if car a eq 'expt
  1024. then if depends(cadr a,var) then
  1025. prepsq simp list('log,cadr a) .
  1026. cadr a .
  1027. caddr a .
  1028. append(pseudodiff(cadr a,var),pseudodiff(caddr a,var))
  1029. else caddr a . pseudodiff(caddr a,var)
  1030. else list prepsq simpdf(list(a,var));
  1031. symbolic procedure simpint1 u;
  1032. begin scalar v,!*sqrt;
  1033. u := 'int . prepsq car u . cdr u;
  1034. if (v := formlnr u) neq u
  1035. then if !*nolnr
  1036. then <<v:= simp subst('int!*,'int,v);
  1037. return remakesf numr v ./ remakesf denr v>>
  1038. else <<!*nolnr:= nil . !*nolnr;
  1039. u:=errorset(list('simp,mkquote v),
  1040. !*backtrace,!*backtrace);
  1041. if pairp u then v:=car u;
  1042. !*nolnr:= cdr !*nolnr;
  1043. return v>>;
  1044. return if (v := opmtch u) then simp v
  1045. else if !*failhard then rederr "FAILHARD switch set"
  1046. else mksq(u,1)
  1047. end;
  1048. mkop 'int!*;
  1049. put('int!*,'simpfn,'simpint!*);
  1050. symbolic procedure simpint!* u;
  1051. begin scalar x;
  1052. return if (x := opmtch('int . u)) then simp x
  1053. else simpiden('int!* . u)
  1054. end;
  1055. symbolic procedure remakesf u;
  1056. %remakes standard form U, substituting operator INT for INT!*;
  1057. if domainp u then u
  1058. else addf(multpf(if eqcar(mvar u,'int!*)
  1059. then mksp('int . cdr mvar u,ldeg u)
  1060. else lpow u,remakesf lc u),
  1061. remakesf red u);
  1062. symbolic procedure allowedfns u;
  1063. if null u
  1064. then t
  1065. else if atom car u or
  1066. flagp(caar u,'transcendental)
  1067. then allowedfns cdr u
  1068. else nil;
  1069. symbolic procedure purge(a,b);
  1070. if null a then b
  1071. else if null b then nil
  1072. else purge(cdr a,delete(car a,b));
  1073. endmodule;
  1074. module d3d4; % Splitting of cubics and quartics.
  1075. % Authors: Mary Ann Moore and Arthur C. Norman.
  1076. fluid '(knowndiscrimsign zlist);
  1077. global '(!*trint);
  1078. exports cubic,quartic;
  1079. imports covecdf,cuberootf,nth,forceazero,makepolydf,multdf,multdfconst,
  1080. !*multf,negdf,plusdf,printdf,printsf,quadratic,sqrtf,vp1,vp2,addf,
  1081. negf;
  1082. symbolic procedure cubic(pol,var,res);
  1083. %Split the univariate (wrt z-vars) cubic pol, at least if a
  1084. %change of origin puts it in the form (x-a)**3-b=0;
  1085. begin scalar a,b,c,d,v,shift,p;
  1086. v:=covecdf(pol,var,3);
  1087. shift:=forceazero(v,3); %make coeff x**2 vanish.
  1088. %also checks univariate.
  1089. % if shift='failed then go to prime;
  1090. a:=getv(v,3); b:=getv(v,2); %=0, I hope!;
  1091. c:=getv(v,1); d:=getv(v,0);
  1092. if !*trint then << printc "Cubic has coefficients";
  1093. printsf a; printsf b;
  1094. printsf c; printsf d >>;
  1095. if not null c then <<
  1096. if !*trint then printc "Cubic too hard to split";
  1097. go to exit >>;
  1098. a:=cuberootf(a); %can't ever fail;
  1099. d:=cuberootf(d);
  1100. if !*trint then << printc "Cube roots of a and d are";
  1101. printsf a; printsf d>>;
  1102. %now a*(x+shift)+d is a factor of pol;
  1103. %create x+shift in p;
  1104. p:=(vp2 zlist .* shift) .+ nil;
  1105. p:=(vp1(var,1,zlist) .* (1 ./ 1)) .+ p; %(x+shift);
  1106. b:=nil;
  1107. b:=(vp2 zlist .* (d ./ 1)) .+ b;
  1108. b:=plusdf(b,multdfconst(a ./ 1,p));
  1109. b:=makepolydf b; %get rid of denominator.
  1110. if !*trint then << printc "One factor of the cubic is";
  1111. printdf b >>;
  1112. res:=('log . b) . res;
  1113. %now form the (quadratic) cofactor;
  1114. b:=(vp2 zlist .* (!*multf(d,d) ./ 1)) .+ nil;
  1115. b:=plusdf(b,multdfconst(negf !*multf(a,d) ./ 1,p));
  1116. b:=plusdf(b,multdfconst(!*multf(a,a) ./ 1,
  1117. multdf(p,p)));
  1118. return quadratic(makepolydf b,var,res); %deal with what is left;
  1119. prime:
  1120. if !*trint then printc "The following cubic does not split";
  1121. exit:
  1122. if !*trint then printdf pol;
  1123. return ('log . pol) . res
  1124. end;
  1125. symbolic procedure quartic(pol,var,res);
  1126. %Splits univariate (wrt z-vars) quartics that can be written
  1127. %in the form (x-a)**4+b*(x-a)**2+c;
  1128. begin scalar a,b,c,d,ee,v,shift,p,q,p1,p2,dsc;
  1129. v:=covecdf(pol,var,4);
  1130. shift:=forceazero(v,4); %make coeff x**3 vanish;
  1131. % if shift='failed then go to prime;
  1132. a:=getv(v,4); b:=getv(v,3); %=0, I hope.
  1133. c:=getv(v,2); d:=getv(v,1);
  1134. ee:=getv(v,0);
  1135. if !*trint then << printc "Quartic has coefficients";
  1136. printsf a; printsf b;
  1137. printsf c; printsf d;
  1138. printsf ee >>;
  1139. if d
  1140. then <<if !*trint then printc "Quartic too hard to split";
  1141. go to exit >>;
  1142. b:=c; c:=ee; %squash up the notation;
  1143. if knowndiscrimsign eq 'negative then go to complex;
  1144. dsc := addf(!*multf(b,b),multf(-4,!*multf(a,c)));
  1145. p2 := minusf c;
  1146. if not p2 and minusf dsc then go to complex;
  1147. p1 := null b or minusf b;
  1148. if not p1 then if p2 then p1 := t else p2 := t;
  1149. p1 := if p1 then 'positive else 'negative;
  1150. p2 := if p2 then 'negative else 'positive;
  1151. a := sqrtf a;
  1152. dsc := sqrtf dsc;
  1153. if a eq 'failed or dsc eq 'failed then go to prime;
  1154. ee := invsq(addf(a,a) ./ 1);
  1155. d := multsq(addf(b,negf dsc) ./ 1,ee);
  1156. ee := multsq(addf(b,dsc) ./ 1,ee);
  1157. if !*trint
  1158. then <<printc "Quadratic factors will have coefficients";
  1159. printsf a; print 0; printsq d;
  1160. printc "or"; printsq ee>>;
  1161. p := (vp2 zlist .* shift) .+ nil;
  1162. p := (vp1(var,1,zlist) .* (1 ./ 1)) .+ p; %(x+shift);
  1163. q := multdf(p,p); %square of same;
  1164. q := multdfconst(a ./ 1,q);
  1165. p := plusdf(q,(vp2 zlist .* d) .+ nil);
  1166. q := plusdf(q,(vp2 zlist .* ee) .+ nil);
  1167. if !*trint
  1168. then <<printc "Allowing for change of origin:";
  1169. printdf p; printdf q>>;
  1170. knowndiscrimsign := p1;
  1171. res := quadratic(p,var,res);
  1172. knowndiscrimsign := p2;
  1173. res := quadratic(q,var,res);
  1174. go to quarticdone;
  1175. complex:
  1176. a:=sqrtf(a);
  1177. c:=sqrtf(c);
  1178. if a eq 'failed or c eq 'failed then go to prime;
  1179. b:=addf(!*multf(2,!*multf(a,c)),negf b);
  1180. b:=sqrtf b;
  1181. if b eq 'failed then go to prime;
  1182. %now a*(x+shift)**2 (+/-) b*(x+shift) + c is a factor.
  1183. if !*trint
  1184. then << printc "Quadratic factors will have coefficients";
  1185. printsf a; printsf b; printsf c>>;
  1186. p:=(vp2 zlist .* shift) .+ nil;
  1187. p:=(vp1(var,1,zlist) .* (1 ./ 1)) .+ p; %(x+shift);
  1188. q:=multdf(p,p); %square of same;
  1189. p:=multdfconst(b ./ 1,p);
  1190. q:=multdfconst(a ./ 1,q);
  1191. q:=plusdf(q,(vp2 zlist .* (c ./ 1)) .+ nil);
  1192. if !*trint then <<
  1193. printc "Allowing for change of origin, p (+/-) q with p,q=";
  1194. printdf p; printdf q>>;
  1195. %now p+q and p-q are the factors of the quartic;
  1196. knowndiscrimsign := 'negative;
  1197. res:=quadratic(plusdf(q,p),var,res);
  1198. res:=quadratic(plusdf(q,negdf p),var,res);
  1199. quarticdone:
  1200. knowndiscrimsign := nil;
  1201. if !*trint then printc "Quartic done";
  1202. return res;
  1203. prime:
  1204. if !*trint then printc "The following quartic does not split";
  1205. exit:
  1206. if !*trint then printdf pol;
  1207. return ('log . pol) . res
  1208. end;
  1209. endmodule;
  1210. module factr; % Crude factorization routine for integrator.
  1211. % Authors: Mary Ann Moore and Arthur C. Norman.
  1212. fluid '(zlist);
  1213. global '(!*trint);
  1214. exports int!-fac,var2df;
  1215. imports cubic,df2q,f2df,interr,multdf,printdf,quadratic,quartic,unifac,
  1216. uniform,vp1,vp2,sub1;
  1217. symbolic procedure int!-fac x;
  1218. % Input: primitive, square-free polynomial (s.form).
  1219. %output:
  1220. % list of 'factors' wrt zlist
  1221. % each item in this list is either
  1222. % log . sq
  1223. % or atan . sq
  1224. % and these logs and arctans are all that is needed in the
  1225. % integration of 1/(argument).
  1226. begin scalar res,pol,dset,var,degree,vars;
  1227. pol:=f2df x; %convert to distributed form
  1228. dset:=degreeset(pol);
  1229. %now extract factors of the form 'x' or 'log(x)' etc;
  1230. %these correspond to items in dset with a non-zero cdr.
  1231. begin scalar zl,ds;
  1232. zl:=zlist; ds:=dset;
  1233. while not null ds do <<
  1234. if onep cdar ds then <<
  1235. res:=('log . var2df(car zl,1,zlist)) . res;
  1236. %record in answer.
  1237. pol:=multdf(var2df(car zl,-1,zlist),pol);
  1238. %divide out.
  1239. if !*trint then << printc "Trivial factor found";
  1240. printdf cdar res>>;
  1241. rplaca(ds,sub1 caar ds . cdar ds) >>
  1242. else if null zerop cdar ds then
  1243. interr "Repeated trivial factor in arg to factor";
  1244. zl:=cdr zl; ds:=cdr ds >>;
  1245. end; %single term factors all removed now.
  1246. dset:=mapcar(dset,function car); %get lower bounds.
  1247. if !*trint
  1248. then printc ("Upper bounds of remaining factors are now: " .
  1249. dset);
  1250. if dset=vp2 zlist then go to finished; %thing left is constant.
  1251. begin scalar ds,zl;
  1252. var:=car zlist; degree:=car dset;
  1253. if not zerop degree then vars:=var . vars;
  1254. ds:=cdr dset; zl:=cdr zlist;
  1255. while not null ds do <<
  1256. if not zerop car ds then <<
  1257. vars:=car zl . vars;
  1258. if zerop degree or degree>car ds then <<
  1259. var:=car zl; degree:=car ds >> >>;
  1260. zl:=cdr zl; ds:=cdr ds >>
  1261. end;
  1262. % Now var is variable that this poly involves to lowest degree.
  1263. % Degree is the degree of the poly in same variable.
  1264. if !*trint
  1265. then printc ("Best var is " . var . "with exponent " .
  1266. degree);
  1267. if onep degree then <<
  1268. res:=('log . pol) . res; %certainly irreducible.
  1269. if !*trint
  1270. then << printc "The following is certainly irreducible";
  1271. printdf pol>>;
  1272. go to finished >>;
  1273. if degree=2 then <<
  1274. if !*trint then << printc "Quadratic";
  1275. printdf pol>>;
  1276. res:=quadratic(pol,var,res);
  1277. go to finished >>;
  1278. dset:=uniform(pol,var);
  1279. if not (dset='failed) then <<
  1280. if !*trint then << printc "Univariate polynomial";
  1281. printdf pol >>;
  1282. res:=unifac(dset,var,degree,res);
  1283. go to finished >>;
  1284. if not null cdr vars then go to nasty; %only try univariate now.
  1285. if degree=3 then <<
  1286. if !*trint then << printc "Cubic";
  1287. printdf pol>>;
  1288. res:=cubic(pol,var,res);
  1289. % if !*overlaymode then excise 'd3d4;
  1290. go to finished >>;
  1291. if degree=4 then <<
  1292. if !*trint then << printc "Quartic";
  1293. printdf pol>>;
  1294. res:=quartic(pol,var,res);
  1295. % if !*overlaymode then excise 'd3d4;
  1296. go to finished>>;
  1297. %else abandon hope and hand back some rubbish.
  1298. nasty:
  1299. res:=('log . pol) . res;
  1300. printc
  1301. "The following polynomial has not been properly factored";
  1302. printdf pol;
  1303. go to finished;
  1304. finished: %res is a list of d.f. s as required
  1305. pol:=nil; %convert back to standard forms
  1306. while not null res do
  1307. begin scalar type,arg;
  1308. type:=caar res; arg:=cdar res;
  1309. arg:=df2q arg;
  1310. if type='log then rplacd(arg,1);
  1311. pol:=(type . arg) . pol;
  1312. res:=cdr res end;
  1313. return pol
  1314. end;
  1315. symbolic procedure var2df(var,n,zlist);
  1316. ((vp1(var,n,zlist) .* (1 ./ 1)) .+ nil);
  1317. symbolic procedure degreeset pol;
  1318. % Finds degree bounds for all vars in distributed form poly.
  1319. degreesub(dbl lpow pol,red pol);
  1320. symbolic procedure dbl x;
  1321. % Converts list of x into list of (x . x).
  1322. if null x then nil
  1323. else (car x . car x) . dbl cdr x;
  1324. symbolic procedure degreesub(cur,pol);
  1325. % Update degree bounds 'cur' to include info about pol.
  1326. <<
  1327. while not null pol do <<
  1328. cur:=degreesub1(cur,lpow pol);
  1329. pol:=red pol >>;
  1330. cur >>;
  1331. symbolic procedure degreesub1(cur,nxt);
  1332. %Merge information from exponent set next into cur.
  1333. if null cur then nil
  1334. else degreesub2(car cur,car nxt) . degreesub1(cdr cur,cdr nxt);
  1335. symbolic procedure degreesub2(two,one);
  1336. max(car two,one) . min(cdr two,one);
  1337. endmodule;
  1338. module ibasics; % Some basic support routines for integrator.
  1339. % Authors: Mary Ann Moore and Arthur C. Norman.
  1340. fluid '(!*backtrace !*gcd !*sqfree indexlist sqrtflag sqrtlist
  1341. varlist zlist);
  1342. global '(!*trint);
  1343. exports partialdiff,printdf,rationalintegrate,interr;
  1344. imports df2printform,printsf,varsinsf,addsq,multsq,multd,mksp;
  1345. symbolic procedure printdf u;
  1346. % Print distributed form via cheap conversion to reduce structure.
  1347. begin scalar !*gcd;
  1348. printsf df2printform u;
  1349. end;
  1350. symbolic procedure !*n2sq(u1);
  1351. if u1=0 then nil . 1 else u1 . 1;
  1352. symbolic procedure indx(n);
  1353. if n<2 then (list 1) else(n . indx(isub1 n));
  1354. symbolic procedure interr mess;
  1355. <<(!*trint or !*backtrace)
  1356. and <<prin2 "***** INTEGRATION PACKAGE ERROR: "; printc mess>>;
  1357. error1()>>;
  1358. symbolic procedure rationalintegrate(x,var);
  1359. begin scalar n,d;
  1360. n:=numr x; d:=denr x;
  1361. if not var member varsinsf(d,nil) then
  1362. return !*multsq(polynomialintegrate(n,var),1 ./ d);
  1363. rederr "Rational integration not coded yet"
  1364. end;
  1365. symbolic procedure polynomialintegrate(x,v);
  1366. % Integrate standard form. result is standard quotient.
  1367. if null x then nil ./ 1
  1368. else if atom x then ((mksp(v,1) .* 1) .+ nil) ./ 1
  1369. else begin scalar r;
  1370. r:=polynomialintegrate(red x,v); % deal with reductum
  1371. if v=mvar x then begin scalar degree,newlt;
  1372. degree:=1+tdeg lt x;
  1373. newlt:=((mksp(v,degree) .* lc x) .+ nil) ./ 1; % up exponent
  1374. r:=addsq(!*multsq(newlt,1 ./ degree),r)
  1375. end
  1376. else begin scalar newterm;
  1377. newterm:=(((lpow x) .* 1) .+ nil) ./ 1;
  1378. newterm:=!*multsq(newterm,polynomialintegrate(lc x,v));
  1379. r:=addsq(r,newterm)
  1380. end;
  1381. return r
  1382. end;
  1383. symbolic procedure partialdiff(p,v);
  1384. % Partial differentiation of p wrt v - p is s.f. as is result.
  1385. if domainp p then nil
  1386. else
  1387. if v=mvar p then
  1388. (lambda x; if x=1 then lc p
  1389. else ((mksp(v,x-1) .* multd(x,lc p))
  1390. .+ partialdiff(red p,v)))
  1391. (tdeg lt p)
  1392. else
  1393. (lambda x; if null x then partialdiff(red p,v)
  1394. else ((lpow p .* x) .+ partialdiff(red p,v)))
  1395. (partialdiff(lc p,v));
  1396. put('pdiff,'simpfn,'simppdiff);
  1397. symbolic procedure ncdr(l,n);
  1398. % we can use small integer arithmetic here.
  1399. if n=0 then l else ncdr(cdr l,isub1 n);
  1400. symbolic procedure mkilist(old,term);
  1401. if null old then nil
  1402. else term.mkilist(cdr old,term);
  1403. %symbolic procedure addin(lista,first,listb);
  1404. %if null lista
  1405. % then nil
  1406. % else ((first.car listb).car lista).addin(cdr lista,first,cdr listb);
  1407. symbolic procedure removeduplicates(u);
  1408. % Purges duplicates from the list passed to it.
  1409. if null u then nil
  1410. else if (atom u) then u.nil
  1411. else if member(car u,cdr u)
  1412. then removeduplicates cdr u
  1413. else (car u).removeduplicates cdr u;
  1414. symbolic procedure jsqfree(sf,var);
  1415. begin
  1416. varlist:=getvariables(sf ./ 1);
  1417. zlist:=findzvars(varlist,list var,var,nil);
  1418. sqrtlist:=findsqrts varlist; % before the purge
  1419. sqrtflag:=not null sqrtlist;
  1420. varlist:=purge(zlist,varlist);
  1421. if sf eq !*sqfree
  1422. then return list list sf
  1423. else return sqfree(sf,zlist)
  1424. end;
  1425. symbolic procedure jfactor(sf,var);
  1426. begin
  1427. scalar varlist,zlist,indexlist,sqrtlist,sqrtflag;
  1428. scalar prim,answer,u,v; % scalar var2
  1429. prim:=jsqfree(sf,var);
  1430. indexlist:=createindices zlist;
  1431. prim:=factorlistlist (prim,t);
  1432. while prim do <<
  1433. if caar prim eq 'log then <<
  1434. u:=cdar prim;
  1435. u:=!*multsq(numr u ./ 1,1 ./ cdr stt(numr u,var));
  1436. v:=denr u;
  1437. while not atom v do v:=lc v;
  1438. if (numberp v) and (0> v)
  1439. then u:=(negf numr u) ./ (negf denr u);
  1440. answer:=u.answer >>
  1441. else if caar prim eq 'atan then <<
  1442. % We can ignore this, since we also get LOG (U**2+1) as another term.
  1443. >>
  1444. else interr "Unexpected term in jfactor";
  1445. prim:=cdr prim >>;
  1446. return answer
  1447. end;
  1448. symbolic procedure stt(u,x);
  1449. if domainp u
  1450. then if u eq nil
  1451. then ((-1) . nil)
  1452. else (0 . u)
  1453. else if mvar u eq x
  1454. then ldeg u . lc u
  1455. else if ordop(x,mvar u)
  1456. then (0 . u)
  1457. else begin
  1458. scalar ltlc,ltrest;
  1459. ltlc:=stt(lc u,x);
  1460. ltrest:= stt(red u,x);
  1461. if car ltlc = car ltrest then go to merge;
  1462. if car ltlc > car ltrest
  1463. then return car ltlc .
  1464. !*multf(cdr ltlc,(lpow u .* 1) .+ nil)
  1465. else return ltrest;
  1466. merge:
  1467. return car ltlc.addf(cdr ltrest,
  1468. !*multf(cdr ltlc,(lpow u .* 1) .+ nil))
  1469. end;
  1470. symbolic procedure gcdinonevar(u,v,x);
  1471. % Gcd of u and v, regarded as polynnmials in x.
  1472. if null u
  1473. then v
  1474. else if null v
  1475. then u
  1476. else begin
  1477. scalar u1,v1,z,w;
  1478. u1:=stt(u,x);
  1479. v1:=stt(v,x);
  1480. loop:
  1481. if (car u1) > (car v1)
  1482. then go to ok;
  1483. z:=u1;u1:=v1;v1:=z;
  1484. z:=u;u:=v;v:=z;
  1485. ok:
  1486. if car v1 iequal 0
  1487. then interr "Coprimeness in gcd";
  1488. z:=gcdf(cdr u1,cdr v1);
  1489. w:=quotf(cdr u1,z);
  1490. if (car u1) neq (car v1)
  1491. then w:=!*multf(w,!*p2f mksp(x,(car u1)-(car v1)));
  1492. u:=addf(!*multf(v,w),
  1493. !*multf(u,negf quotf(cdr v1,z)));
  1494. if null u
  1495. then return v;
  1496. u1:=stt(u,x);
  1497. go to loop
  1498. end;
  1499. symbolic procedure mapply(funct,l);
  1500. if null l then rederr "Empty list to mapply"
  1501. else if null cdr l then car l
  1502. else apply(funct,list(car l,mapply(funct,cdr l)));
  1503. symbolic procedure !*lcm!*(u,v);
  1504. !*multf(u,quotf(v,gcdf(u,v)));
  1505. symbolic procedure multsql(u,l);
  1506. % Multiplies (!*multsq) each element of l by u.
  1507. if null l
  1508. then nil
  1509. else !*multsq(u,car l).multsql(u,cdr l);
  1510. symbolic procedure intersect(x,y);
  1511. if null x then nil else if member(car x,y) then
  1512. car(x) . intersect(cdr x,y) else
  1513. intersect(cdr x,y);
  1514. symbolic procedure mapvec(v,f);
  1515. begin
  1516. scalar n;
  1517. n:=upbv v;
  1518. for i:=0:n do
  1519. apply(f,list getv(v,i))
  1520. end;
  1521. endmodule;
  1522. module jpatches; % Routines for manipulating sf's with power folding.
  1523. % Author: James H. Davenport.
  1524. fluid '(sqrtflag);
  1525. exports !*addsq,!*multsq,!*invsq,!*multf,squashsqrtsq,!*exptsq,!*exptf;
  1526. % !*MULTF(A,B) multiplies the polynomials (standard forms) U and V
  1527. % in much the same way as MULTF(U,V) would, EXCEPT...
  1528. % (1) !*MULTF inhibits the action of OFF EXP and of non-commutative
  1529. % multiplications
  1530. % (2) Within !*MULTF powers of square roots, and powers of
  1531. % exponential kernels are reduced as if substitution rules
  1532. % such as FOR ALL X LET SQRT(X)**2=X were being applied;
  1533. % Note that !*MULTF comes between MULTF and !*Q2F SUBS2F MULTF in its
  1534. % behaviour, and that it is the responsibility of the user to call it
  1535. % in sensible places where its services are needed;
  1536. % similarly for the other functions defined here;
  1537. %symbolic procedure !*addsq(u,v);
  1538. %U and V are standard quotients.
  1539. % %Value is canonical sum of U and V;
  1540. % if null numr u then v
  1541. % else if null numr v then u
  1542. % else if denr u=1 and denr v=1 then addf(numr u,numr v) ./ 1
  1543. % else begin scalar nu,du,nv,dv,x;
  1544. % x := gcdf(du:=denr u,dv:=denr v);
  1545. % du:=quotf(du,x); dv:=quotf(dv,x);
  1546. % nu:=numr u; nv:=numr v;
  1547. % u:=addf(!*multf(nu,dv),!*multf(nv,du));
  1548. % if u=nil then return nil ./ 1;
  1549. % v:=!*multf(du,denr v);
  1550. % return !*ff2sq(u,v)
  1551. % end;
  1552. %symbolic procedure !*multsq(a,b);
  1553. % begin
  1554. % scalar n,d;
  1555. % n:=!*multf(numr a,numr b);
  1556. % d:=!*multf(denr a,denr b);
  1557. % return !*ff2sq(n,d)
  1558. % end;
  1559. %symbolic procedure !*ff2sq(a,b);
  1560. % begin
  1561. % scalar gg;
  1562. % if null a then return nil ./ 1;
  1563. % gg:=gcdf(a,b);
  1564. % if not (gg=1) then <<
  1565. % a:=quotf(a,gg);
  1566. % b:=quotf(b,gg) >>;
  1567. % if minusf b then <<
  1568. % a:=negf a;
  1569. % b:=negf b >>;
  1570. % return a ./ b
  1571. % end;
  1572. symbolic procedure !*addsq(u,v);
  1573. %U and V are standard quotients.
  1574. %Value is canonical sum of U and V;
  1575. if null numr u then v
  1576. else if null numr v then u
  1577. else if denr u=1 and denr v=1 then addf(numr u,numr v) ./ 1
  1578. else begin scalar du,dv,x,y,z;
  1579. x := gcdf(du:=denr u,dv:=denr v);
  1580. du:=quotf(du,x); dv:=quotf(dv,x);
  1581. y:=addf(!*multf(dv,numr u),!*multf(du,numr v));
  1582. if null y then return nil ./ 1;
  1583. z:=!*multf(denr u,dv);
  1584. if minusf z then <<y := negf y; z := negf z>>;
  1585. if x=1 then return y ./ z;
  1586. x := gcdf(y,x);
  1587. return if x=1 then y ./ z else quotf(y,x) ./ quotf(z,x)
  1588. end;
  1589. symbolic procedure !*multsq(u,v);
  1590. %U and V are standard quotients. Result is the canonical product of
  1591. %U and V with surd powers suitably reduced.
  1592. if null numr u or null numr v then nil ./ 1
  1593. else if denr u=1 and denr v=1 then !*multf(numr u,numr v) ./ 1
  1594. else begin scalar w,x,y;
  1595. x := gcdf(numr u,denr v);
  1596. y := gcdf(numr v,denr u);
  1597. w := !*multf(quotf(numr u,x),quotf(numr v,y));
  1598. x := !*multf(quotf(denr u,y),quotf(denr v,x));
  1599. if minusf x then <<w := negf w; x := negf x>>;
  1600. y := gcdf(w,x); % another factor may have been generated.
  1601. return if y=1 then w ./ x else quotf(w,y) ./ quotf(x,y)
  1602. end;
  1603. symbolic procedure !*invsq a;
  1604. % Note that several examples (e.g., int(1/(x**8+1),x)) give a more
  1605. % compact result when SQRTFLAG is true if SQRT2TOP is not called.
  1606. if sqrtflag then sqrt2top invsq a else invsq a;
  1607. symbolic procedure !*multf(u,v);
  1608. % U and V are standard forms
  1609. % Value is SF for U*V;
  1610. begin
  1611. scalar x,y;
  1612. if null u or null v
  1613. then return nil
  1614. else if u = 1
  1615. then return squashsqrt v
  1616. else if v = 1
  1617. then return squashsqrt u
  1618. else if domainp u
  1619. then return multd(u,squashsqrt v)
  1620. else if domainp v
  1621. then return multd(v,squashsqrt u);
  1622. x:=mvar u;
  1623. y:=mvar v;
  1624. if x eq y
  1625. then go to c
  1626. else if ordop(x,y)
  1627. then go to b;
  1628. x:=!*multf(u,lc v);
  1629. y:=!*multf(u,red v);
  1630. return if null x then y
  1631. else if not domainp lc v
  1632. and mvar u eq mvar lc v
  1633. and not atom mvar u
  1634. and car mvar u memq '(expt sqrt)
  1635. then addf(!*multf(x,!*p2f lpow v),y) % what about noncom?
  1636. else makeupsf(lpow v,x,y);
  1637. b: x:=!*multf(lc u,v);
  1638. y:=!*multf(red u,v);
  1639. return if null x then y
  1640. else if not domainp lc u
  1641. and mvar lc u eq mvar v
  1642. and not atom mvar v
  1643. and car mvar v memq '(expt sqrt)
  1644. then addf(!*multf(!*p2f lpow u,x),y)
  1645. else makeupsf(lpow u,x,y);
  1646. c: y:=addf(!*multf(list lt u,red v),!*multf(red u,v));
  1647. if eqcar(x,'sqrt)
  1648. then return addf(squashsqrt y,!*multfsqrt(x,
  1649. !*multf(lc u,lc v),ldeg u + ldeg v))
  1650. else if eqcar(x,'expt) and prefix!-rational!-numberp caddr x
  1651. then return addf(squashsqrt y,!*multfexpt(x,
  1652. !*multf(lc u,lc v),ldeg u + ldeg v));
  1653. x:=mkspm(x,ldeg u + ldeg v);
  1654. return if null x or null (u:=!*multf(lc u,lc v))
  1655. then y
  1656. else x .* u .+ y
  1657. end;
  1658. symbolic procedure makeupsf(u,x,y);
  1659. % Makes u .* x .+ y except when u is not a valid lpow (because of
  1660. % sqrts).
  1661. if atom car u or cdr u = 1 then u .* x .+ y
  1662. else if caar u eq 'sqrt then addf(!*multfsqrt(car u,x,cdr u),y)
  1663. else if <<begin scalar v;
  1664. v:=car u;
  1665. if car v neq 'expt then return nil;
  1666. v:=caddr v;
  1667. if atom v then return nil;
  1668. return (car v eq 'quotient
  1669. and numberp cadr v
  1670. and numberp caddr v)
  1671. end >>
  1672. then addf(!*multfexpt(car u,x,cdr u),y)
  1673. else u .* x .+ y;
  1674. symbolic procedure !*multfsqrt(x,u,w);
  1675. % This code (Due to Norman a& Davenport) squashes SQRT(...)**2.
  1676. begin scalar v;
  1677. w:=divide(w,2);
  1678. v:=!*q2f simp cadr x;
  1679. u:=!*multf(u,exptf(v,car w));
  1680. if not zerop cdr w then u:=!*multf(u,!*p2f mksp(x,1));
  1681. return u
  1682. end;
  1683. symbolic procedure !*multfexpt(x,u,w);
  1684. begin scalar expon,v;
  1685. expon:=caddr x;
  1686. x:=cadr x;
  1687. w:=w * cadr expon;
  1688. expon:=caddr expon;
  1689. v:=gcdn(w,expon);
  1690. w:=w/v;
  1691. v:=expon/v;
  1692. if not (w > 0) then rederr "Invalid exponent"
  1693. else if v = 1
  1694. then return !*multf(u,exptf(if numberp x then x
  1695. else if atom x then !*k2f x
  1696. else !*q2f if car x eq '!*sq
  1697. then argof x
  1698. else simp x,
  1699. w));
  1700. expon:=0;
  1701. while not (w < v) do <<expon:=expon + 1; w:=w-v>>;
  1702. if expon>0 then u:=!*multf(u,exptf(!*q2f simp x,expon));
  1703. if w = 0 then return u;
  1704. x:=list('expt,x,list('quotient,1,v));
  1705. return multf(squashsqrt u,!*p2f mksp(x,w))
  1706. end;
  1707. symbolic procedure prefix!-rational!-numberp u;
  1708. % Tests for m/n in prefix representation.
  1709. eqcar(u,'quotient) and numberp cadr u and numberp caddr u;
  1710. symbolic procedure squashsqrtsq sq;
  1711. !*multsq(squashsqrt numr sq ./ 1,
  1712. 1 ./ squashsqrt denr sq);
  1713. symbolic procedure squashsqrt sf;
  1714. if (not sqrtflag) or atom sf or atom mvar sf
  1715. then sf
  1716. else if car mvar sf eq 'sqrt and ldeg sf > 1
  1717. then addf(squashsqrt red sf,!*multfsqrt(mvar sf,lc sf,ldeg sf))
  1718. else if car mvar sf eq 'expt
  1719. and prefix!-rational!-numberp caddr mvar sf
  1720. and ldeg sf >= caddr caddr mvar sf
  1721. then addf(squashsqrt red sf,!*multfexpt(mvar sf,lc sf,ldeg sf))
  1722. else (lpow sf .* squashsqrt lc sf) .+ squashsqrt red sf;
  1723. %remd 'simpx1;
  1724. %symbolic procedure simpx1(u,m,n);
  1725. % %u,m and n are prefix expressions;
  1726. % %value is the standard quotient expression for u**(m/n);
  1727. % begin scalar flg,z;
  1728. % if null frlis!* or null xn(frlis!*,flatten (m . n))
  1729. % then go to a;
  1730. % exptp!* := t;
  1731. % return !*k2q list('expt,u,if n=1 then m
  1732. % else list('quotient,m,n));
  1733. % a: if numberp m and fixp m then go to e
  1734. % else if atom m then go to b
  1735. % else if car m eq 'minus then go to mns
  1736. % else if car m eq 'plus then go to pls
  1737. % else if car m eq 'times and numberp cadr m and fixp cadr m
  1738. % and numberp n
  1739. % then go to tms;
  1740. % b: z := 1;
  1741. % c: if atom u and not numberp u then flag(list u,'used!*);
  1742. % u := list('expt,u,if n=1 then m else list('quotient,m,n));
  1743. % if not u member exptl!* then exptl!* := u . exptl!*;
  1744. % d: return mksq(u,if flg then -z else z); %u is already in lowest
  1745. %% %terms;
  1746. % e: if numberp n and fixp n then go to int;
  1747. % z := m;
  1748. % m := 1;
  1749. % go to c;
  1750. % mns: m := cadr m;
  1751. % if !*mcd then return invsq simpx1(u,m,n);
  1752. % flg := not flg;
  1753. % go to a;
  1754. % pls: z := 1 ./ 1;
  1755. % pl1: m := cdr m;
  1756. % if null m then return z;
  1757. % z := multsq(simpexpt list(u,
  1758. % list('quotient,if flg then list('minus,car m)
  1759. % else car m,n)),
  1760. % z);
  1761. % go to pl1;
  1762. % tms: z := gcdn(n,cadr m);
  1763. % n := n/z;
  1764. % z := cadr m/z;
  1765. % m := retimes cddr m;
  1766. % go to c;
  1767. % int:z := divide(m,n);
  1768. % if cdr z<0 then z:= (car z - 1) . (cdr z+n);
  1769. % if 0 = cdr z
  1770. % then return simpexpt list(u,car z);
  1771. % if n = 2
  1772. % then return multsq(simpexpt list(u,car z),
  1773. % simpsqrti u);
  1774. % return multsq(simpexpt list(u,car z),
  1775. % mksq(list('expt,u,list('quotient,1,n)),cdr z))
  1776. % end;
  1777. symbolic procedure !*exptsq(a,n);
  1778. % raise A to the power N using !*MULTSQ;
  1779. if n=0 then 1 ./ 1
  1780. else if n=1 then a
  1781. else if n<0 then !*exptsq(invsq a,-n)
  1782. else begin
  1783. scalar q,r;
  1784. q:=divide(n,2);
  1785. r:=cdr q; q:=car q;
  1786. q:=!*exptsq(!*multsq(a,a),q);
  1787. if r=0 then return q
  1788. else return !*multsq(a,q)
  1789. end;
  1790. symbolic procedure !*exptf(a,n);
  1791. % raise A to the power N using !*MULTF;
  1792. if n=0 then 1
  1793. else if n=1 then a
  1794. else begin
  1795. scalar q,r;
  1796. q:=divide(n,2);
  1797. r:=cdr q; q:=car q;
  1798. q:=!*exptf(!*multf(a,a),q);
  1799. if r=0 then return q
  1800. else return !*multf(a,q)
  1801. end;
  1802. endmodule;
  1803. module hacksqrt; % Routines for manipulation of sqrt expressions.
  1804. % Author: James H. Davenport.
  1805. fluid '(nestedsqrts thisplace);
  1806. exports sqrtsintree,sqrtsinsq,sqrtsinsql,sqrtsinsf,sqrtsign;
  1807. exports degreenest,sortsqrts;
  1808. imports mkvect,interr,getv,dependsp,union;
  1809. symbolic procedure sqrtsintree(u,var,slist);
  1810. % Adds to slist all the sqrts in the prefix-type tree u.
  1811. if atom u
  1812. then slist
  1813. else if car u eq '!*sq
  1814. then union(slist,sqrtsinsq(cadr u,var))
  1815. else if car u eq 'sqrt
  1816. then if dependsp(argof u,var)
  1817. then <<
  1818. slist:=sqrtsintree(argof u,var,slist);
  1819. % nested square roots
  1820. if member(u,slist)
  1821. then slist
  1822. else u.slist >>
  1823. else slist
  1824. else sqrtsintree(car u,var,sqrtsintree(cdr u,var,slist));
  1825. symbolic procedure sqrtsinsq(u,var);
  1826. % Returns list of all sqrts in sq.
  1827. sqrtsinsf(denr u,sqrtsinsf(numr u,nil,var),var);
  1828. symbolic procedure sqrtsinsql(u,var);
  1829. % Returns list of all sqrts in sq list.
  1830. if null u
  1831. then nil
  1832. else sqrtsinsf(denr car u,
  1833. sqrtsinsf(numr car u,sqrtsinsql(cdr u,var),var),var);
  1834. symbolic procedure sqrtsinsf(u,slist,var);
  1835. % Adds to slist all the sqrts in sf.
  1836. if domainp u or null u
  1837. then slist
  1838. else <<
  1839. if eqcar(mvar u,'sqrt) and
  1840. dependsp(argof mvar u,var) and
  1841. not member(mvar u,slist)
  1842. then begin
  1843. scalar slist2;
  1844. slist2:=sqrtsintree(argof mvar u,var,nil);
  1845. if slist2
  1846. then <<
  1847. nestedsqrts:=t;
  1848. slist:=union(slist2,slist) >>;
  1849. slist:=(mvar u).slist
  1850. end;
  1851. sqrtsinsf(lc u,sqrtsinsf(red u,slist,var),var) >>;
  1852. symbolic procedure easysqrtsign(slist,things);
  1853. % This procedure builds a list of all substitutions for all possible
  1854. % combinations of square roots in list.
  1855. if null slist
  1856. then things
  1857. else easysqrtsign(cdr slist,
  1858. nconc(mapcons(things,(car slist).(car slist)),
  1859. mapcons(things,
  1860. list(car slist,'minus,car slist))));
  1861. symbolic procedure hardsqrtsign(slist,things);
  1862. % This procedure fulfils the same role for nested sqrts
  1863. % ***assumption: the simpler sqrts come further up the list.
  1864. if null slist
  1865. then things
  1866. else begin
  1867. scalar thisplace,answers,pos,neg;
  1868. thisplace:=car slist;
  1869. answers:=mapcar(things,function (lambda u;sublis(u,thisplace).u));
  1870. pos:=mapcar(answers,function (lambda u;(thisplace.car u).(cdr u)));
  1871. % pos is sqrt(f) -> sqrt(innersubst f)
  1872. neg:=mapcar(answers,
  1873. function (lambda u;list(thisplace,'minus,car u).(cdr u)));
  1874. % neg is sqrt(f) -> -sqrt(innersubst f)
  1875. return hardsqrtsign(cdr slist,nconc(pos,neg))
  1876. end;
  1877. symbolic procedure degreenest(pf,var);
  1878. % Returns the maximum degree of nesting of var
  1879. % inside sqrts in the prefix form pf.
  1880. if atom pf
  1881. then 0
  1882. else if car pf eq 'sqrt
  1883. then if dependsp(cadr pf,var)
  1884. then iadd1 degreenest(cadr pf,var)
  1885. else 0
  1886. else if car pf eq 'expt
  1887. then if dependsp(cadr pf,var)
  1888. then if eqcar(caddr pf,'quotient)
  1889. then iadd1 degreenest(cadr pf,var)
  1890. else degreenest(cadr pf,var)
  1891. else 0
  1892. else degreenestl(cdr pf,var);
  1893. symbolic procedure degreenestl(u,var);
  1894. %Returns max degreenest from list of pfs u.
  1895. if null u
  1896. then 0
  1897. else max(degreenest(car u,var),
  1898. degreenestl(cdr u,var));
  1899. symbolic procedure sortsqrts(u,var);
  1900. % Sorts list of sqrts into order required by hardsqrtsign
  1901. % (and many other parts of the package).
  1902. begin
  1903. scalar i,v;
  1904. v:=mkvect(10); %should be good enough!
  1905. while u do <<
  1906. i:=degreenest(car u,var);
  1907. if i iequal 0
  1908. then interr "Non-dependent sqrt found";
  1909. if i > 10
  1910. then interr
  1911. "Degree of nesting exceeds 10 (recompile with 10 increased)";
  1912. putv(v,i,(car u).getv(v,i));
  1913. u:=cdr u >>;
  1914. u:=getv(v,10);
  1915. for i :=9 step -1 until 1 do
  1916. u:=nconc(getv(v,i),u);
  1917. return u
  1918. end;
  1919. symbolic procedure sqrtsign(sqrts,x);
  1920. if nestedsqrts then hardsqrtsign(sortsqrts(sqrts,x),list nil)
  1921. else easysqrtsign(sqrts,list nil);
  1922. endmodule;
  1923. module kron; % Kronecker factorization of univ. polys over integers.
  1924. % Authors: Mary Ann Moore and Arthur C. Norman.
  1925. global '(!*trint);
  1926. exports linfac,quadfac;
  1927. imports zfactor;
  1928. % Only linear and quadratic factors are found.
  1929. symbolic procedure linfac(w);
  1930. trykr(w,'(0 1));
  1931. symbolic procedure quadfac(w);
  1932. trykr(w,'(-1 0 1));
  1933. symbolic procedure trykr(w,points);
  1934. %Look for factor of w by evaluation at (points) and use of
  1935. % interpolate. Return (fac . cofac) with fac=nil if none
  1936. % found and cofac=nil if nothing worthwhile is left.
  1937. begin scalar values,attempt;
  1938. if null w then return nil . nil;
  1939. if (length points > car w) then return w . nil;
  1940. %that says if w is already tiny, it is already factored.
  1941. values:=mapcar(points,function (lambda x;
  1942. evalat(w,x)));
  1943. if !*trint then << printc ("At x= " . points);
  1944. printc ("p(x)= " . values)>>;
  1945. if 0 member values then go to lucky; %(x-1) is a factor!
  1946. values:=mapcar(values,function zfactors);
  1947. rplacd(values,mapcar(cdr values,function (lambda y;
  1948. append(y,mapcar(y,function minus)))));
  1949. if !*trint then <<printc "Possible factors go through some of";
  1950. print values>>;
  1951. attempt:=search4fac(w,values,nil);
  1952. if null attempt then attempt:=nil . w;
  1953. return attempt;
  1954. lucky: %here (x-1) is a factor because p(0) or p(1) or p(-1)
  1955. %vanished and cases p(0), p(-1) will have been removed
  1956. %elsewhere.
  1957. attempt:='(1 1 -1); %the factor
  1958. return attempt . testdiv(w,attempt)
  1959. end;
  1960. symbolic procedure zfactors n;
  1961. % Produces a list of all (positive) integer factors of the integer n.
  1962. if n=0 then list 0
  1963. else if (n:=abs n)=1 then list 1
  1964. else combinationtimes zfactor n;
  1965. symbolic procedure search4fac(w,values,cv);
  1966. % Combinatorial search. cv gets current selected value-set.
  1967. % Returns nil if fails, else factor . cofactor.
  1968. if null values then tryfactor(w,cv)
  1969. else begin scalar ff,q;
  1970. ff:=car values; %try all values here
  1971. loop: if null ff then return nil; %no factor found
  1972. q:=search4fac(w,cdr values,(car ff) . cv);
  1973. if null q then << ff:=cdr ff; go to loop>>;
  1974. return q
  1975. end;
  1976. symbolic procedure tryfactor(w,cv);
  1977. % Tests if cv represents a factor of w.
  1978. begin scalar ff,q;
  1979. if null cddr cv then ff:=linethrough(cadr cv,car cv)
  1980. else ff:=quadthrough(caddr cv,cadr cv,car cv);
  1981. if ff='failed then return nil; %it does not interpolate
  1982. q:=testdiv(w,ff);
  1983. if q='failed then return nil; %not a factor
  1984. return ff . q
  1985. end;
  1986. symbolic procedure evalat(p,n);
  1987. % Evaluate polynomial at integer point n.
  1988. begin scalar r;
  1989. r:=0;
  1990. p:=cdr p;
  1991. while not null p do <<
  1992. r:=n*r+car p;
  1993. p:=cdr p >>;
  1994. return r
  1995. end;
  1996. symbolic procedure testdiv(a,b);
  1997. % Quotient a/b or failed.
  1998. begin scalar q;
  1999. q:=testdiv1(cdr a,car a,cdr b,car b);
  2000. if q='failed then return q;
  2001. return (car a-car b) . q
  2002. end;
  2003. symbolic procedure testdiv1(a,da,b,db);
  2004. if da<db then begin
  2005. check0: if null a then return nil
  2006. else if not zerop car a then return 'failed;
  2007. a:=cdr a;
  2008. go to check0
  2009. end
  2010. else begin scalar q;
  2011. q:=divide(car a,car b);
  2012. if zerop cdr q then q:=car q
  2013. else return 'failed;
  2014. a:=testdiv1(ambq(cdr a,cdr b,q),da-1,b,db);
  2015. if a='failed then return a;
  2016. return q . a
  2017. end;
  2018. symbolic procedure ambq(a,b,q);
  2019. % A-B*Q with Q an integer.
  2020. if null b then a
  2021. else ((car a)-(car b)*q) . ambq(cdr a,cdr b,q);
  2022. symbolic procedure linethrough(y0,y1);
  2023. begin scalar a;
  2024. a:=y1-y0;
  2025. if zerop a then return 'failed;
  2026. if a<0 then <<a:=-a; y0:=-y0 >>;
  2027. if onep gcdn(a,y0) then return list(1,a,y0);
  2028. return 'failed
  2029. end;
  2030. symbolic procedure quadthrough(ym1,y0,y1);
  2031. begin scalar a,b,c;
  2032. a:=divide(ym1+y1,2);
  2033. if zerop cdr a then a:=(car a)-y0
  2034. else return 'failed;
  2035. if zerop a then return 'failed; %linear things already done.
  2036. c:=y0;
  2037. b:=divide(y1-ym1,2);
  2038. if zerop cdr b then b:=car b
  2039. else return 'failed;
  2040. if not onep gcdn(a,gcd(b,c)) then return 'failed;
  2041. if a<0 then <<a:=-a; b:=-b; c:=-c>>;
  2042. return list(2,a,b,c)
  2043. end;
  2044. endmodule;
  2045. module lowdeg; % Splitting of low degree polynomials.
  2046. % Author: To be determined.
  2047. fluid '(clogflag knowndiscrimsign zlist);
  2048. global '(!*trint);
  2049. exports forceazero,makepolydf,quadratic,covecdf,exponentdf;
  2050. imports dfquotdf,gcdf,interr,minusdfp,multdf,multdfconst,!*multf,
  2051. negsq,minusp,printsq,multsq,invsq,pnth,nth,mknill,
  2052. negdf,plusdf,printdf,printsq,quotf,sqrtdf,var2df,vp2,addsq,sub1;
  2053. symbolic procedure covecdf(pol,var,degree);
  2054. % Extract coefficients of polynomial wrt var, given a degree-bound
  2055. % degree. Result is a lisp vector.
  2056. begin scalar v,x,w;
  2057. w:=pol;
  2058. v:=mkvect(degree);
  2059. while not null w do <<
  2060. x:=exponentof(var,lpow w,zlist);
  2061. if (x<0) or (x>degree) then interr "Bad degree in covecdf";
  2062. putv(v,x,lt w . getv(v,x));
  2063. w:=red w >>;
  2064. for i:=0:degree do putv(v,i,multdf(reversewoc getv(v,i),
  2065. var2df(var,-i,zlist)));
  2066. return v
  2067. end;
  2068. symbolic procedure quadratic(pol,var,res);
  2069. % Add in to res logs or arctans corresponding to splitting the
  2070. % polynomial. Pol given that it is quadratic wrt var.
  2071. % Does not assume pol is univariate.
  2072. begin scalar a,b,c,w,discrim;
  2073. w:=covecdf(pol,var,2);
  2074. a:=getv(w,2); b:=getv(w,1); c:=getv(w,0);
  2075. % that split the quadratic up to find the coefficients a,b,c.
  2076. if !*trint then << printc "a="; printdf a;
  2077. printc "b="; printdf b;
  2078. printc "c="; printdf c>>;
  2079. discrim:=plusdf(multdf(b,b),
  2080. multdfconst((-4) . 1,multdf(a,c)));
  2081. if !*trint then << printc "Discriminant is";
  2082. printdf discrim>>;
  2083. if null discrim then interr "Discrim=0 in quadratic";
  2084. if knowndiscrimsign
  2085. then <<if knowndiscrimsign eq 'negative then go to atancase>>
  2086. else if (not clogflag) and (minusdfp discrim)
  2087. then go to atancase;
  2088. discrim:=sqrtdf(discrim);
  2089. if discrim='failed then go to nofactors;
  2090. if !*trint then << printc "Square root is";
  2091. printdf discrim>>;
  2092. w:=var2df(var,1,zlist);
  2093. w:=multdf(w,a);
  2094. b:=multdfconst(1 ./ 2,b);
  2095. discrim:=multdfconst(1 ./ 2,discrim);
  2096. w:=plusdf(w,b); %a*x+b/2.
  2097. a:=plusdf(w,discrim); b:=plusdf(w,negdf(discrim));
  2098. if !*trint then << printc "Factors are";
  2099. printdf a; printdf b>>;
  2100. return ('log . a) . ('log . b) . res;
  2101. atancase:
  2102. discrim:=sqrtdf negdf discrim; %sqrt(4*a*c-b**2) this time!
  2103. if discrim='failed then go to nofactors; %sqrt did not exist?
  2104. res := ('log . pol) . res; %one part of the answer
  2105. a:=multdf(a,var2df(var,1,zlist));
  2106. a:=plusdf(b,multdfconst(2 ./ 1,a));
  2107. a:=dfquotdf(a,discrim); %assumes division is exact
  2108. return ('atan . a) . res;
  2109. nofactors:
  2110. if !*trint
  2111. then <<printc
  2112. "The following quadratic does not seem to factor";
  2113. printdf pol>>;
  2114. return ('log . pol) . res
  2115. end;
  2116. symbolic procedure exponentof(var,l,zl);
  2117. if null zl then interr "Var not found in exponentof"
  2118. else if var=car zl then car l
  2119. else exponentof(var,cdr l,cdr zl);
  2120. symbolic procedure df2sf a;
  2121. if null a then nil
  2122. else if ((null red a) and
  2123. (denr lc a = 1) and
  2124. (lpow a=vp2 zlist)) then numr lc a
  2125. else interr "Nasty cubic or quartic";
  2126. symbolic procedure makepolydf p;
  2127. % Multiply df by lcm of denominators of all coefficient denominators.
  2128. begin scalar h,w;
  2129. if null(w:=p) then return nil; %poly is zero already.
  2130. h:=denr lc w; %a good start.
  2131. w:=red w;
  2132. while not null w do <<
  2133. h:=quotf(!*multf(h,denr lc w),gcdf(h,denr lc w));
  2134. w:=red w >>;
  2135. %h is now lcm of denominators.
  2136. return multdfconst(h ./ 1,p)
  2137. end;
  2138. symbolic procedure forceazero(p,n);
  2139. %Shift polynomial p so that coeff of x**(n-1) vanishes.
  2140. %Return the amount of the shift, update (vector) p.
  2141. begin scalar r,i,w;
  2142. for i:=0:n do putv(p,i,df2sf getv(p,i)); %convert to polys.
  2143. r:=getv(p,n-1);
  2144. if null r then return nil ./ 1; %already zero.
  2145. r:= !*multsq(r ./ 1,invsq(!*multf(n,getv(p,n)) ./ 1));
  2146. % Used to be subs2q multsq
  2147. %the shift amount.
  2148. %now I have to set p:=subst(x-r,x,p) and then reduce to sf again.
  2149. if !*trint then << printc "Shift is by ";
  2150. printsq r>>;
  2151. w:=mkvect(n); %workspace vector.
  2152. for i:=0:n do putv(w,i,nil ./ 1); %zero it.
  2153. i:=n;
  2154. while not minusp i do <<
  2155. mulvecbyxr(w,negsq r,n); %W:=(X-R)*W;
  2156. putv(w,0,addsq(getv(w,0),getv(p,i) ./ 1));
  2157. i:=i-1 >>;
  2158. if !*trint then << printc "SQ shifted poly is";
  2159. print w>>;
  2160. for i:=0:n do putv(p,i,getv(w,i));
  2161. w:=denr getv(p,0);
  2162. for i:=1:n do w:=quotf(!*multf(w,denr getv(p,i)),
  2163. gcdf(w,denr getv(p,i)));
  2164. for i:=0:n do putv(p,i,numr !*multsq(getv(p,i),w ./ 1));
  2165. % Used to be subs2q multsq
  2166. w:=getv(p,0);
  2167. for i:=1:n do w:=gcdf(w,getv(p,i));
  2168. if not (w=1) then
  2169. for i:=0:n do putv(p,i,quotf(getv(p,i),w));
  2170. if !*trint then << printc "Final shifted poly is ";
  2171. print p>>;
  2172. return r
  2173. end;
  2174. symbolic procedure mulvecbyxr(w,r,n);
  2175. % W is a vector representing a poly of degree n.
  2176. % Multiply it by (x+r).
  2177. begin scalar i,im1;
  2178. i:=n;
  2179. im1:=sub1 i;
  2180. while not minusp im1 do <<
  2181. putv(w,i,!*addsq(getv(w,im1),!*multsq(r,getv(w,i))));
  2182. % Used to be subs2q addsq/multsq
  2183. i:=im1; im1:=sub1 i >>;
  2184. putv(w,0,!*multsq(getv(w,0),r));
  2185. % Used to be subs2q multsq
  2186. return w
  2187. end;
  2188. endmodule;
  2189. module reform; % Reformulate expressions using C-constant substitution.
  2190. % Authors: Mary Ann Moore and Arthur C. Norman.
  2191. fluid '(cmap cval loglist ulist);
  2192. global '(!*trint);
  2193. exports logstosq,substinulist;
  2194. imports prepsq,mksp,nth,multsq,addsq,domainp,invsq,plusdf;
  2195. symbolic procedure substinulist ulist;
  2196. % Substitutes for the C-constants in the values of the U's given in
  2197. % ULIST. Result is a D.F.
  2198. if null ulist then nil
  2199. else begin scalar temp,lcu;
  2200. lcu:=lc ulist;
  2201. temp:=evaluateuconst numr lcu;
  2202. if null numr temp then temp:=nil
  2203. else temp:=((lpow ulist) .*
  2204. !*multsq(temp,!*invsq(denr lcu ./ 1))) .+ nil;
  2205. return plusdf(temp,substinulist red ulist)
  2206. end;
  2207. symbolic procedure evaluateuconst coefft;
  2208. % Substitutes for the C-constants into COEFFT (=S.F.). Result is S.Q.;
  2209. if null coefft or domainp coefft then coefft ./ 1
  2210. else begin scalar temp;
  2211. if null(temp:=assoc(mvar coefft,cmap)) then
  2212. temp:=(!*p2f lpow coefft) ./ 1
  2213. else temp:=getv(cval,cdr temp);
  2214. temp:=!*multsq(temp,evaluateuconst(lc coefft));
  2215. % Next line had addsq previously
  2216. return !*addsq(temp,evaluateuconst(red coefft))
  2217. end;
  2218. symbolic procedure logstosq;
  2219. % Converts LOGLIST to sum of the log terms as a S.Q.;
  2220. begin scalar lglst,logsq,i,temp;
  2221. i:=1;
  2222. lglst:=loglist;
  2223. logsq:=nil ./ 1;
  2224. loop: if null lglst then return logsq;
  2225. temp:=cddr car lglst;
  2226. if !*trint
  2227. then <<printc "SF arg for log etc ="; printc temp>>;
  2228. if not (caar lglst='iden) then <<
  2229. temp:=prepsq temp; %convert to prefix form.
  2230. temp:=list(caar lglst,temp); %function name.
  2231. temp:=((mksp(temp,1) .* 1) .+ nil) ./ 1 >>;
  2232. temp:=!*multsq(temp,getv(cval,i));
  2233. % Next line had addsq previously
  2234. logsq:=!*addsq(temp,logsq);
  2235. lglst:=cdr lglst;
  2236. i:=i+1;
  2237. go to loop
  2238. end;
  2239. endmodule;
  2240. module simplog; % Simplify logarithms.
  2241. % Authors: Mary Ann Moore and Arthur C. Norman.
  2242. exports simplog,simplogsq;
  2243. imports quotf,prepf,mksp,simp!*,!*multsq,simptimes,addsq,minusf,negf,
  2244. addf,comfac,negsq,mk!*sq,carx;
  2245. symbolic procedure simplog(exxpr); simplogi carx(exxpr,'simplog);
  2246. symbolic procedure simplogi(sq);
  2247. begin
  2248. if atom sq then go to simplify;
  2249. if car sq eq 'times
  2250. then return simpplus(for each u in cdr sq
  2251. collect mk!*sq simplogi u);
  2252. if car sq eq 'quotient
  2253. then return addsq(simplogi cadr sq,
  2254. negsq simplogi caddr sq);
  2255. if car sq eq 'expt
  2256. then return simptimes list(caddr sq,
  2257. mk!*sq simplogi cadr sq);
  2258. if car sq eq 'nthroot
  2259. then return !*multsq(1 ./ caddr sq,simplogi cadr sq);
  2260. % we had (nthroot of n).
  2261. if car sq eq 'sqrt
  2262. then return !*multsq(1 ./ 2,simplogi argof sq);
  2263. if car sq = '!*sq
  2264. then return simplogsq cadr sq;
  2265. simplify:
  2266. sq:=simp!* sq;
  2267. return simplogsq sq
  2268. end;
  2269. symbolic procedure simplogsq sq;
  2270. addsq((simplog2 numr sq),negsq(simplog2 denr sq));
  2271. symbolic procedure simplog2(sf);
  2272. if atom sf
  2273. then if null sf then rederr "Log 0 formed"
  2274. else if numberp sf
  2275. then if sf iequal 1
  2276. then nil ./ 1
  2277. else if sf iequal 0 then rederr "Log 0 formed"
  2278. else((mksp(list('log,sf),1) .* 1) .+ nil) ./ 1
  2279. else formlog(sf)
  2280. else begin
  2281. scalar form;
  2282. form:=comfac sf;
  2283. if not null car form
  2284. then return addsq(formlog(form .+ nil),
  2285. simplog2 quotf(sf,form .+ nil));
  2286. % we have killed common powers.
  2287. form:=cdr form;
  2288. if form neq 1
  2289. then return addsq(simplog2 form,
  2290. simplog2 quotf(sf,form));
  2291. % remove a common factor from the sf.
  2292. return (formlog sf)
  2293. end;
  2294. symbolic procedure formlogterm(sf);
  2295. begin
  2296. scalar u;
  2297. u:=mvar sf;
  2298. if not atom u and (car u member '(times sqrt expt nthroot))
  2299. then u:=addsq(simplog2 lc sf,
  2300. !*multsq(simplogi u,simp!* ldeg sf))
  2301. else if (lc sf iequal 1) and (ldeg sf iequal 1)
  2302. then u:=((mksp(list('log,u),1) .* 1) .+ nil) ./ 1
  2303. else u:=addsq(simptimes list(list('log,u),ldeg sf),
  2304. simplog2 lc sf);
  2305. return u
  2306. end;
  2307. symbolic procedure formlog sf;
  2308. if null red sf
  2309. then formlogterm sf
  2310. else if minusf sf
  2311. then addf((mksp(list('log,-1),1) .* 1) .+ nil,
  2312. formlog2 negf sf) ./ 1
  2313. else (formlog2 sf) ./ 1;
  2314. symbolic procedure formlog2 sf;
  2315. ((mksp(list('log,prepf sf),1) .* 1) .+ nil);
  2316. endmodule;
  2317. module simpsqrt; % Simplify square roots.
  2318. % Authors: Mary Ann Moore and Arthur C. Norman.
  2319. % Heavily modified J.H. Davenport for algebraic functions.
  2320. fluid '(!*backtrace !*conscount !*galois !*pvar basic!-listofallsqrts
  2321. gaussiani basic!-listofnewsqrts kord!* knowntobeindep
  2322. listofallsqrts listofnewsqrts sqrtflag sqrtlist
  2323. sqrt!-places!-alist variable varlist zlist);
  2324. global '(!*tra !*trint);
  2325. % This module should be rewritten in terms of the REDUCE function
  2326. % SIMPSQRT;
  2327. % remd 'simpsqrt;
  2328. exports proper!-simpsqrt,simpsqrti,simpsqrtsq,simpsqrt2,sqrtsave,
  2329. newplace,actualsimpsqrt,formsqrt;
  2330. symbolic procedure proper!-simpsqrt(exprn);
  2331. simpsqrti carx(exprn,'proper!-simpsqrt);
  2332. symbolic procedure simpsqrti sq;
  2333. begin
  2334. scalar u;
  2335. if atom sq
  2336. then if numberp sq
  2337. then return (simpsqrt2 sq) ./ 1
  2338. else if (u:=get(sq,'avalue))
  2339. then return simpsqrti cadr u
  2340. % BEWARE!!! This is VERY system dependent.
  2341. else return simpsqrt2((mksp(sq,1) .* 1) .+ nil) ./ 1;
  2342. % If it doesnt have an AVALUE then it is itself;
  2343. if car sq eq 'times
  2344. then return mapply(function multsq,
  2345. mapcar(cdr sq,function simpsqrti));
  2346. if car sq eq 'quotient
  2347. then return multsq(simpsqrti cadr sq,
  2348. invsq simpsqrti caddr sq);
  2349. if car sq eq 'expt and numberp caddr sq
  2350. then if evenp caddr sq
  2351. then return simpexpt list(cadr sq,caddr sq / 2)
  2352. else return simpexpt
  2353. list(mk!*sq simpsqrti cadr sq,caddr sq);
  2354. if car sq = '!*sq
  2355. then return simpsqrtsq cadr sq;
  2356. return simpsqrtsq tidysqrt simp!* sq
  2357. end;
  2358. symbolic procedure simpsqrtsq sq;
  2359. (simpsqrt2 numr sq) ./ (simpsqrt2 denr sq);
  2360. symbolic procedure simpsqrt2 sf;
  2361. if minusf sf
  2362. then if sf iequal -1
  2363. then gaussiani
  2364. else begin
  2365. scalar u;
  2366. u:=negf sf;
  2367. if numberp u
  2368. then return multf(gaussiani,simpsqrt3 u);
  2369. % we cannot negate general expressions for the following reason:
  2370. % (%%%thesis remark%%%)
  2371. % sqrt(x*x-1) under x->1/x gives sqrt(1-x*x)/x=i*sqrt(x*x-1)/x
  2372. % under x->1/x gives x*i*sqrt(-1+1/x*x)=i**2*sqrt(x*x-1)
  2373. % hence an abysmal catastrophe;
  2374. return simpsqrt3 sf
  2375. end
  2376. else simpsqrt3 sf;
  2377. symbolic procedure simpsqrt3 sf;
  2378. begin
  2379. scalar u;
  2380. u:=assoc(sf,listofallsqrts);
  2381. if u
  2382. then return cdr u;
  2383. % now see if 'knowntobeindep'can help.
  2384. u:=atsoc(listofnewsqrts,knowntobeindep);
  2385. if null u
  2386. then go to no;
  2387. u:=assoc(sf,cdr u);
  2388. if u
  2389. then <<
  2390. listofallsqrts:=u.listofallsqrts;
  2391. return cdr u >>;
  2392. no:
  2393. u:=actualsimpsqrt sf;
  2394. listofallsqrts:=(sf.u).listofallsqrts;
  2395. return u
  2396. end;
  2397. symbolic procedure sqrtsave(u,v,place);
  2398. begin
  2399. scalar a;
  2400. %u is new value of listofallsqrts, v of new.
  2401. a:=assoc(place,sqrt!-places!-alist);
  2402. if null a
  2403. then sqrt!-places!-alist:=(place.(listofnewsqrts.listofallsqrts))
  2404. .sqrt!-places!-alist
  2405. else rplacd(a,listofnewsqrts.listofallsqrts);
  2406. listofnewsqrts:=v;
  2407. % throw away things we are not going to need in future.
  2408. if not !*galois
  2409. then listofallsqrts:=u;
  2410. % we cannot guarantee the validity of our calculations.
  2411. if listofallsqrts eq u
  2412. then return nil;
  2413. v:=listofallsqrts;
  2414. while not (cdr v eq u) do
  2415. v:=cdr v;
  2416. rplacd(v,nil);
  2417. % listofallsqrts is all those added since routine was entered.
  2418. v:=atsoc(listofnewsqrts,knowntobeindep);
  2419. if null v
  2420. then knowntobeindep:=(listofnewsqrts.listofallsqrts)
  2421. . knowntobeindep
  2422. else rplacd(v,union(cdr v,listofallsqrts));
  2423. listofallsqrts:=u;
  2424. return nil
  2425. end;
  2426. symbolic procedure newplace(u);
  2427. % Says to restart algebraic bases at a new place u.
  2428. begin
  2429. scalar v;
  2430. v:=assoc(u,sqrt!-places!-alist);
  2431. if null v
  2432. then <<
  2433. listofallsqrts:=basic!-listofallsqrts;
  2434. listofnewsqrts:=basic!-listofnewsqrts >>
  2435. else <<
  2436. v:=cdr v;
  2437. listofnewsqrts:=car v;
  2438. listofallsqrts:=cdr v >>;
  2439. return if v then v
  2440. else listofnewsqrts.listofallsqrts
  2441. end;
  2442. symbolic procedure mknewsqrt u;
  2443. % U is prefix form.
  2444. begin
  2445. scalar v,w;
  2446. if not !*galois then go to new;
  2447. % no checking required.
  2448. v:=addf(!*p2f mksp(!*pvar,2),negf !*q2f tidysqrt simp u);
  2449. % count !*conscount;
  2450. w:=errorset(list('afactor,mkquote v,mkquote !*pvar),t,!*backtrace);
  2451. % if !*tra then <<
  2452. % princ "*** That took ";
  2453. % princ (!*conscount - count nil);
  2454. % printc " conses" >>;
  2455. % count 0;
  2456. if atom w
  2457. then go to new
  2458. else w:=car w; %the actual result of afactor.
  2459. if cdr w
  2460. then go to notnew;
  2461. new:
  2462. w:=sqrtify u;
  2463. listofnewsqrts:=w . listofnewsqrts;
  2464. return !*kk2f w;
  2465. notnew:
  2466. w:=car w;
  2467. v:=stt(w,!*pvar);
  2468. if car v neq 1
  2469. then rederr "HELP ...";
  2470. w:=addf(w,multf(cdr v,(mksp(!*pvar,car v) .* -1) .+nil));
  2471. w:=sqrt2top(w ./ cdr v);
  2472. w:=quotf(numr w,denr w);
  2473. if null w
  2474. then rederr "Division failure";
  2475. return w
  2476. end;
  2477. symbolic procedure actualsimpsqrt(sf);
  2478. if sf iequal -1
  2479. then gaussiani
  2480. else actualsqrtinner(sf,listofnewsqrts);
  2481. symbolic procedure actualsqrtinner(sf,l);
  2482. if null l
  2483. then actualsimpsqrt2 sf
  2484. else begin
  2485. scalar z;
  2486. % z:=simp argof car l;
  2487. % if denr z neq 1 or (z := numr z) iequal -1
  2488. z:=!*q2f simp argof car l;
  2489. if z iequal -1
  2490. then return actualsqrtinner(sf,cdr l);
  2491. z:=quotf(sf,z);
  2492. if null z
  2493. then return actualsqrtinner(sf,cdr l);
  2494. return !*multf(!*kk2f car l,actualsimpsqrt z)
  2495. end;
  2496. symbolic procedure actualsimpsqrt2(sf);
  2497. if atom sf
  2498. then if null sf
  2499. then nil
  2500. else if numberp sf
  2501. then if sf < 0
  2502. then multf(gaussiani,actualsimpsqrt2(- sf))
  2503. %Above 2 lines inserted JHD 4 Sept 80;
  2504. % test case: SQRT(B*X**2-C)/SQRT(X);
  2505. else begin
  2506. scalar n;
  2507. n:=int!-sqrt sf;
  2508. % Changed for conformity with DEC20 LISP JHD July 1982;
  2509. if not fixp n
  2510. then return mknewsqrt sf
  2511. else return n
  2512. end
  2513. else mknewsqrt(sf)
  2514. else begin
  2515. scalar form;
  2516. form:=comfac sf;
  2517. if car form
  2518. then return multf((if null cdr sf and (car sf = form)
  2519. then formsqrt(form .+ nil)
  2520. else simpsqrt2(form .+ nil)),
  2521. %The above 2 lines changed by JHD;
  2522. %(following suggestions of Morrison);
  2523. %to conform to Standard LISP 4 Sept 80;
  2524. simpsqrt2 quotf(sf,form .+ nil));
  2525. % we have killed common powers.
  2526. form:=cdr form;
  2527. if form neq 1
  2528. then return multf(simpsqrt2 form,
  2529. simpsqrt2 quotf(sf,form));
  2530. % remove a common factor from the sf.
  2531. return formsqrt sf
  2532. end;
  2533. symbolic procedure int!-sqrt n;
  2534. % Return sqrt of n if same is exact, or something non-numeric
  2535. % otherwise.
  2536. if not numberp n then 'nonnumeric
  2537. else if n<0 then 'negative
  2538. else if floatp n then sqrt!-float n
  2539. else if n<2 then n
  2540. else int!-nr(n,(n+1)/2);
  2541. symbolic procedure int!-nr(n,root);
  2542. % root is an overestimate here. nr moves downwards to root;
  2543. begin
  2544. scalar w;
  2545. w:=root*root;
  2546. if n=w then return root;
  2547. w:=(root+n/root)/2;
  2548. if w>=root then return !*q2f simpsqrt list n;
  2549. return int!-nr(n,w)
  2550. end;
  2551. symbolic procedure formsqrt(sf);
  2552. if (null red sf)
  2553. then if (lc sf iequal 1) and (ldeg sf iequal 1)
  2554. then mknewsqrt mvar sf
  2555. else multf(if evenp ldeg sf
  2556. then !*p2f mksp(mvar sf,ldeg sf / 2)
  2557. else exptf(mknewsqrt mvar sf,ldeg sf),simpsqrt2 lc sf)
  2558. else begin
  2559. scalar varlist,zlist,sqrtlist,sqrtflag;
  2560. scalar v,l,n,w;
  2561. % This returns a list, the i-th member of which is
  2562. % a list of the factors of multiplicity i (as s.f's);
  2563. v:=jsqfree(sf,if variable and involvesf(sf,variable)
  2564. then variable
  2565. else findatom mvar sf);
  2566. % VARIABLE is the best thing to do square-free
  2567. % decompositions with respect to, but anything
  2568. % else will do if VARIABLE is not set;
  2569. if null cdr v and null cdar v
  2570. then return mknewsqrt prepf sf;
  2571. % The JSQFREE did nothing;
  2572. l:=nil;
  2573. n:=0;
  2574. while v do <<
  2575. n:=n+1;
  2576. w:=car v;
  2577. while w do <<
  2578. l:=list('expt,mk!*sq !*f2q car w,n) . l;
  2579. w:=cdr w >>;
  2580. v:=cdr v >>;
  2581. if null cdr l
  2582. then l:=car l
  2583. else l:='times.l;
  2584. % makes L into a valid prefix form;
  2585. return !*q2f simpsqrti l
  2586. end;
  2587. symbolic procedure findatom pf;
  2588. if atom pf
  2589. then pf
  2590. else findatom argof pf;
  2591. symbolic procedure sqrtify u;
  2592. % Actually creates the sqrt.
  2593. begin
  2594. scalar v,n,prinlist;
  2595. n:=degreenest(u,nil);
  2596. % v:=list('sqrt,u);
  2597. v := mksqrt u; % To ensure sqrt**2 rule set.
  2598. prinlist:=member(v,kord!*);
  2599. if prinlist then return car prinlist;
  2600. % This might improve sharing.
  2601. % anyway, we mustn't re-add this object to KORD!*;
  2602. while kord!* and
  2603. eqcar(car kord!*,'sqrt) and
  2604. (degreenest(argof car kord!*,nil) > n) do <<
  2605. prinlist:=(car kord!*) . prinlist;
  2606. kord!*:=cdr kord!* >>;
  2607. kord!*:=v . kord!*;
  2608. while prinlist do <<
  2609. kord!*:=(car prinlist) . kord!*;
  2610. prinlist:=cdr prinlist >>;
  2611. return v
  2612. end;
  2613. % deflist ('((sqrt (((x) quotient (sqrt x) (times 2 x))))),'dfn);
  2614. % put('sqrt,'simpfn,'proper!-simpsqrt); % Now in driver.
  2615. endmodule;
  2616. module isolve; % Routines for solving the final reduction equation.
  2617. % Author: Mary Ann Moore and Arthur C. Norman.
  2618. % Modifications by: John P. Fitch.
  2619. fluid '(badpart
  2620. ccount
  2621. cmap
  2622. cmatrix
  2623. cval
  2624. indexlist
  2625. lhs!*
  2626. lorder
  2627. nnn
  2628. orderofelim
  2629. pt
  2630. rhs!*
  2631. sillieslist
  2632. tanlist
  2633. ulist
  2634. zlist);
  2635. global '(!*number!* !*statistics !*trint);
  2636. exports solve!-for!-u;
  2637. imports nth,findpivot,gcdf,int!-gensym1,mkvect,interr,multdfconst,
  2638. !*multf!*,negdf,orddf,plusdf,printdf,printsf,printspreadc,printsq,
  2639. quotf,putv,spreadc,subst4eliminatedcs,mknill,pnth,domainp,addf,
  2640. invsq,multsq;
  2641. symbolic procedure uterm(powu,rhs!*);
  2642. % Finds the contribution from RHS!* of reduction equation, of the;
  2643. % U-coefficient given by POWU. Result is in D.F.;
  2644. if null rhs!* then nil
  2645. else begin scalar coef,power;
  2646. power:=addinds(powu,lpow rhs!*);
  2647. coef:=evaluatecoeffts(numr lc rhs!*,powu);
  2648. if null coef then return uterm(powu,red rhs!*);
  2649. coef:=coef ./ denr lc rhs!*;
  2650. return plusdf((power .* coef) .+ nil,uterm(powu,red rhs!*))
  2651. end;
  2652. symbolic procedure solve!-for!-u(rhs!*,lhs!*,ulist);
  2653. % Solves the reduction eqn LHS!*=RHS!*. Returns list of U-coefficients
  2654. % and their values (ULIST are those we have so far), and a list of
  2655. % C-equations to be solved (CLIST are the eqns we have so far).
  2656. if null lhs!* then ulist
  2657. else begin scalar u,lpowlhs;
  2658. lpowlhs:=lpow lhs!*;
  2659. begin scalar ll,mm,chge; ll:=maxorder(rhs!*,zlist,0);
  2660. mm:=lorder;
  2661. while mm do << if car ll < car mm then
  2662. << chge:=t; rplaca(mm,car ll) >>;
  2663. ll:=cdr ll; mm:=cdr mm >>;
  2664. if !*trint and chge then << print ("Maxorder now ".lorder) >>
  2665. end;
  2666. u:=pickupu(rhs!*,lpow lhs!*,t);
  2667. if null u then
  2668. << if !*trint then << printc "***** C-equation to solve:";
  2669. printsf numr lc lhs!*;
  2670. printc " = 0";
  2671. printc " ">>;
  2672. % Remove a zero constant from the lhs, rather than use
  2673. % Gauss Elim;
  2674. if gausselimn(numr lc lhs!*,lt lhs!*) then
  2675. lhs!*:=squashconstants(red lhs!*)
  2676. else lhs!*:=red lhs!* >>
  2677. else
  2678. << ulist:=(car u .
  2679. !*multsq(coefdf(lhs!*,lpowlhs),invsq cdr u)).ulist;
  2680. % used to be subs2q multsq
  2681. if !*statistics then !*number!*:=!*number!*+1;
  2682. if !*trint then <<prin2 "***** U"; prin2 car u; prin2t " =";
  2683. printsq multsq(coefdf(lhs!*,lpowlhs),invsq cdr u);
  2684. printc " ">>;
  2685. lhs!*:=plusdf(lhs!*,
  2686. negdf multdfconst(cdar ulist,uterm(car u,rhs!*))) >>;
  2687. if !*trint then << printc ".... LHS is now:";
  2688. printdf lhs!*;
  2689. printc " ">>;
  2690. return solve!-for!-u(rhs!*,lhs!*,ulist)
  2691. end;
  2692. symbolic procedure squashconstants(express);
  2693. begin scalar constlst,ii,xp,cl,subby,cmt,xx;
  2694. constlst:=reverse cmap;
  2695. cmt:=cmatrix;
  2696. xxx: xx:=car cmt; % Look at next row of Cmatrix;
  2697. cl:=constlst; % and list of the names;
  2698. ii:=1; % will become index of removed constant;
  2699. while not getv(xx,ii) do
  2700. << ii:=ii+1; cl:=cdr cl >>;
  2701. subby:=caar cl; %II is now index, and SUBBY the name;
  2702. if member(subby,sillieslist) then
  2703. <<cmt:=cdr cmt; go to xxx>>; %This loop must terminate;
  2704. % This is because at least one constant remains;
  2705. xp:=prepsq !*f2q getv(xx,0); % start to build up the answer;
  2706. cl:=cdr cl;
  2707. if not (ccount=ii) then for jj:=ii+1:ccount do <<
  2708. if getv(xx,jj) then
  2709. xp:=list('plus,xp,
  2710. list('times,caar cl,
  2711. prepsq !*f2q getv(xx,jj)));
  2712. cl:=cdr cl >>;
  2713. xp:=list('quotient,list('minus,xp),
  2714. prepsq !*f2q getv(xx,ii));
  2715. if !*trint then << prin2 "Replace "; prin2 subby;
  2716. prin2 " by "; printsq simp xp >>;
  2717. sillieslist:=subby . sillieslist;
  2718. return subdf(express,xp,subby)
  2719. end;
  2720. symbolic procedure checku(ulist,u);
  2721. % Checks that U is not already in ULIST - ie. that this u-coefficient;
  2722. % has not already been given a value;
  2723. if null ulist then nil
  2724. else if (car u) = caar ulist then t
  2725. else checku(cdr ulist,u);
  2726. symbolic procedure checku1(powu,rhs!*);
  2727. %Checks that use of a particular U-term will not cause trouble;
  2728. %by introducing negative exponents into lhs when it is used;
  2729. begin
  2730. top:
  2731. if null rhs!* then return nil;
  2732. if negind(powu,lpow rhs!*) then
  2733. if not null evaluatecoeffts(numr lc rhs!*,powu) then return t;
  2734. rhs!*:=red rhs!*;
  2735. go to top
  2736. end;
  2737. symbolic procedure negind(pu,pr);
  2738. %check if substituting index values in power gives rise to -ve
  2739. % exponents;
  2740. if null pu then nil
  2741. else if (car pu+caar pr)<0 then t
  2742. else negind(cdr pu,cdr pr);
  2743. symbolic procedure evaluatecoeffts(coefft,indlist);
  2744. % Substitutes the values of the i,j,k,...'s that appear in the S.F. ;
  2745. % COEFFT (=coefficient of r.h.s. of reduction equation). Result is S.F.;
  2746. if null coefft or domainp coefft then
  2747. if coefft=0 then nil else coefft
  2748. else begin scalar temp;
  2749. if mvar coefft member indexlist then
  2750. temp:=valuecoefft(mvar coefft,indlist,indexlist)
  2751. else temp:=!*p2f lpow coefft;
  2752. temp:=!*multf(temp,evaluatecoeffts(lc coefft,indlist));
  2753. return addf(temp,evaluatecoeffts(red coefft,indlist))
  2754. end;
  2755. symbolic procedure valuecoefft(var,indvalues,indlist);
  2756. % Finds the value of VAR, which should be in INDLIST, given INDVALUES;
  2757. % - the corresponding values of INDLIST variables;
  2758. if null indlist then interr "Valuecoefft - no value"
  2759. else if var eq car indlist then
  2760. if car indvalues=0 then nil
  2761. else car indvalues
  2762. else valuecoefft(var,cdr indvalues,cdr indlist);
  2763. symbolic procedure addinds(powu,powrhs);
  2764. % Adds indices in POWU to those in POWRHS. Result is LPOW of D.F.;
  2765. if null powu then if null powrhs then nil
  2766. else interr "Powrhs too long"
  2767. else if null powrhs then interr "Powu too long"
  2768. else (car powu + caar powrhs).addinds(cdr powu,cdr powrhs);
  2769. symbolic procedure pickupu(rhs!*,powlhs,flg);
  2770. % Picks up the 'lowest' U coefficient from RHS!* if it exists and
  2771. % returns it in the form of LT of D.F..
  2772. % Returns NIL if no legal term in RHS!* can be found.
  2773. % POWLHS is the power we want to match (LPOW of D.F).
  2774. % and COEFFU is the list of previous coefficients that must be zero;
  2775. begin scalar coeffu,u;
  2776. pt:=rhs!*;
  2777. top:
  2778. if null pt then return nil; %no term found - failed;
  2779. u:=nextu(lt pt,powlhs); %check this term...;
  2780. if null u then go to notthisone;
  2781. if not testord(car u,lorder) then go to neverthisone;
  2782. if not checkcoeffts(coeffu,car u) then go to notthisone;
  2783. %that inhibited clobbering things already passed over;
  2784. if checku(ulist,u) then go to notthisone;
  2785. %that avoided redefining a u value;
  2786. if checku1(car u,rhs!*) then go to neverthisone;
  2787. %avoid introduction of negative exponents;
  2788. if flg then
  2789. u:=patchuptan(list u,powlhs,red pt,rhs!*);
  2790. return u;
  2791. neverthisone:
  2792. coeffu:=(lc pt) . coeffu;
  2793. notthisone:
  2794. pt:=red pt;
  2795. go to top
  2796. end;
  2797. symbolic procedure patchuptan(u,powlhs,rpt,rhs!*);
  2798. begin
  2799. scalar uu,cc,dd,tanlist,redu,redu1;
  2800. pt:=rpt;
  2801. while pt do <<
  2802. if (uu:=pickupu(pt,powlhs,nil))
  2803. and testord(car uu,lorder) then <<
  2804. % Nasty found, patch it up;
  2805. cc:=(int!-gensym1('!C).caar u).cc;
  2806. % CC is an alist of constants;
  2807. if !*trint then <<prin2 "***** U";
  2808. prin2 caar u;
  2809. prin2t " =";
  2810. print caar cc >>;
  2811. redu:=plusdf(redu,
  2812. multdfconst(!*k2q caar cc,uterm(caar u,rhs!*)));
  2813. u:=uu.u
  2814. >>;
  2815. if pt then pt:=red pt >>;
  2816. redu1:=redu;
  2817. while redu1 do begin scalar xx; xx:=car redu1;
  2818. if !*trint then << prin2 "Introduced residue "; print xx >>;
  2819. if (not testord(car xx,lorder)) then <<
  2820. if !*trint then <<
  2821. printsq cdr xx; printc " = 0" >>;
  2822. if dd:=killsingles(cadr xx,cc) then <<
  2823. redu:=subdf(redu,0,car dd);
  2824. redu1:=subdf(redu1,0,car dd);
  2825. ulist:=((cdr dd).(nil ./ 1)).ulist;
  2826. u:=rmve(u,cdr dd);
  2827. cc:=purgeconst(cc,dd) >>
  2828. else redu1:=cdr redu1 >>
  2829. else redu1:=cdr redu1 end;
  2830. for each xx in redu do <<
  2831. if (not testord(car xx,lorder)) then <<
  2832. while cc do <<
  2833. addctomap(caar cc);
  2834. ulist:=((cdar cc).(!*k2q caar cc))
  2835. . ulist;
  2836. if !*statistics
  2837. then !*number!*:=!*number!*+1;
  2838. cc:=cdr cc >>;
  2839. gausselimn(numr lc redu,lt redu)>> >>;
  2840. if redu then << while cc do << addctomap(caar cc);
  2841. ulist:=((cdar cc).(!*k2q caar cc)).ulist;
  2842. if !*statistics then !*number!*:=!*number!*+1;
  2843. cc:=cdr cc >>;
  2844. lhs!*:=plusdf(lhs!*,negdf redu) >>;
  2845. return car u
  2846. end;
  2847. symbolic procedure killsingles(xx,cc);
  2848. if atom xx then nil
  2849. else if not (cdr xx eq nil) then nil
  2850. else begin scalar dd;
  2851. dd:=assoc(caaar xx,cc);
  2852. if dd then return dd;
  2853. return killsingles(cdar xx,cc)
  2854. end;
  2855. symbolic procedure rmve(l,x);
  2856. if caar l=x then cdr l else cons(car l,rmve(cdr l,x));
  2857. symbolic procedure subdf(a,b,c);
  2858. % SUBSTITUTE B FOR C INTO THE DF A;
  2859. % Used to get rid of silly constants introduced;
  2860. if a=nil then nil else
  2861. begin scalar x;
  2862. x:=subs2q subf(numr lc a,list (c . b)) ;
  2863. if x=(nil . 1) then return subdf(red a,b,c)
  2864. else return plusdf(
  2865. list ((lpow a).((car x).!*multf(cdr x,denr lc a))),
  2866. subdf(red a,b,c))
  2867. end;
  2868. symbolic procedure testord(a,b);
  2869. % Test order of two DF's in recursive fashion;
  2870. if null a then t
  2871. else if car a leq car b then testord(cdr a,cdr b)
  2872. else nil;
  2873. symbolic procedure tanfrom(rhs!*,z,nnn);
  2874. % We notice that in all bad cases we have (j-num)tan**j...;
  2875. % Extract the num;
  2876. begin scalar n,zz,r,rr;
  2877. r:=rhs!*;
  2878. n:=0; zz:=zlist;
  2879. while car zz neq z do << n:=n+1; zz:=cdr zz >>;
  2880. a: if null r then go to b;
  2881. rr:=caar r; % The list of powers;
  2882. for i:=1:n do rr:=cdr rr;
  2883. if fixp caar rr then if caar rr>0 then <<
  2884. rr:=numr cdar r;
  2885. if null red rr then rr:=nil ./ 1
  2886. else if fixp (rr:=quotf(red rr,lc rr))
  2887. then rr:=-rr else rr:=0>>;
  2888. if atom rr then go to b;
  2889. r:=cdr r;
  2890. go to a;
  2891. b: if null r then return maxfrom(lhs!*,nnn)+1;
  2892. return max(rr,maxfrom(lhs!*,nnn)+1)
  2893. end;
  2894. symbolic procedure coefdf(y,u);
  2895. if y=nil then nil
  2896. else if lpow y=u then lc y
  2897. else coefdf(red y,u);
  2898. symbolic procedure purgeconst(a,b);
  2899. % Remove a const from and expression. May be the same as DELETE?;
  2900. if null a then nil
  2901. else if car a=b then purgeconst(cdr a,b)
  2902. else cons(car a,purgeconst(cdr a,b));
  2903. symbolic procedure maxorder(rhs!*,z,n);
  2904. % Find a limit on the order of terms, theis is ad hoc;
  2905. if null z then nil
  2906. else if eqcar(car z,'sqrt) then
  2907. cons(1,maxorder(rhs!*,cdr z,n+1))
  2908. else if (atom car z) or (caar z neq 'tan) then
  2909. cons(maxfrom(lhs!*,n)+1,maxorder(rhs!*,cdr z,n+1))
  2910. else cons(tanfrom(rhs!*,car z,n),maxorder(rhs!*,cdr z,n+1));
  2911. symbolic procedure maxfrom(l,n);
  2912. % Largest order in the nth varable;
  2913. if null l then 0
  2914. else max(nth(caar l,n+1),maxfrom(cdr l,n));
  2915. symbolic procedure copy u;
  2916. if atom u then u
  2917. else cons(copy car u,copy cdr u);
  2918. symbolic procedure addctomap cc;
  2919. begin
  2920. scalar ncval;
  2921. ccount:=ccount+1;
  2922. ncval:=mkvect(ccount);
  2923. for i:=0:(ccount-1) do putv(ncval,i,getv(cval,i));
  2924. putv(ncval,ccount,nil ./ 1);
  2925. cval:=ncval;
  2926. cmap:=(cc . ccount).cmap;
  2927. if !*trint then << prin2 "Constant map changed to "; print cmap >>;
  2928. cmatrix:=mapcar(cmatrix,function addtovector);
  2929. end;
  2930. symbolic procedure addtovector v;
  2931. begin scalar vv;
  2932. vv:=mkvect(ccount);
  2933. for i:=0:(ccount-1) do putv(vv,i,getv(v,i));
  2934. putv(vv,ccount,nil);
  2935. return vv
  2936. end;
  2937. symbolic procedure checkcoeffts(cl,indv);
  2938. % checks to see that the coefficients in CL (coefficient list - S.Q.s);
  2939. % are zero when the i,j,k,... are given values in INDV (LPOW of;
  2940. % D.F.). if so the result is true else NIL=false;
  2941. if null cl then t
  2942. else begin scalar res;
  2943. res:=evaluatecoeffts(numr car cl,indv);
  2944. if not(null res or res=0) then return nil
  2945. else return checkcoeffts(cdr cl,indv)
  2946. end;
  2947. symbolic procedure nextu(ltrhs,powlhs);
  2948. % picks out the appropriate U coefficients for term: LTRHS to match the
  2949. % powers of the z-variables given in POWLHS (= exponent list of D.F.).
  2950. % return this coefficient in form LT of D.F. If U coefficient does
  2951. % not exist then result is NIL. If it is multiplied by a zero then
  2952. % result is NIL;
  2953. if null ltrhs then nil
  2954. else begin scalar indlist,ucoefft;
  2955. indlist:=subtractinds(powlhs,car ltrhs,nil);
  2956. if null indlist then return nil;
  2957. ucoefft:=evaluatecoeffts(numr cdr ltrhs,indlist);
  2958. if null ucoefft or ucoefft=0 then return nil;
  2959. return indlist .* (ucoefft ./ denr cdr ltrhs)
  2960. end;
  2961. symbolic procedure subtractinds(powlhs,l,sofar);
  2962. % subtract the indices in list L from those in POWLHS to find;
  2963. % appropriate values for i,j,k,... when equating coefficients of terms;
  2964. % on lhs of reduction eqn. SOFAR is the resulting value list we;
  2965. % have constructed so far. if any i,j,k,... value is -ve then result;
  2966. % is NIL;
  2967. if null l then reversewoc sofar
  2968. else if ((car powlhs)-(caar l))<0 then nil
  2969. else subtractinds(cdr powlhs,cdr l,
  2970. ((car powlhs)-(caar l)) . sofar);
  2971. symbolic procedure gausselimn(equation,tokill);
  2972. % Performs Gaussian elimination on the matrix for the c-equations;
  2973. % as each c-equation is found. EQUATION is the next one to deal with;
  2974. begin scalar newrow,pivot;
  2975. if zerop ccount then go to noway; %failure
  2976. newrow:=mkvect(ccount);
  2977. spreadc(equation,newrow,1);
  2978. subst4eliminatedcs(newrow,reverse orderofelim,reverse cmatrix);
  2979. pivot:=findpivot newrow;
  2980. if null pivot then go to nopivotfound;
  2981. orderofelim:=pivot . orderofelim;
  2982. newrow:=makeprim newrow; %remove hcf from new equation
  2983. cmatrix:=newrow . cmatrix;
  2984. % if !*trint then printspreadc newrow;
  2985. return t;
  2986. nopivotfound:
  2987. if null getv(newrow,0) then <<
  2988. if !*trint then printc "Already included";
  2989. return nil>>; %equation was 0=0
  2990. noway:
  2991. badpart:=tokill . badpart; %non-integrable term.
  2992. if !*trint then printc "Inconsistent";
  2993. return nil
  2994. end;
  2995. symbolic procedure makeprim row;
  2996. begin scalar g;
  2997. g:=getv(row,0);
  2998. for i:=1:ccount do g:=gcdf(g,getv(row,i));
  2999. if g neq 1 then
  3000. for i:=0:ccount do putv(row,i,quotf(getv(row,i),g));
  3001. for i := 0:ccount do
  3002. <<g := getv(row,i);
  3003. if g and not domainp g
  3004. then putv(row,i,numr resimp((rootextractf g) ./ 1))>>;
  3005. return row
  3006. end;
  3007. endmodule;
  3008. module sqrtf; % Square root of standard forms.
  3009. % Authors: Mary Ann Moore and Arthur C. Norman.
  3010. fluid '(!*noextend zlist);
  3011. exports minusdfp,sqrtdf,nrootn,domainp,minusf;
  3012. imports contentsmv,gcdf,interr,!*multf,partialdiff,printdf,quotf,
  3013. simpsqrt2,vp2;
  3014. symbolic procedure minusdfp a;
  3015. % Test sign of leading coedd of d.f.
  3016. if null a then interr "Minusdfp 0 illegal"
  3017. else minusf numr lc a;
  3018. symbolic procedure sqrtdf l;
  3019. % Takes square root of distributive form. "Failed" usually means
  3020. % that the square root is not among already existing objects.
  3021. if null l then nil
  3022. else begin scalar c;
  3023. if lpow l=vp2 zlist then go to ok;
  3024. c:=sqrtsq df2q l;
  3025. if numr c eq 'failed
  3026. then return 'failed;
  3027. if denr c eq 'failed
  3028. then return 'failed;
  3029. return for each u in f2df numr c
  3030. collect (car u).!*multsq(cdr u,1 ./ denr c);
  3031. ok: c:=sqrtsq lc l;
  3032. if numr c eq 'failed or
  3033. denr c eq 'failed
  3034. then return 'failed
  3035. else return (lpow l .* c) .+nil
  3036. end;
  3037. symbolic procedure sqrtsq a;
  3038. sqrtf numr a ./ sqrtf denr a;
  3039. symbolic procedure sqrtf p;
  3040. begin scalar ip,qp;
  3041. if null p then return nil;
  3042. ip:=sqrtf1 p;
  3043. qp:=cdr ip;
  3044. ip:=car ip; %respectable and nasty parts of the sqrt.
  3045. if qp=1 then return ip; %exact root found.
  3046. if !*noextend then return 'failed;
  3047. % We cannot add new square roots in this case, since it is
  3048. % then impossible to determine if one square root depends
  3049. % on another if new ones are being added all the time.
  3050. if zlistp qp then return 'failed;
  3051. % Liouville's theorem tells you that you never need to add
  3052. % new algebraics depending on the variable of integration.
  3053. qp:=simpsqrt2 qp;
  3054. return !*multf(ip,qp)
  3055. end;
  3056. symbolic procedure zlistp qp;
  3057. if atom qp then member(qp,zlist)
  3058. else or(member(mvar qp,zlist),zlistp lc qp,zlistp red qp);
  3059. symbolic procedure sqrtf1 p;
  3060. % Returns a . b with p=a**2*b.
  3061. if domainp p
  3062. then if fixp p then nrootn(p,2)
  3063. else !*q2f simpsqrt list prepf p . 1
  3064. else begin scalar co,pp,g,pg;
  3065. co:=contentsmv(p,mvar p,nil); %contents of p.
  3066. pp:=quotf(p,co); %primitive part.
  3067. co:=sqrtf1(co); %process contents via recursion.
  3068. g:=gcdf(pp,partialdiff(pp,mvar pp));
  3069. pg:=quotf(pp,g);
  3070. g:=gcdf(g,pg); %a repeated factor of pp.
  3071. if g=1 then pg:=1 . pp
  3072. else <<
  3073. pg:= quotf(pp,!*multf(g,g)); %what is still left.
  3074. pg:=sqrtf1(pg); %split that up.
  3075. rplaca(pg,!*multf(car pg,g))>>;
  3076. %put in the thing found here.
  3077. rplaca(pg, !*multf(car pg,car co));
  3078. rplacd(pg, !*multf(cdr pg,cdr co));
  3079. return pg
  3080. end;
  3081. % NROOTN removed as in REDUCE base.
  3082. endmodule;
  3083. module tdiff; % Differentiation routines for integrator.
  3084. % Authors: Mary Ann Moore and Arthur C. Norman.
  3085. exports !-!-simpdf;
  3086. imports simpcar,kernp,diffsq,prepsq,msgpri;
  3087. flag('(!-!-simpdf),'lose);
  3088. symbolic procedure !-!-simpdf u;
  3089. % U is a list of forms, the first an expression and the remainder
  3090. % kernels and numbers.
  3091. % Value is derivative of first form wrt rest of list.
  3092. begin scalar v,x,y,tt;
  3093. tt := time(); %start the clock;
  3094. v := cdr u;
  3095. u := simpcar u;
  3096. a: if null v or null numr u then go to exit;
  3097. x := if null y or y=0 then simpcar v else y;
  3098. if null kernp x then go to e;
  3099. x := caaaar x;
  3100. v := cdr v;
  3101. if null v then go to c;
  3102. y := simpcar v;
  3103. if null numr y then go to d
  3104. else if not denr y=1 or not numberp numr y then go to c;
  3105. y := car y;
  3106. v := cdr v;
  3107. b: if y=0 then go to a;
  3108. u := diffsq(u,x);
  3109. y := y-1;
  3110. go to b;
  3111. c: u := diffsq(u,x);
  3112. go to a;
  3113. d: y := nil;
  3114. v := cdr v;
  3115. go to a;
  3116. exit:
  3117. print list('time,time()-tt);
  3118. return u;
  3119. e: msgpri("Differentiation wrt",prepsq x,"not allowed",nil,t)
  3120. end;
  3121. put('tdf,'simpfn,'!-!-simpdf);
  3122. endmodule;
  3123. module tidysqrt; % General tidying up of square roots.
  3124. % Authors: Mary Ann Moore and Arthur C. Norman.
  3125. % Modifications by J.H. Davenport.
  3126. exports sqrt2top,tidysqrt;
  3127. %symbolic procedure tidysqrtdf a;
  3128. % if null a then nil
  3129. % else begin scalar tt,r;
  3130. % tt:=tidysqrt lc a;
  3131. % r:=tidysqrtdf red a;
  3132. % if null numr tt then return r;
  3133. % return ((lpow a) .* tt) .+ r
  3134. % end;
  3135. %
  3136. symbolic procedure tidysqrt q;
  3137. begin scalar nn,dd;
  3138. nn:=tidysqrtf numr q;
  3139. if null nn then return nil ./ 1; %answer is zero.
  3140. dd:=tidysqrtf denr q;
  3141. return multsq(nn,invsq dd)
  3142. end;
  3143. symbolic procedure tidysqrtf p;
  3144. %Input - standard form.
  3145. %Output - standard quotient.
  3146. %Simplifies sqrt(a)**n with n>1.
  3147. if domainp p then p ./ 1
  3148. else begin scalar v,w;
  3149. v:=lpow p;
  3150. if car v='i then v:=mksp('(sqrt -1),cdr v); %I->sqrt(-1);
  3151. if eqcar(car v,'sqrt) and not onep cdr v
  3152. then begin scalar x;
  3153. %here we have a reduction to apply.
  3154. x:=divide(cdr v,2); %halve exponent.
  3155. w:=exptsq(simp cadar v,car x); %rational part of answer.
  3156. if not zerop cdr x then w:=multsq(w,
  3157. ((mksp(car v,1) .* 1) .+ nil) ./ 1);
  3158. %the next line allows for the horrors of nested sqrts.
  3159. w:=tidysqrt w
  3160. end
  3161. else w:=((v .* 1) .+ nil) ./ 1;
  3162. v:=multsq(w,tidysqrtf lc p);
  3163. return addsq(v,tidysqrtf red p)
  3164. end;
  3165. symbolic procedure multoutdenr q;
  3166. % Move sqrts in a sq to the numerator.
  3167. begin scalar n,d,root,conj;
  3168. n:=numr q;
  3169. d:=denr q;
  3170. while (root:=findsquareroot d) do <<
  3171. conj:=conjugatewrt(d,root);
  3172. n:=!*multf(n,conj);
  3173. d:=!*multf(d,conj) >>;
  3174. while (root:=findnthroot d) do <<
  3175. conj:=conjugateexpt(d,root,kord!*);
  3176. n:=!*multf(n,conj);
  3177. d:=!*multf(d,conj) >>;
  3178. return (n . d);
  3179. end;
  3180. symbolic procedure conjugateexpt(d,root,kord!*);
  3181. begin scalar ord,ans,repl,xi;
  3182. ord:=caddr caddr root; % the denominator of the exponent;
  3183. ans:=1;
  3184. kord!*:= (xi:=gensym()) . kord!*;
  3185. % XI is an ORD'th root of unity;
  3186. for i:=1:ord-1 do <<
  3187. ans:=!*multf(ans,numr subf(d,
  3188. list(root . list('times,root,list('explt,xi,i)))));
  3189. while (mvar ans eq xi) and ldeg ans > ord do
  3190. ans:=addf(red ans,(xi) to (ldeg ans - ord) .* lc ans .+ nil);
  3191. if (mvar ans eq xi) and ldeg ans = ord then
  3192. ans:=addf(red ans,lc ans) >>;
  3193. if (mvar ans eq xi) and ldeg ans = ord-1 then <<
  3194. repl:=-1;
  3195. for i:=1:ord-2 do
  3196. repl:=(xi) to i .* -1 .+ repl;
  3197. ans:=addf(red ans,!*multf(lc ans,repl)) >>;
  3198. if not domainp ans and mvar ans eq xi
  3199. then interr "Conjugation failure";
  3200. return ans;
  3201. end;
  3202. symbolic procedure sqrt2top q;
  3203. begin
  3204. scalar n,d;
  3205. n:=multoutdenr q;
  3206. d:=denr n;
  3207. n:=numr n;
  3208. if d eq denr q
  3209. then return q;%no change.
  3210. if d iequal 1
  3211. then return (n ./ 1);
  3212. q:=gcdcoeffsofsqrts n;
  3213. if q iequal 1
  3214. then if minusf d
  3215. then return (negf n ./ negf d)
  3216. else return (n ./ d);
  3217. q:=gcdf(q,d);
  3218. n:=quotf(n,q);
  3219. d:=quotf(d,q);
  3220. if minusf d
  3221. then return (negf n ./ negf d)
  3222. else return (n ./ d)
  3223. end;
  3224. %symbolic procedure denrsqrt2top q;
  3225. %begin
  3226. % scalar n,d;
  3227. % n:=multoutdenr q;
  3228. % d:=denr n;
  3229. % n:=numr n;
  3230. % if d eq denr q
  3231. % then return d; % no changes;
  3232. % if d iequal 1
  3233. % then return 1;
  3234. % q:=gcdcoeffsofsqrts n;
  3235. % if q iequal 1
  3236. % then return d;
  3237. % q:=gcdf(q,d);
  3238. % if q iequal 1
  3239. % then return d
  3240. % else return quotf(d,q)
  3241. % end;
  3242. symbolic procedure findsquareroot p;
  3243. % Locate a sqrt symbol in poly p.
  3244. if domainp p then nil
  3245. else begin scalar w;
  3246. w:=mvar p; %check main var first.
  3247. if atom w
  3248. then return nil; %we have passed all sqrts.
  3249. if eqcar(w,'sqrt) then return w;
  3250. w:=findsquareroot lc p;
  3251. if null w then w:=findsquareroot red p;
  3252. return w
  3253. end;
  3254. symbolic procedure findnthroot p;
  3255. nil; % Until corrected.
  3256. symbolic procedure x!-findnthroot p;
  3257. % Locate an n-th root symbol in poly p.
  3258. if domainp p then nil
  3259. else begin scalar w;
  3260. w:=mvar p; %check main var first.
  3261. if atom w
  3262. then return nil; %we have passed all sqrts.
  3263. if eqcar(w,'expt) and eqcar(caddr w,'quotient) then return w;
  3264. w:=findnthroot lc p;
  3265. if null w then w:=findnthroot red p;
  3266. return w
  3267. end;
  3268. symbolic procedure conjugatewrt(p,var);
  3269. % Var -> -var in form p.
  3270. if domainp p then p
  3271. else if mvar p=var then begin
  3272. scalar x,c,r;
  3273. x:=tdeg lt p; %degree
  3274. c:=lc p; %coefficient
  3275. r:=red p; %reductum
  3276. x:=remainder(x,2); %now just 0 or 1.
  3277. if x=1 then c:=negf c; %-coefficient.
  3278. return (lpow p .* c) .+ conjugatewrt(r,var) end
  3279. else if ordop(var,mvar p) then p
  3280. else (lpow p .* conjugatewrt(lc p,var)) .+
  3281. conjugatewrt(red p,var);
  3282. symbolic procedure gcdcoeffsofsqrts u;
  3283. if atom u
  3284. then if numberp u and minusp u
  3285. then -u
  3286. else u
  3287. else if eqcar(mvar u,'sqrt)
  3288. then begin
  3289. scalar v;
  3290. v:=gcdcoeffsofsqrts lc u;
  3291. if v iequal 1
  3292. then return v
  3293. else return gcdf(v,gcdcoeffsofsqrts red u)
  3294. end
  3295. else begin
  3296. scalar root;
  3297. root:=findsquareroot u;
  3298. if null root
  3299. then return u;
  3300. u:=makemainvar(u,root);
  3301. root:=gcdcoeffsofsqrts lc u;
  3302. if root iequal 1
  3303. then return 1
  3304. else return gcdf(root,gcdcoeffsofsqrts red u)
  3305. end;
  3306. endmodule;
  3307. module trcase; % Driving routine for integration of transcendental fns.
  3308. % Authors: Mary Ann Moore and Arthur C. Norman.
  3309. % Modifications by: John P. Fitch.
  3310. fluid '(!*backtrace
  3311. !*nowarnings
  3312. !*purerisch
  3313. !*reverse
  3314. badpart
  3315. ccount
  3316. cmap
  3317. cmatrix
  3318. content
  3319. cuberootflag
  3320. cval
  3321. denbad
  3322. denominator
  3323. indexlist
  3324. lhs!*
  3325. loglist
  3326. lorder
  3327. orderofelim
  3328. rhs!*
  3329. sillieslist
  3330. sqfr
  3331. sqrtflag
  3332. sqrtlist
  3333. tanlist
  3334. svar
  3335. varlist
  3336. xlogs
  3337. zlist);
  3338. % !*reverse: flag to re-order zlist.
  3339. % !*nowarnings: flag to lose messages.
  3340. global '(!*failhard
  3341. !*number!*
  3342. !*ratintspecial
  3343. !*seplogs
  3344. !*spsize!*
  3345. !*statistics
  3346. !*trint
  3347. gensymcount);
  3348. switch failhard;
  3349. exports transcendentalcase;
  3350. imports backsubst4cs,countz,createcmap,createindices,df2q,dfnumr,
  3351. difflogs,fsdf,factorlistlist,findsqrts,findtrialdivs,gcdf,mkvect,
  3352. interr,logstosq,mergin,multbyarbpowers,!*multf,multsqfree,
  3353. printdf,printsq,quotf,rationalintegrate,putv,
  3354. simpint1,solve!-for!-u,sqfree,sqmerge,sqrt2top,substinulist,trialdiv,
  3355. mergein,negsq,addsq,f2df,mknill,pnth,invsq,multsq,domainp,mk!*sq,
  3356. mksp,prettyprint,prepsq;
  3357. % Note that SEPLOGS keeps logarithmic part of result together as a
  3358. % kernel form, but this can lead to quite messy results.
  3359. symbolic
  3360. procedure transcendentalcase(integrand,svar,xlogs,zlist,varlist);
  3361. begin scalar divlist,jhd!-content,content,prim,sqfr,dfu,indexlist,
  3362. % JHD!-CONTENT is local, while CONTENT is free (set in SQFREE).
  3363. sillieslist,originalorder,wrongway,
  3364. sqrtlist,tanlist,loglist,dflogs,eprim,dfun,unintegrand,
  3365. sqrtflag,badpart,rhs!*,lhs!*,gcdq,cmap,cval,orderofelim,cmatrix;
  3366. scalar cuberootflag,ccount,denominator,result,denbad;
  3367. gensymcount:=0;
  3368. integrand:=sqrt2top integrand; % Move the sqrts to the numerator.
  3369. if !*trint then << printc "Extension variables z<i> are";
  3370. print zlist>>;
  3371. if !*ratintspecial and null cdr zlist then
  3372. return rationalintegrate(integrand,svar);
  3373. % *** now unnormalize integrand, maybe ***.
  3374. begin scalar w,gg;
  3375. gg:=1;
  3376. foreach z in zlist do <<
  3377. w:=subs2 diffsq(simp z,svar);
  3378. gg:=!*multf(gg,quotf(denr w,gcdf(denr w,gg))) >>;
  3379. gg:=quotf(gg,gcdf(gg,denr integrand));
  3380. unintegrand:=(!*multf(gg,numr integrand)
  3381. ./ !*multf(gg,denr integrand));
  3382. if !*trint then <<
  3383. printc "Unnormalized integrand =";
  3384. printsq unintegrand >> end;
  3385. divlist:=findtrialdivs zlist;
  3386. %also puts some things on loglist sometimes.
  3387. % if !*trint
  3388. % then << printc "Exponentials and tans to try dividing:";
  3389. % print divlist>>;
  3390. sqrtlist:=findsqrts zlist;
  3391. % if !*trint then << printc "Square-root z-variables";
  3392. % print sqrtlist >>;
  3393. divlist:=trialdiv(denr unintegrand,divlist);
  3394. % if !*trint then << printc "Divisors:";
  3395. % print car divlist;
  3396. % print cdr divlist>>;
  3397. %n.b. the next line also sets 'content' as a free variable.
  3398. % Since SQFREE may be used later, we copy it into JHD!-CONTENT.
  3399. prim:=sqfree(cdr divlist,zlist);
  3400. jhd!-content:=content;
  3401. printfactors(prim,nil);
  3402. eprim:=sqmerge(countz car divlist,prim,nil);
  3403. printfactors(eprim,t);
  3404. % if !*trint then << terpri();
  3405. % printsf denominator;
  3406. % terpri();
  3407. % printc "...content is:";
  3408. % printsf jhd!-content>>;
  3409. sqfr:=for each u in eprim collect multup u;
  3410. % sqfr:=multsqfree eprim;
  3411. % if !*trint then << printc "...sqfr is:";
  3412. % superprint sqfr>>;
  3413. if !*reverse then zlist:=reverse zlist; %ALTER ORDER FUNCTION;
  3414. indexlist:=createindices zlist;
  3415. % if !*trint then << printc "...indices are:";
  3416. % superprint indexlist>>;
  3417. dfu:=dfnumr(svar,car divlist);
  3418. % if !*trint then << terpri();
  3419. % printc "************ Derivative of u is:";
  3420. % printsq dfu>>;
  3421. loglist:=append(loglist,factorlistlist (prim,nil));
  3422. loglist:=mergein(xlogs,loglist);
  3423. loglist:=mergein(tanlist,loglist);
  3424. cmap:=createcmap();
  3425. ccount:=length cmap;
  3426. if !*trint then << printc "Loglist ";
  3427. print loglist >>;
  3428. dflogs:=difflogs(loglist,denr unintegrand,svar);
  3429. if !*trint then << printc "************ 'Derivative' of logs is:";
  3430. printsq dflogs>>;
  3431. dflogs:=addsq((numr unintegrand) ./ 1,negsq dflogs);
  3432. % Put everything in reduction eqn over common denominator.
  3433. gcdq:=gcdf(denr dflogs,denr dfu);
  3434. dfun:= !*multf(numr dfu,
  3435. denbad:=quotf(denr dflogs,gcdq));
  3436. denbad:=!*multf(denr dfu,denbad);
  3437. denbad:= !*multf(denr unintegrand,denbad);
  3438. dflogs:= !*multf(numr dflogs,quotf(denr dfu,gcdq));
  3439. dfu:=dfun;
  3440. % Now DFU and DFLOGS are S.F.s.
  3441. rhs!*:=multbyarbpowers f2df dfu;
  3442. if checkdffail(rhs!*,svar) then interr "Simplification failure";
  3443. if !*trint then << printc "Distributed Form of U is:";
  3444. printdf rhs!*>>;
  3445. lhs!*:=f2df dflogs;
  3446. if checkdffail(lhs!*,svar) then interr "Simplification failure";
  3447. if !*trint then << printc "Distributed Form of l.h.s. is:";
  3448. printdf lhs!*;
  3449. terpri()>>;
  3450. cval:=mkvect(ccount);
  3451. for i:=0 : ccount do putv(cval,i,nil ./ 1);
  3452. lorder:=maxorder(rhs!*,zlist,0);
  3453. originalorder:=lorder;
  3454. if !*trint then << printc "Maximum order determined as ";
  3455. print lorder >>;
  3456. if !*statistics then << !*number!*:=0;
  3457. !*spsize!*:=1;
  3458. foreach xx in lorder do
  3459. !*spsize!*:=!*spsize!* * (xx+1) >>;
  3460. % That calculates the largest U that can appear.
  3461. dfun:=solve!-for!-u(rhs!*,lhs!*,nil);
  3462. backsubst4cs(nil,orderofelim,cmatrix);
  3463. % if !*trint then if not (ccount=0) then printvecsq cval;
  3464. if !*statistics then << prin2 !*number!*; prin2 " used out of ";
  3465. printc !*spsize!* >>;
  3466. badpart:=substinulist badpart;
  3467. %substitute for c<i> still in badpart.
  3468. dfun:=df2q substinulist dfun;
  3469. % if !*trint then superprint dfun;
  3470. result:= !*multsq(dfun,!*invsq(denominator ./ 1));
  3471. result:= !*multsq(result,!*invsq(jhd!-content ./ 1));
  3472. % if !*trint then superprint result;
  3473. dflogs:=logstosq();
  3474. if not null numr dflogs then <<
  3475. if !*seplogs and (not domainp numr result) then <<
  3476. result:=mk!*sq result;
  3477. result:=(mksp(result,1) .* 1) .+ nil;
  3478. result:=result ./ 1 >>;
  3479. result:=addsq(result,dflogs)>>;
  3480. if !*trint then << superprint result;
  3481. terpri();
  3482. printc
  3483. "*****************************************************";
  3484. printc
  3485. "************ THE INTEGRAL IS : **********************";
  3486. printc
  3487. "*****************************************************";
  3488. terpri();
  3489. printsq result;
  3490. terpri()>>;
  3491. if not null badpart then <<
  3492. if !*trint then printc "plus a bad part";
  3493. lhs!*:=badpart;
  3494. lorder:=maxorder(rhs!*,zlist,0);
  3495. while lorder do <<
  3496. if car lorder > car originalorder then
  3497. wrongway:=t;
  3498. lorder:=cdr lorder;
  3499. originalorder:=cdr originalorder >>;
  3500. dfun:=df2q badpart;
  3501. if !*trint
  3502. then <<printsq dfun; printc "Denbad = "; printsf denbad>>;
  3503. dfun:= !*multsq(dfun,invsq(denbad ./ 1));
  3504. if wrongway then << result:= nil ./ 1; dfun:=integrand >>;
  3505. if rootcheckp(unintegrand,svar) then
  3506. return simpint1(integrand . svar.nil)
  3507. else if !*purerisch or allowedfns zlist then
  3508. dfun:=simpint1 (dfun . svar.nil)
  3509. else << !*purerisch:=t;
  3510. if !*trint
  3511. then <<printc " [Transforming ..."; printsq dfun>>;
  3512. denbad:=transform(dfun,svar);
  3513. if denbad=dfun
  3514. then dfun:=simpint1(dfun . svar.nil)
  3515. else <<denbad:=errorset('(integratesq denbad svar xlogs),
  3516. !*backtrace,!*backtrace);
  3517. if not atom denbad then dfun:=untan car denbad
  3518. else dfun:=simpint1(dfun . svar.nil) >> >>;
  3519. if !*trint then printsq dfun;
  3520. if !*failhard then rederr "FAILHARD switch set";
  3521. if !*seplogs and not domainp result then <<
  3522. result:=mk!*sq result;
  3523. if not numberp result
  3524. then result:=(mksp(result,1) .* 1) .+ nil;
  3525. result:=result ./ 1>>;
  3526. result:=addsq(result,dfun) >>;
  3527. % if !*overlaymode then excise transcode;
  3528. return sqrt2top result
  3529. end;
  3530. symbolic procedure checkdffail(u,v);
  3531. u and (depends(lc u,v) or checkdffail(red u,v));
  3532. symbolic procedure printfactors(w,prdenom);
  3533. % W is a list of factors to each power. If PRDENOM is true
  3534. % this prints denominator of answer, else prints square-free
  3535. % decomposition.
  3536. begin scalar i,wx;
  3537. i:=1;
  3538. if prdenom then <<
  3539. denominator:=1;
  3540. if !*trint
  3541. then printc "Denominator of 1st part of answer is:";
  3542. if not null w then w:=cdr w >>;
  3543. loopx: if w=nil then return;
  3544. if !*trint then <<prin2 "Factors of multiplicity "; print i>>;
  3545. wx:=car w;
  3546. while not null wx do <<
  3547. if !*trint then printsf car wx;
  3548. for j:=1 : i do
  3549. denominator:= !*multf(car wx,denominator);
  3550. wx:=cdr wx >>;
  3551. i:=i+1;
  3552. w:=cdr w;
  3553. go to loopx
  3554. end;
  3555. % unfluid '(dfun svar xlogs);
  3556. endmodule;
  3557. module halfangle; % Routines for conversion to half angle tangents.
  3558. % Author: Steve Harrington.
  3559. % Modifications by: John P. Fitch.
  3560. fluid '(!*gcd);
  3561. exports halfangle,untan;
  3562. symbolic procedure transform(u,x);
  3563. % Transform the SQ U to remove the 'bad' functions sin, cos, cot etc
  3564. % in favor of half angles;
  3565. halfangle(u,x);
  3566. symbolic procedure quotqq(u1,v1);
  3567. multsq(u1, invsq(v1));
  3568. symbolic procedure !*subtrq(u1,v1);
  3569. addsq(u1, negsq(v1));
  3570. symbolic procedure !*int2qm(u1);
  3571. if u1=0 then nil . 1 else u1 . 1;
  3572. symbolic procedure halfangle(r,x);
  3573. % Top level procedure for converting;
  3574. % R is a rational expression to be converted,
  3575. % X the integration variable.
  3576. % A rational expression is returned.
  3577. quotqq(hfaglf(numr(r),x), hfaglf(denr(r),x));
  3578. symbolic procedure hfaglf(p,x);
  3579. % Converting polynomials, a rational expression is returned.
  3580. if domainp(p) then !*f2q(p)
  3581. else subs2q addsq(multsq(exptsq(hfaglk(mvar(p),x), ldeg(p)),
  3582. hfaglf(lc(p),x)),
  3583. hfaglf(red(p),x));
  3584. symbolic procedure hfaglk(k,x);
  3585. % Converting kernels, a rational expression is returned.
  3586. begin
  3587. scalar kt;
  3588. if atom k or not member(x,flatten(cdr(k))) then return !*k2q k;
  3589. k := car(k) . hfaglargs(cdr(k), x);
  3590. kt := simp list('tan, list('quotient, cadr(k), 2));
  3591. return if car(k) = 'sin
  3592. then quotqq(multsq(!*int2qm(2),kt), addsq(!*int2qm(1),
  3593. exptsq(kt,2)))
  3594. else if car(k) = 'cos
  3595. then quotqq(!*subtrq(!*int2qm(1),exptsq(kt,2)),addsq(!*int2qm(1),
  3596. exptsq(kt,2)))
  3597. else if car(k) = 'tan
  3598. then quotqq(multsq(!*int2qm(2),kt), !*subtrq(!*int2qm(1),
  3599. exptsq(kt,2)))
  3600. else if car(k) = 'sinh then
  3601. quotqq(!*subtrq(exptsq(!*k2q('expt.('e. cdr k)),2),
  3602. !*int2qm(1)), multsq(!*int2qm(2), !*k2q('expt . ('e . cdr(k)))))
  3603. else if car(k) = 'cosh then
  3604. quotqq(addsq(exptsq(!*k2q('expt.('e. cdr k)),2),
  3605. !*int2qm(1)), multsq(!*int2qm(2), !*k2q('expt . ('e . cdr(k)))))
  3606. else if car(k) = 'tanh then
  3607. quotqq(!*subtrq(exptsq(!*k2q('expt.('e. cdr k)),2),
  3608. !*int2qm(1)), addsq(exptsq(!*k2q ('expt.('e.cdr(k))),2),
  3609. !*int2qm(1)))
  3610. else !*k2q(k); % additional transformation might be added here.
  3611. end;
  3612. symbolic procedure hfaglargs(l,x);
  3613. % Conversion of argument list.
  3614. if null l then nil
  3615. else prepsq(hfaglk(car(l),x)) . hfaglargs(cdr(l), x);
  3616. symbolic procedure untanf x;
  3617. % This should be done by a table.
  3618. begin scalar y,z,w;
  3619. if domainp x then return x . 1;
  3620. y := mvar x;
  3621. if eqcar(y,'int) then error1(); % assume all is hopeless.
  3622. z := ldeg x;
  3623. w := 1 . 1;
  3624. y :=
  3625. if atom y then !*k2q y
  3626. else if car y eq 'tan
  3627. then if evenp z
  3628. then <<z := z/2;
  3629. simp list('quotient,
  3630. list('plus,
  3631. list('minus,
  3632. list('cos,
  3633. 'times
  3634. . (2 . cdr y))),
  3635. 1),list('plus,
  3636. list('cos,
  3637. 'times
  3638. . (2 . cdr y)),
  3639. 1))>>
  3640. else if z=1
  3641. then simp list('quotient,
  3642. list('plus,
  3643. list('minus,
  3644. list('cos,
  3645. 'times . (2 . cdr y))),
  3646. 1),list('sin,
  3647. 'times . (2 . cdr y)))
  3648. else <<z := (z - 1)/2;
  3649. w :=
  3650. simp list('quotient,
  3651. list('plus,
  3652. list('minus,
  3653. list('cos,
  3654. 'times
  3655. . (2 . cdr y))),
  3656. 1),list('sin,
  3657. 'times
  3658. . (2 . cdr y)));
  3659. simp list('quotient,
  3660. list('plus,
  3661. list('minus,
  3662. list('cos,
  3663. 'times
  3664. . (2 . cdr y))),
  3665. 1),list('plus,
  3666. list('cos,
  3667. 'times
  3668. . (2 . cdr y)),
  3669. 1))>>
  3670. else simp y;
  3671. return addsq(multsq(multsq(exptsq(y,z),untanf lc x),w),
  3672. untanf red x)
  3673. end;
  3674. symbolic procedure untanlist(y);
  3675. if null y then nil
  3676. else (prepsq (untan(simp car y)) . untanlist(cdr y));
  3677. symbolic procedure untan(x);
  3678. % Expects x to be canonical quotient.
  3679. begin scalar y;
  3680. y:=cossqchk sinsqrdchk multsq(untanf(numr x),
  3681. invsq untanf(denr x));
  3682. return if length flatten y>length flatten x then x else y
  3683. end;
  3684. symbolic procedure sinsqrdchk(x);
  3685. multsq(sinsqchkf(numr x), invsq sinsqchkf(denr x));
  3686. symbolic procedure sinsqchkf(x);
  3687. begin
  3688. scalar y,z,w;
  3689. if domainp x then return x . 1;
  3690. y := mvar x;
  3691. z := ldeg x;
  3692. w := 1 . 1;
  3693. y := if eqcar(y,'sin) then if evenp z
  3694. then <<z := quotient(z,2);
  3695. simp list('plus,1,list('minus,
  3696. list('expt,('cos . cdr(y)),2)))>>
  3697. else if z = 1 then !*k2q y
  3698. else << z := quotient(difference(z,1),2); w := !*k2q y;
  3699. simp list('plus,1,list('minus,
  3700. list('expt,('cos . cdr(y)),2)))>>
  3701. else !*k2q y;
  3702. return addsq(multsq(multsq(exptsq(y,z),sinsqchkf(lc x)),w),
  3703. sinsqchkf(red x));
  3704. end;
  3705. symbolic procedure cossqchkf(x);
  3706. begin
  3707. scalar y,z,w,x1,x2;
  3708. if domainp x then return x . 1;
  3709. y := mvar x;
  3710. z := ldeg x;
  3711. w := 1 . 1;
  3712. x1 := cossqchkf(lc x);
  3713. x2 := cossqchkf(red x);
  3714. x := addsq(multsq(!*p2q lpow x,x1),x2);
  3715. y := if eqcar(y,'cos) then if evenp z
  3716. then <<z := quotient(z,2);
  3717. simp list('plus,1,list('minus,
  3718. list('expt,('sin . cdr(y)),2)))>>
  3719. else if z = 1 then !*k2q y
  3720. else << z := quotient(difference(z,1),2); w := !*k2q y;
  3721. simp list('plus,1,list('minus,
  3722. list('expt,('sin . cdr(y)),2)))>>
  3723. else !*k2q y;
  3724. y := addsq(multsq(multsq(exptsq(y,z),w),x1),x2);
  3725. return if length(y) > length(x) then x else y;
  3726. end;
  3727. symbolic procedure cossqchk(x);
  3728. begin scalar !*gcd;
  3729. !*gcd := t;
  3730. return multsq(cossqchkf(numr x), invsq cossqchkf(denr x))
  3731. end;
  3732. symbolic procedure lrootchk(l,x);
  3733. % Checks each member of list l for a root.
  3734. if null l then nil else krootchk(car l, x) or lrootchk(cdr l, x);
  3735. symbolic procedure krootchk(f,x);
  3736. % Checks a kernel to see if it is a root.
  3737. if atom f then nil
  3738. else if car(f) = 'sqrt and member(x, flatten cdr f) then t
  3739. else if car(f) = 'expt
  3740. and not atom caddr(f)
  3741. and caaddr(f) = 'quotient
  3742. and member(x, flatten cadr f) then t
  3743. else lrootchk(cdr f, x);
  3744. symbolic procedure rootchk1p(f,x);
  3745. % Checks polynomial for a root.
  3746. if domainp f then nil
  3747. else krootchk(mvar f,x) or rootchk1p(lc f,x) or rootchk1p(red f,x);
  3748. symbolic procedure rootcheckp(f,x);
  3749. % Checks rational (standard quotient) for a root.
  3750. rootchk1p(numr f,x) or rootchk1p(denr f,x);
  3751. endmodule;
  3752. module trialdiv; % Trial division routines.
  3753. % Authors: Mary Ann Moore and Arthur C. Norman.
  3754. fluid '(denominator loglist tanlist);
  3755. global '(!*trint);
  3756. exports countz,findsqrts,findtrialdivs,trialdiv,simp,mksp;
  3757. imports !*multf,printsf,quotf;
  3758. symbolic procedure countz dl;
  3759. % DL is a list of S.F.s;
  3760. begin scalar s,n,rl;
  3761. loop2: if null dl then return arrangelistz rl;
  3762. n:=1;
  3763. loop1: n:=n+1;
  3764. s:=car dl;
  3765. dl:=cdr dl;
  3766. if not null dl and (s eq car dl) then
  3767. go to loop1
  3768. else rl:=(s.n).rl;
  3769. go to loop2
  3770. end;
  3771. symbolic procedure arrangelistz d;
  3772. begin scalar n,s,rl,r;
  3773. n:=1;
  3774. if null d then return rl;
  3775. loopd: if (cdar d)=n then s:=(caar d).s
  3776. else r:=(car d).r;
  3777. d:=cdr d;
  3778. if not null d then go to loopd;
  3779. d:=r;
  3780. rl:=s.rl;
  3781. s:=nil;
  3782. r:=nil;
  3783. n:=n+1;
  3784. if not null d then go to loopd;
  3785. return reversewoc rl
  3786. end;
  3787. symbolic procedure findtrialdivs zl;
  3788. %zl is list of kernels found in integrand. result is a list
  3789. %giving things to be treated specially in the integration
  3790. %viz: exps and tans.
  3791. %Result is list of form ((a . b) ...)
  3792. % with a a kernel and car a=expt or tan
  3793. % and b a standard form for either expt or (1+tan**2).
  3794. begin scalar dlists1,args1;
  3795. while not null zl do <<
  3796. if exportan car zl then <<
  3797. if caar zl='tan
  3798. then << args1:=(mksp(car zl,2) .* 1) .+ 1;
  3799. tanlist:=(args1 ./ 1) . tanlist>>
  3800. else args1:=!*k2f car zl;
  3801. dlists1:=(car zl . args1) . dlists1>>;
  3802. zl:=cdr zl >>;
  3803. return dlists1
  3804. end;
  3805. symbolic procedure exportan dl;
  3806. if atom dl then nil
  3807. else begin
  3808. % extract exp or tan fns from the z-list.
  3809. if eq(car dl,'tan) then return t;
  3810. nxt: if not eq(car dl,'expt) then return nil;
  3811. dl:=cadr dl;
  3812. if atom dl then return t;
  3813. % Make sure we find nested exponentials?
  3814. go to nxt
  3815. end;
  3816. symbolic procedure findsqrts z;
  3817. begin scalar r;
  3818. while not null z do <<
  3819. if eqcar(car z,'sqrt) then r:=(car z) . r;
  3820. z:=cdr z >>;
  3821. return r
  3822. end;
  3823. symbolic procedure trialdiv(x,dl);
  3824. begin scalar qlist,q;
  3825. while not null dl do
  3826. if not null(q:=quotf(x,cdar dl)) then <<
  3827. if (caaar dl='tan) and not eqcar(qlist,cdar dl) then
  3828. loglist:=('iden . simp cadr caar dl) . loglist;
  3829. %tan fiddle!
  3830. qlist:=(cdar dl).qlist;
  3831. x:=q >>
  3832. else dl:=cdr dl;
  3833. return qlist.x
  3834. end;
  3835. endmodule;
  3836. module unifac; % Univariate factorization for integration.
  3837. % Authors: Mary Ann Moore and Arthur C. Norman.
  3838. fluid '(knowndiscrimsign zlist);
  3839. global '(!*trint);
  3840. exports unifac;
  3841. imports cubic,linfac,printdf,quadfac,quadratic,quartic,vp1,
  3842. gcd,minusp,prettyprint;
  3843. symbolic procedure unifac(pol,var,degree,res);
  3844. begin scalar w,q,c;
  3845. w:=pol;
  3846. if !*trint then superprint w;
  3847. %now try looking for linear factors.
  3848. trylin: q:=linfac(w);
  3849. if null car q then go to nomorelin;
  3850. res := ('log . back2df(car q,var)) . res;
  3851. w:=cdr q;
  3852. go to trylin;
  3853. nomorelin:
  3854. q:=quadfac(w);
  3855. if null car q then go to nomorequad;
  3856. res := quadratic(back2df(car q,var),var,res);
  3857. w:=cdr q;
  3858. go to nomorelin;
  3859. nomorequad:
  3860. if null w then return res; %all done.
  3861. degree:=car w; %degree of what is left.
  3862. c:=back2df(w,var);
  3863. if degree=3 then res:=cubic(c,var,res)
  3864. else if degree=4 then res:=quartic(c,var,res)
  3865. else if evenp degree and
  3866. pairp (q := halfpower cddr w)
  3867. then <<w := (degree/2) . (cadr w . q);
  3868. w := unifac(w,var,car w,nil);
  3869. res := pluckfactors(w,var,res)>>
  3870. else <<
  3871. printc "The following has not been split";
  3872. printdf c;
  3873. res:=('log . c) . res>>;
  3874. return res
  3875. end;
  3876. symbolic procedure halfpower w;
  3877. if null w then nil
  3878. else if car w=0
  3879. then (lambda r;
  3880. if r eq 'failed then r else cadr w . r) halfpower cddr w
  3881. else 'failed;
  3882. symbolic procedure pluckfactors(w,var,res);
  3883. begin scalar p,q,knowndiscrimsign;
  3884. while w do
  3885. <<p := car w;
  3886. if car p eq 'atan then nil
  3887. else if car p eq 'log
  3888. then <<q := doublepower cdr p . q;
  3889. %prin2 "q="; %printdf car q;
  3890. >>
  3891. else interr "Bad form";
  3892. w := cdr w>>;
  3893. while q do
  3894. <<p := car q;
  3895. if caaar p=4
  3896. then <<knowndiscrimsign := 'negative;
  3897. res := quartic(p,var,res);
  3898. knowndiscrimsign := nil>>
  3899. else if caaar p=2
  3900. then res := quadratic(p,var,res)
  3901. else res := ('log . p) . res;
  3902. q := cdr q>>;
  3903. return res
  3904. end;
  3905. symbolic procedure doublepower r;
  3906. if null r then nil
  3907. else ((for each j in caar r collect 2*j) . cdar r)
  3908. . doublepower cdr r;
  3909. symbolic procedure back2df(p,v);
  3910. % Undo the effect of uniform.
  3911. begin scalar r,n;
  3912. n:=car p;
  3913. p:=cdr p;
  3914. while not minusp n do <<
  3915. if not zerop car p then r:=
  3916. (vp1(v,n,zlist) .* (car p ./ 1)) .+ r;
  3917. p:=cdr p;
  3918. n:=n-1 >>;
  3919. return reversewoc r
  3920. end;
  3921. endmodule;
  3922. module uniform; % Convert from D.F. to list of coefficients.
  3923. % Authors: Mary Ann Moore and Arthur C. Norman.
  3924. fluid '(zlist);
  3925. exports uniform;
  3926. imports exponentof;
  3927. symbolic procedure uniform(p,v);
  3928. %Convert from d.f. in one variable (v) to a simple list of
  3929. %coeffs (with degree consed onto front).
  3930. %Fails if coefficients are not all simple integers.
  3931. if null p then 0 . (0 . nil)
  3932. else begin scalar a,b,c,d;
  3933. a:=exponentof(v,lpow p,zlist);
  3934. b:=lc p;
  3935. if not(denr b=1) then return 'failed;
  3936. b:=numr b;
  3937. if null b then b:=0
  3938. else if not numberp b then return 'failed;
  3939. if a=0 then return a . (b . nil); %constant term.
  3940. c:=uniform(red p,v);
  3941. if c='failed then return 'failed;
  3942. d:=car c;
  3943. c:=cdr c;
  3944. d:=d+1;
  3945. while not (a=d) do <<
  3946. c:=0 . c;
  3947. d:=d+1>>;
  3948. return a . (b . c)
  3949. end;
  3950. endmodule;
  3951. module makevars; % Make dummy variables for integration process.
  3952. % Authors: Mary Ann Moore and Arthur C. Norman.
  3953. fluid '(!*gensymlist!* !*purerisch);
  3954. exports getvariables,varsinlist,varsinsq,varsinsf,findzvars,
  3955. createindices,mergein;
  3956. imports dependsp,union;
  3957. % Note that 'i' is already maybe committed for sqrt(-1),
  3958. % also 'l' and 'o' are not used as they print badly on certain
  3959. % terminals etc and may lead to confusion.
  3960. !*gensymlist!* := '(! j ! k ! m ! n ! p ! q ! r ! s ! t ! u ! v ! w ! x
  3961. ! y ! z);
  3962. %mapc(!*gensymlist!*,function remob); %REMOB protection;
  3963. symbolic procedure varsinlist(l,vl);
  3964. % L is a list of s.q. - find all variables mentioned,
  3965. % given thal vl is a list already known about.
  3966. begin while not null l do <<
  3967. vl:=varsinsf(numr car l,varsinsf(denr car l,vl));
  3968. l:=cdr l >>;
  3969. return vl
  3970. end;
  3971. symbolic procedure getvariables sq;
  3972. varsinsf(numr sq,varsinsf(denr sq,nil));
  3973. symbolic procedure varsinsq(sq,vl);
  3974. varsinsf(numr sq,varsinsf(denr sq,vl));
  3975. symbolic procedure varsinsf(form,l);
  3976. if domainp form then l
  3977. else begin
  3978. while not domainp form do <<
  3979. l:=varsinsf(lc form,union(l,list mvar form));
  3980. form:=red form >>;
  3981. return l
  3982. end;
  3983. symbolic procedure findzvars(vl,zl,var,flg);
  3984. begin scalar v;
  3985. % VL is the crude list of variables found in the original integrand;
  3986. % ZL must have merged into it all EXP, LOG etc terms from this.
  3987. % If FLG is true then ignore DF as a function.
  3988. scan: if null vl then return zl;
  3989. v:=car vl; % next variable.
  3990. vl:=cdr vl;
  3991. % at present items get put onto ZL if they are non-atomic
  3992. % and they depend on the main variable. The arguments of
  3993. % functions are decomposed by recursive calls to findzvar.
  3994. %give up if V has been declared dependent on other things;
  3995. if atom v and v neq var and depends(v,var) then
  3996. rederr "Can't integrate in the presence of side-relations"
  3997. else if not atom v and (not v member zl) and dependsp(v,var)
  3998. then if car v='!*sq then zl:=findzvarssq(cadr v,zl,var)
  3999. else if car v memq '(times quotient plus minus difference int)
  4000. or (((car v) eq 'expt) and fixp caddr v)
  4001. then
  4002. zl:=findzvars(cdr v,zl,var,flg)
  4003. else if flg and car v eq 'df
  4004. then <<!*purerisch := t; return zl>> % try and stop it
  4005. else zl:=v . findzvars(cdr v,zl,var,flg);
  4006. % scan arguments of fn.
  4007. %ACH: old code used to look only at CADR if a DF involved.
  4008. go to scan
  4009. end;
  4010. symbolic procedure findzvarssq(sq,zl,var);
  4011. findzvarsf(numr sq,findzvarsf(denr sq,zl,var),var);
  4012. symbolic procedure findzvarsf(sf,zl,var);
  4013. if domainp sf then zl
  4014. else findzvarsf(lc sf,
  4015. findzvarsf(red sf,
  4016. findzvars(list mvar sf,zl,var,nil),
  4017. var),
  4018. var);
  4019. symbolic procedure createindices zl;
  4020. % Produces a list of unique indices, each associated with a ;
  4021. % different Z-variable;
  4022. reversewoc crindex1(zl,!*gensymlist!*);
  4023. symbolic procedure crindex1(zl,gl);
  4024. begin if null zl then return nil;
  4025. if null gl then << gl:=list int!-gensym1 'i; %new symbol needed;
  4026. nconc(!*gensymlist!*,gl) >>;
  4027. return (car gl) . crindex1(cdr zl,cdr gl) end;
  4028. symbolic procedure rmember(a,b);
  4029. if null b then nil
  4030. else if a=cdar b then car b
  4031. else rmember(a,cdr b);
  4032. symbolic procedure mergein(dl,ll);
  4033. % Adjoin logs of things in dl to existing list ll.
  4034. if null dl then ll
  4035. else if rmember(car dl,ll) then mergein(cdr dl,ll)
  4036. else mergein(cdr dl,('log . car dl) . ll);
  4037. endmodule;
  4038. module vect; % Vector support routines.
  4039. % Authors: Mary Ann Moore and Arthur C. Norman.
  4040. % Modified by: James H. Davenport.
  4041. exports mkuniquevect,mkvec,mkvecf2q,mkidenm,copyvec,vecsort,swap,
  4042. non!-null!-vec,mkvect2;
  4043. symbolic procedure mkuniquevect v;
  4044. begin scalar u,n;
  4045. n:=upbv v;
  4046. for i:=0:n do begin
  4047. scalar uu;
  4048. uu:=getv(v,i);
  4049. if not (uu member u)
  4050. then u:=uu.u
  4051. end;
  4052. return mkvec u
  4053. end;
  4054. symbolic procedure mkvec(l);
  4055. begin scalar v,i;
  4056. v:=mkvect(isub1 length l);
  4057. i:=0;
  4058. while l do <<putv(v,i,car l); i:=iadd1 i; l:=cdr l>>;
  4059. return v
  4060. end;
  4061. symbolic procedure mkvecf2q(l);
  4062. begin
  4063. scalar v,i,ll;
  4064. v:=mkvect(isub1 length l);
  4065. i:=0;
  4066. while l do <<
  4067. ll:=car l;
  4068. if ll = 0 then ll:=nil;
  4069. putv(v,i,!*f2q ll);
  4070. i:=iadd1 i;
  4071. l:=cdr l >>;
  4072. return v
  4073. end;
  4074. symbolic procedure mkidenm n;
  4075. begin
  4076. scalar ans,u;
  4077. scalar c0,c1;
  4078. c0:=nil ./ 1;
  4079. c1:= 1 ./ 1;
  4080. % constants.
  4081. ans:=mkvect(n);
  4082. for i:=0 step 1 until n do <<
  4083. u:=mkvect n;
  4084. for j:=0 step 1 until n do
  4085. if i iequal j
  4086. then putv(u,j,c1)
  4087. else putv(u,j,c0);
  4088. putv(ans,i,u) >>;
  4089. return ans
  4090. end;
  4091. symbolic procedure copyvec(v,n);
  4092. begin scalar new;
  4093. new:=mkvect(n);
  4094. for i:=0:n do putv(new,i,getv(v,i));
  4095. return new
  4096. end;
  4097. symbolic procedure vecsort(u,l);
  4098. % Sorts vector v of numbers into decreasing order.
  4099. % Performs same interchanges of all vectors in the list l.
  4100. begin
  4101. scalar j,k,n,v,w;
  4102. n:=upbv u;% elements 0...n exist.
  4103. % algorithm used is a bubble sort.
  4104. for i:=1:n do begin
  4105. v:=getv(u,i);
  4106. k:=i;
  4107. loop:
  4108. j:=k;
  4109. k:=isub1 k;
  4110. w:=getv(u,k);
  4111. if v<=w
  4112. then goto ordered;
  4113. putv(u,k,v);
  4114. putv(u,j,w);
  4115. mapc(l,function (lambda u;swap(u,j,k)));
  4116. if k>0
  4117. then goto loop;
  4118. ordered:
  4119. end;
  4120. return nil
  4121. end;
  4122. symbolic procedure swap(u,j,k);
  4123. if null u
  4124. then nil
  4125. else begin
  4126. scalar v;
  4127. %swaps elements i,j of vector u.
  4128. v:=getv(u,j);
  4129. putv(u,j,getv(u,k));
  4130. putv(u,k,v)
  4131. end;
  4132. symbolic procedure non!-null!-vec v;
  4133. begin
  4134. scalar cnt;
  4135. cnt := 0;
  4136. for i:=0:upbv v do
  4137. if getv(v,i)
  4138. then cnt:=iadd1 cnt;
  4139. return cnt
  4140. end;
  4141. symbolic procedure mkvect2(n,initial);
  4142. begin
  4143. scalar u;
  4144. u:=mkvect n;
  4145. for i:=0:n do
  4146. putv(u,i,initial);
  4147. return u
  4148. end;
  4149. endmodule;
  4150. end;