123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800 |
- module int!-intro; % General support for REDUCE integrator.
- % Authors: A. C. Norman and P. M. A. Moore.
- % Modified by: J. Davenport, J. P. Fitch, A. C. Hearn.
- % Note that at one point, INT had been flagged SIMP0FN. However, that
- % lead to problems when the arguments of INT contained pattern
- % variables.
- fluid '(!*conscount !*noextend !*pvar gaussiani);
- global '(btrlevel frlis!* gensymcount initl!*);
- !*conscount:=10000; % default maximum number of conses in certain
- % operations.
- !*pvar:='!_a;
- btrlevel := 5; %default to a reasonably full backtrace.
- % The next smacro is needed at this point to define gaussiani.
- symbolic smacro procedure !*kk2f u; !*p2f mksp(u,1);
- gaussiani := !*kk2f '(sqrt -1);
- gensymcount := 0;
- initl!* := append('(!*noextend), initl!*);
- flag('(interr),'transfer); %For the compiler;
- flag ('(atan dilog erf expint expt log tan),'transcendental);
- comment Kludge to define derivative of an integral and integral of
- a derivative;
- frlis!* := union('(!=x !=y),frlis!*);
- put('df,'opmtch,'(((int !=y !=x) !=x) (nil . t)
- (evl!* !=y) nil) . get('df,'opmtch));
- put('int,'opmtch,'(((df !=y !=x) !=x) (nil . t)
- (evl!* !=y) nil) . get('int,'opmtch));
- put('evl!*,'opmtch,'(((!=x) (nil . t) !=x nil)));
- put('evl!*,'simpfn,'simpiden);
- %Various functions used throughout the integrator.
- smacro procedure !*kk2q a; ((mksp(a,1) .* 1) .+ nil) ./ 1;
- symbolic smacro procedure divsf(u,v); sqrt2top(u ./ v);
- symbolic procedure flatten u;
- if null u then nil
- else if atom u then list u
- else if atom car u then car u . flatten cdr u
- else nconc(flatten car u,flatten cdr u);
- symbolic procedure int!-gensym1 u;
- << gensymcount:=gensymcount+1;
- compress append(explode u,explode gensymcount) >>;
- symbolic smacro procedure maninp(u,v,w);
- interr "MANINP called -- not implemented";
- symbolic procedure mknill n; if n=0 then nil else nil . mknill(n-1);
- % Various selectors written as macros.
- smacro procedure argof u;
- % Argument of a unary function.
- cadr u;
- smacro procedure firstsubs u;
- % The first substitution in a substitution list.
- car u;
- smacro procedure lsubs u; car u;
- smacro procedure rsubs u; cdr u;
- smacro procedure lfirstsubs u; caar u;
- smacro procedure rfirstsubs u; cdar u;
- put('nthroot,'simpfn,'simpiden);
- % The binary n-th root operator nthroot(x,2)=sqrt(x)
- % no simplification is used here.
- % Hope is that pbuild introduces it, and simplog removes it.
- % Selectors for the taylor series structure.
- % Format is:
- %function.((first.last computed so far) . assoc list of computed terms).
- % ***store-hack-1***:
- % remove this macro if more store is available.
- smacro procedure tayshorten u;nil;
- smacro procedure taylordefn u; car u;
- symbolic smacro procedure taylorfunction u; caar u;
- smacro procedure taylornumbers u; cadr u;
- smacro procedure taylorfirst u; caadr u;
- smacro procedure taylorlast u; cdadr u;
- smacro procedure taylorlist u; cddr u;
- smacro procedure taylormake(fn,nums,alist); fn.(nums.alist);
- endmodule;
- module contents;
- % Authors: Mary Ann Moore and Arthur C. Norman
- fluid '(clogflag content indexlist sqfr varlist zlist);
- exports contents,contentsmv,dfnumr,difflogs,factorlistlist,multsqfree,
- multup,sqfree,sqmerge;
- imports int!-fac,fquotf,gcdf,interr,!*multf,partialdiff,quotf,ordop,
- addf,negf,domainp,difff,mksp,negsq,invsq,addsq,!*multsq,diffsq;
- comment we assume no power substitution is necessary in this module;
- symbolic procedure contents(p,v);
- % Find the contents of the polynomial p wrt variable v;
- % Note that v may not be the main variable of p;
- if domainp(p) then p
- else if v=mvar p then contentsmv(p,v,nil)
- else if ordop(v,mvar p) then p
- else contentsmv(makemainvar(p,v),v,nil);
- symbolic procedure contentsmv(p,v,sofar);
- % Find contents of polynomial P;
- % V is main variable of P;
- % SOFAR is partial result;
- if sofar=1 then 1
- else if domainp p then gcdf(p,sofar)
- else if not v=mvar p then gcdf(p,sofar)
- else contentsmv(red p,v,gcdf(lc p,sofar));
- symbolic procedure makemainvar(p,v);
- % Bring v up to be the main variable in polynomial p;
- % Note that the reconstructed p must be used with care since;
- % it does not conform to the normal reduce ordering rules;
- if domainp p then p
- else if v=mvar p then p
- else mergeadd(mulcoeffsby(makemainvar(lc p,v),lpow p,v),
- makemainvar(red p,v),v);
- symbolic procedure mulcoeffsby(p,pow,v);
- % Multiply each coefficient in p by the standard power pow;
- if null p then nil
- else if domainp p or not v=mvar p then ((pow .* p) .+ nil)
- else (lpow p .* ((pow .* lc p) .+ nil)) .+ mulcoeffsby(red p,pow,v);
- symbolic procedure mergeadd(a,b,v);
- % Add polynomials a and b given that they have same main variable v;
- if domainp a or not v=mvar a then
- if domainp b or not v=mvar b then addf(a,b)
- else lt b .+ mergeadd(a,red b,v)
- else if domainp b or not v=mvar b then
- lt a .+ mergeadd(red a,b,v)
- else (lambda xc;
- if xc=0 then (lpow a .* addf(lc a,lc b)) .+
- mergeadd(red a,red b,v)
- else if xc>0 then lt a .+ mergeadd(red a,b,v)
- else lt b .+ mergeadd(a,red b,v))
- (tdeg lt a-tdeg lt b);
- symbolic procedure sqfree(p,vl);
- if (null vl) or (domainp p) then
- <<content:=p; nil>>
- else begin scalar w,v,dp,gg,pg,dpg,p1,w1;
- w:=contents(p,car vl); % content of p ;
- p:=quotf(p,w); % make p primitive;
- w:=sqfree(w,cdr vl); % process content by recursion;
- if p=1 then return w;
- v:=car vl; % pick out variable from list;
- while not (p=1) do <<
- dp:=partialdiff(p,v);
- gg:=gcdf(p,dp);
- pg:=quotf(p,gg);
- dpg:=negf partialdiff(pg,v);
- p1:=gcdf(pg,addf(quotf(dp,gg),dpg));
- w1:=p1.w1;
- p:=gg>>;
- return sqmerge(reverse w1,w,t)
- end;
- symbolic procedure sqmerge(w1,w,simplew1);
- % w and w1 are lists of factors of each power. if simplew1 is true
- % then w1 contains only single factors for each power. ;
- if null w1 then w
- else if null w then if car w1=1 then nil.sqmerge(cdr w1,w,simplew1)
- else (if simplew1 then list car w1 else car w1).
- sqmerge(cdr w1,w,simplew1)
- else if car w1=1 then (car w).sqmerge(cdr w1,cdr w,simplew1) else
- append(if simplew1 then list car w1 else car w1,car w).
- sqmerge(cdr w1,cdr w,simplew1);
- symbolic procedure multup l;
- % l is a list of s.f.'s. result is s.f. for product of elements of l;
- begin scalar res;
- res:=1;
- while not null l do <<
- res:=multf(res,car l);
- l:=cdr l >>;
- return res
- end;
- symbolic procedure diflist(l,cl,x,rl);
- % Differentiates l (list of s.f.'s) wrt x to produce the sum of
- % terms for the derivative of numr of 1st part of answer. cl is
- % coefficient list (s.f.'s) & rl is list of derivatives we have
- % dealt with so far. Result is s.q.;
- if null l then nil ./ 1
- else begin scalar temp;
- temp:=!*multf(multup rl,multup cdr l);
- temp:=!*multsq(difff(car l,x),!*f2q temp);
- temp:=!*multsq(temp,(car cl) ./ 1);
- return addsq(temp,diflist(cdr l,cdr cl,x,(car l).rl))
- end;
- symbolic procedure multsqfree w;
- % W is list of sqfree factors. result is product of each LIST IN W
- % to give one polynomial for each sqfree power;
- if null w then nil
- else (multup car w).multsqfree cdr w;
- symbolic procedure l2lsf l;
- % L is a list of kernels. result is a list of same members as s.f.'s;
- if null l then nil
- else ((mksp(car l,1) .* 1) .+ nil).l2lsf cdr l;
- symbolic procedure dfnumr(x,dl);
- % Gives the derivative of the numr of the 1st part of answer.
- % dl is list of any exponential or 1+tan**2 that occur in integrand
- % denr. these are divided out from result before handing it back.
- % result is s.q., ready for printing.
- begin scalar temp1,temp2,coeflist,qlist,count;
- if not null sqfr then <<
- count:=0;
- qlist:=cdr sqfr;
- coeflist:=nil;
- while not null qlist do <<
- count:=count+1;
- coeflist:=count.coeflist;
- qlist:=cdr qlist >>;
- coeflist:=reverse coeflist >>;
- temp1:=!*multsq(diflist(l2lsf zlist,l2lsf indexlist,x,nil),
- !*f2q multup sqfr);
- if not null sqfr and not null cdr sqfr then <<
- temp2:=!*multsq(diflist(cdr sqfr,coeflist,x,nil),
- !*f2q multup l2lsf zlist);
- temp2:=!*multsq(temp2,(car sqfr) ./ 1) >>
- else temp2:=nil ./ 1;
- temp1:=addsq(temp1,negsq temp2);
- temp2:=cdr temp1;
- temp1:=car temp1;
- qlist:=nil;
- while not null dl do <<
- if not car dl member qlist then qlist:=(car dl).qlist;
- dl:=cdr dl >>;
- while not null qlist do <<
- temp1:=quotf(temp1,car qlist);
- qlist:=cdr qlist >>;
- return temp1 ./ temp2
- end;
- symbolic procedure difflogs(ll,denm1,x);
- % LL is list of log terms (with coeffts), den is common denominator
- % over which they are to be put. Result is s.q. for derivative of all
- % these wrt x.
- if null ll then nil ./ 1
- else begin scalar temp,qu,cvar,logoratan,arg;
- logoratan:=caar ll;
- cvar:=cadar ll;
- arg:=cddar ll;
- temp:=!*multsq(cvar ./ 1,diffsq(arg,x));
- if logoratan='iden then qu:=1 ./ 1
- else if logoratan='log then qu:=arg
- else if logoratan='atan then qu:=addsq(1 ./ 1,!*multsq(arg,arg))
- else interr "Logoratan=? in difflogs";
- %Note call to special division routine;
- qu:=fquotf(!*multf(!*multf(denm1,numr temp),
- denr qu),numr qu);
- %*MUST* GO EXACTLY;
- temp:=!*multsq(!*invsq (denr temp ./ 1),qu);
- %result of fquotf is a s.q;
- return !*addsq(temp,difflogs(cdr ll,denm1,x))
- end;
- symbolic procedure factorlistlist (w,clogflag);
- % W is list of lists of sqfree factors in s.f. result is list of log
- % terms required for integral answer. the arguments for each log fn
- % are in s.q.;
- begin scalar res,x,y;
- while not null w do <<
- x:=car w;
- while not null x do <<
- y:=facbypp(car x,varlist);
- while not null y do <<
- res:=append(int!-fac car y,res);
- y:=cdr y >>;
- x:=cdr x >>;
- w:=cdr w >>;
- return res
- end;
- symbolic procedure facbypp(p,vl);
- % Use contents/primitive parts to try to factor p.
- if null vl then list p
- else begin scalar princilap!-part,co;
- co:=contents(p,car vl);
- vl:=cdr vl;
- if co=1 then return facbypp(p,vl); %this var no help.
- princilap!-part:=quotf(p,co); %primitive part.
- if princilap!-part=1 then return facbypp(p,vl); %again no help;
- return nconc(facbypp(princilap!-part,vl),facbypp(co,vl))
- end;
- endmodule;
- module csolve; % routines to do with the C constants.
- % Author: John P. Fitch.
- fluid '(ccount cmap cmatrix cval loglist neweqn);
- global '(!*trint);
- exports backsubst4cs,createcmap,findpivot,printspreadc,printvecsq,
- spreadc,subst4eliminateds;
- imports nth,interr,!*multf,printsf,printsq,quotf,putv,negf,invsq,
- negsq,addsq,multsq,mksp,addf,domainp,pnth;
- symbolic procedure findpivot cvec;
- % Finds first non-zero element in CVEC and returns its cell number.
- % If no such element exists, result is nil.
- begin scalar i,x;
- i:=1;
- x:=getv(cvec,i);
- while i<ccount and null x do
- << i:=i+1;
- x:=getv(cvec,i) >>;
- if null x then return nil;
- return i
- end;
- symbolic procedure subst4eliminatedcs(neweqn,substorder,ceqns);
- % Substitutes into NEWEQN for all the C's that have been eliminated so
- % far. These are given by CEQNS. SUBSTORDER gives the order of
- % substitution as well as the constant multipliers. Result is the
- % transformed NEWEQN.
- if null substorder then neweqn
- else begin scalar nxt,row,cvar,temp;
- row:=car ceqns;
- nxt:=car substorder;
- if null (cvar:=getv(neweqn,nxt)) then
- return subst4eliminatedcs(neweqn,cdr substorder,cdr ceqns);
- nxt:=getv(row,nxt);
- for i:=0 : ccount do
- << temp:=!*multf(nxt,getv(neweqn,i));
- temp:=addf(temp,negf !*multf(cvar,getv(row,i)));
- putv(neweqn,i,temp) >>;
- return subst4eliminatedcs(neweqn,cdr substorder,cdr ceqns)
- end;
- symbolic procedure backsubst4cs(cs2subst,cs2solve,cmatrix);
- % Solves the C-eqns and sets vector CVAL to the C-constant values
- % CMATRIX is a list of matrix rows for C-eqns after Gaussian
- % elimination has been performed. CS2SOLVE is a list of the remaining
- % C's to evaluate and CS2SUBST are the C's we have evaluated already.
- if null cmatrix then nil
- else begin scalar eqnn,cvar,already,substlist,temp,temp2;
- eqnn:=car cmatrix;
- cvar:=car cs2solve;
- already:=nil ./ 1; % The S.Q. nil.
- substlist:=cs2subst;
- % Now substitute for previously evaluated c's:
- while not null substlist do
- << temp:=car substlist;
- if not null getv(eqnn,temp) then
- already:=addsq(already,multsq(getv(eqnn,temp) ./ 1,
- getv(cval,temp)));
- substlist:=cdr substlist >>;
- % Now solve for the c given by cvar (any remaining c's assumed zero).
- temp:=negsq addsq(getv(eqnn,0) ./ 1,already);
- if not null (temp2:=quotf(numr temp,getv(eqnn,cvar))) then
- temp:=temp2 ./ denr temp
- else temp:=multsq(temp,invsq(getv(eqnn,cvar) ./ 1));
- if not null numr temp then putv(cval,cvar,
- resimp rootextractsq subs2q temp);
- backsubst4cs(reversewoc(cvar . reversewoc cs2subst),
- cdr cs2solve,cdr cmatrix)
- end;
- %**********************************************************************
- % Routines to deal with linear equations for the constants C.
- %**********************************************************************
- symbolic procedure createcmap;
- %Sets LOGLIST to list of things of form (LOG C-constant f), where f is
- % function linear in one of the z-variables and C-constant is in S.F.
- % When creating these C-constant names, the CMAP is also set up and
- % returned as the result.
- begin scalar i,l,c;
- l:=loglist;
- i:=1;
- while not null l do <<
- c:=(int!-gensym1('c) . i) . c;
- i:=i+1;
- rplacd(car l,((mksp(caar c,1) .* 1) .+ nil) . cdar l);
- l:=cdr l >>;
- if !*trint then printc ("Constants Map" . c);
- return c
- end;
- symbolic procedure spreadc(eqnn,cvec1,w);
- % Sets a vector 'cvec1' to coefficients of c<i> in eqnn.
- if domainp eqnn then putv(cvec1,0,addf(getv(cvec1,0),
- !*multf(eqnn,w)))
- else begin scalar mv,t1,t2;
- spreadc(red eqnn,cvec1,w);
- mv:=mvar eqnn;
- t1:=assoc(mv,cmap); %tests if it is a c var.
- if not null t1 then return <<
- t1:=cdr t1; %loc in vector for this c.
- if not (tdeg lt eqnn=1) then interr "Not linear in c eqn";
- t2:=addf(getv(cvec1,t1),!*multf(w,lc eqnn));
- putv(cvec1,t1,t2) >>;
- t1:=((lpow eqnn) .* 1) .+ nil; %this main var as sf.
- spreadc(lc eqnn,cvec1,!*multf(w,t1))
- end;
- symbolic procedure printspreadc cvec1;
- begin
- for i:=0 : ccount do <<
- prin2 i;
- printc ":";
- printsf(getv(cvec1,i)) >>;
- printc "End of printspreadc output"
- end;
- %symbolic procedure printvecsq cvec;
- %% Print contents of cvec which contains s.q.'s (not s.f.'s).
- %% Starts from cell 1 not 0 as above routine (printspreadc).
- % begin
- % for i:=1 : ccount do <<
- % prin2 i;
- % printc ":";
- % if null getv(cvec,i) then printc "0"
- % else printsq(getv(cvec,i)) >>;
- % printc "End of printvecsq output"
- % end;
- endmodule;
- module cuberoot; % Cube roots of standard forms.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(cuberootflag);
- exports cuberootdf;
- imports contentsmv,gcdf,!*multf,nrootn,partialdiff,printdf,quotf,vp2,
- mksp,mk!*sq,domainp;
- symbolic procedure cuberootsq a;
- cuberootf numr a ./ cuberootf denr a;
- symbolic procedure cuberootf p;
- begin scalar ip,qp;
- if null p then return nil;
- ip:=cuberootf1 p;
- qp:=cdr ip;
- ip:=car ip; %respectable and nasty parts of the cuberoot.
- if numberp qp and onep qp then return ip; %exact root found.
- qp:=list('expt,prepf qp,'(quotient 1 3));
- cuberootflag:=t; %symbolic cube-root introduced.
- qp:=(mksp(qp,1).* 1) .+ nil;
- return !*multf(ip,qp)
- end;
- symbolic procedure cuberootf1 p;
- % Returns a . b with p=a**2*b.
- % Does this need power reduction?
- if domainp p then nrootn(p,3)
- else begin scalar co,ppp,g,pg;
- co:=contentsmv(p,mvar p,nil); %contents of p.
- ppp:=quotf(p,co); %primitive part.
- % now consider ppp=p1*p2**2*p3**3*p4**4*...
- co:=cuberootf1(co); %process contents via recursion.
- g:=gcdf(ppp,partialdiff(ppp,mvar ppp));
- % g=p2*p3**2*p4**3*...
- if not domainp g then <<
- pg:=quotf(ppp,g);
- %pg=p1*p2*p3*p4*...
- g:=gcdf(g,partialdiff(g,mvar g));
- % g=g3*g4**2*g5**3*...
- g:=gcdf(g,pg)>>; %a triple factor of ppp.
- if domainp g then pg:=1 . ppp
- else <<
- pg:=quotf(ppp,!*multf(g,!*multf(g,g))); %what's left.
- pg:=cuberootf1 pg; %split that up.
- rplaca(pg,!*multf(car pg,g))>>;
- %put in the thing found here.
- rplaca(pg,!*multf(car pg,car co));
- rplacd(pg,!*multf(cdr pg,cdr co));
- return pg
- end;
- endmodule;
- module idepend; % Routines for considering dependency among variables.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(taylorvariable);
- exports dependspl,dependsp,involvesq,involvsf;
- imports taylorp,domainp;
- symbolic procedure dependsp(x,v);
- if null v then t
- else if depends(x,v) then x
- else if atom x then if x eq v then x else nil
- else if car x = '!*sq then involvesq(cadr x,v)
- else if taylorp x
- then if v eq taylorvariable then taylorvariable else nil
- else begin scalar w;
- if x=v then return v;
- % Check if a prefix form expression depends on the variable v.
- % Note this assumes the form x is in normal prefix notation;
- w := x; % preserve the dependency;
- x := cdr x; % ready to recursively check arguments;
- scan: if null x then return nil; % no dependency found;
- if dependsp(car x,v) then return w;
- x:=cdr x;
- go to scan
- end;
- symbolic procedure involvesq(sq,term);
- involvesf(numr sq,term) or involvesf(denr sq,term);
-
- symbolic procedure involvesf(sf,term);
- if domainp sf or null sf then nil
- else dependsp(mvar sf,term)
- or involvesf(lc sf,term)
- or involvesf(red sf,term);
- symbolic procedure dependspl(dep!-list,var);
- % True if any member of deplist (a list of prefix forms) depends on
- % var.
- dep!-list
- and (dependsp(car dep!-list,var) or dependspl(cdr dep!-list,var));
- symbolic procedure taylorp exxpr;
- % Sees if a random entity is a taylor expression.
- not atom exxpr
- and not atom car exxpr
- and flagp(taylorfunction exxpr,'taylor);
- endmodule;
- module df2q; % Conversion from distributive to standard forms.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(indexlist zlist);
- exports df2q;
- imports addf,gcdf,mksp,!*multf,quotf;
- comment We assume that results already have reduced powers, so
- that no power substitution is necessary;
- symbolic procedure df2q p;
- % Converts distributed form P to standard quotient;
- begin scalar n,d,gg,w;
- if null p then return nil ./ 1;
- d:=denr lc p;
- w:=red p;
- while not null w do <<
- gg:=gcdf(d,denr lc w); %get denominator of answer...
- d:=!*multf(d,quotf(denr lc w,gg));
- %..as lcm of denoms in input
- w:=red w >>;
- n:=nil; %place to build numerator of answer
- while not null p do <<
- n:=addf(n,!*multf(xl2f(lpow p,zlist,indexlist),
- !*multf(numr lc p,quotf(d,denr lc p))));
- p:=red p >>;
- return n ./ d
- end;
- symbolic procedure xl2f(l,z,il);
- % L is an exponent list from a D.F., Z is the Z-list,
- % IL is the list of indices.
- % Value is L converted to standard form. ;
- if null z then 1
- else if car l=0 then xl2f(cdr l,cdr z,cdr il)
- else if not atom car l then
- begin scalar temp;
- if caar l=0 then temp:= car il
- else temp:=list('plus,car il,caar l);
- temp:=mksp(list('expt,car z,temp),1);
- return !*multf(((temp .* 1) .+ nil),
- xl2f(cdr l,cdr z,cdr il))
- end
- % else if minusp car l then ;
- % multsq(invsq (((mksp(car z,-car l) .* 1) .+ nil)), ;
- % xl2f(cdr l,cdr z,cdr il)) ;
- else !*multf((mksp(car z,car l) .* 1) .+ nil,
- xl2f(cdr l,cdr z,cdr il));
- endmodule;
- module distrib; % Routines for manipulating distributed forms.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(indexlist sqrtlist zlist);
- exports dfprintform,multbyarbpowers,negdf,quotdfconst,sub1ind,vp1,
- vp2,plusdf,multdf,multdfconst,orddf;
- imports interr,addsq,negsq,exptsq,simp,domainp,mk!*sq,addf,
- multsq,invsq,minusp,mksp,sub1;
- %***********************************************************************
- % NOTE: The expressions lt,red,lc,lpow have been used on distributed
- % forms as the latter's structure is sufficiently similar to
- % s.f.'s. However lc df is a s.q. not a s.f. and lpow df is a
- % list of the exponents of the variables. This also makes
- % lt df different. Red df is d.f. as expected.
- %**********************************************************************;
- symbolic procedure plusdf(u,v);
- % U and V are D.F.'s. Value is D.F. for U+V;
- if null u then v
- else if null v then u
- else if lpow u=lpow v then
- (lambda(x,y); if null numr x then y else (lpow u .* x) .+ y)
- (!*addsq(lc u,lc v),plusdf(red u,red v))
- else if orddf(lpow u,lpow v) then lt u .+ plusdf(red u,v)
- else (lt v) .+ plusdf(u,red v);
- symbolic procedure orddf(u,v);
- % U and V are the LPOW of a D.F. - i.e. the list of exponents ;
- % Value is true if LPOW U '>' LPOW V and false otherwise ;
- if null u then if null v then interr "Orddf = case"
- else interr "Orddf v longer than u"
- else if null v then interr "Orddf u longer than v"
- else if exptcompare(car u,car v) then t
- else if exptcompare(car v,car u) then nil
- else orddf(cdr u,cdr v);
- symbolic procedure exptcompare(x,y);
- if atom x then if atom y then x>y else nil
- else if atom y then t
- else car x > car y;
- symbolic procedure negdf u;
- if null u then nil
- else (lpow u .* negsq lc u) .+ negdf red u;
- symbolic procedure multdf(u,v);
- % U and V are D.F.'s. Value is D.F. for U*V;
- % reduces squares of square-roots as it goes;
- if null u or null v then nil
- else begin scalar y;
- %use (a+b)*(c+d) = (a*c) + a*(c+d) + b*(c+d);
- y:=multerm(lt u,lt v); %leading terms;
- y:=plusdf(y,multdf(red u,v));
- y:=plusdf(y,multdf((lt u) .+ nil,red v));
- return y
- end;
- symbolic procedure multerm(u,v);
- %multiply two terms to give a D.F.;
- begin scalar coef;
- coef:=!*multsq(cdr u,cdr v); %coefficient part;
- return multdfconst(coef,mulpower(car u,car v))
- end;
- symbolic procedure mulpower(u,v);
- % u and v are exponent lists. multiply corresponding forms;
- begin scalar r,s;
- r:=addexptsdf(u,v);
- if not null sqrtlist then s:=reduceroots(r,zlist);
- r:=(r .* (1 ./ 1)) .+ nil;
- if not (s=nil) then r:=multdf(r,s);
- return r
- end;
- symbolic procedure reduceroots(r,zl);
- begin scalar s;
- while not null r do <<
- if eqcar(car zl,'sqrt) then
- s:=tryreduction(r,car zl,s);
- r:=cdr r; zl:=cdr zl >>;
- return s
- end;
- symbolic procedure tryreduction(r,var,s);
- begin scalar x;
- x:=car r; %current exponent
- if not atom x then << r:=x; x:=car r >>; %numeric part
- if (x=0) or (x=1) then return s; %no reduction possible
- x:=divide(x,2);
- rplaca(r,cdr x); %reduce exponent as redorded
- x:=car x;
- var:=simp cadr var; %sqrt arg as a s q
- var:=!*exptsq(var,x);
- x:=multdfconst(1 ./ denr var,f2df numr var); %distribute
- if s=nil then s:=x
- else s:=multdf(s,x);
- return s
- end;
- symbolic procedure addexptsdf(x,y);
- % X and Y are LPOW's of D.F. Value is list of sum of exponents;
- if null x then if null y then nil else interr "X too long"
- else if null y then interr "Y too long"
- else exptplus(car x,car y).addexptsdf(cdr x,cdr y);
- symbolic procedure exptplus(x,y);
- if atom x then if atom y then x+y else list (x+car y)
- else if atom y then list (car x +y)
- else interr "Bad exponent sum";
- symbolic procedure multdfconst(x,u);
- % X is S.Q. not involving Z variables of D.F. U. Value is D.F.;
- % for X*U;
- if (null u) or (null numr x) then nil
- else lpow u .* !*multsq(x,lc u) .+ multdfconst(x,red u);
- %symbolic procedure quotdfconst(x,u);
- % multdfconst(!*invsq x,u);
- symbolic procedure f2df p;
- % P is standard form. Value is P in D.F.;
- if domainp p then dfconst(p ./ 1)
- else if mvar p member zlist then
- plusdf(multdf(vp2df(mvar p,tdeg lt p,zlist),f2df lc p),
- f2df red p)
- else plusdf(multdfconst(((lpow p .* 1) .+ nil) ./ 1,f2df lc p),
- f2df red p);
- symbolic procedure vp1(var,degg,z);
- % Takes VAR and finds it in Z (=list), raises it to power DEGG and puts
- % the result in exponent list form for use in a distributed form.
- if null z then interr "Var not in z-list after all"
- else if var=car z then degg.vp2 cdr z
- else 0 . vp1(var,degg,cdr z);
- symbolic procedure vp2 z;
- % Makes exponent list of zeroes.
- if null z then nil
- else 0 . vp2 cdr z;
- symbolic procedure vp2df(var,exprn,z);
- % Makes VAR**EXPRN into exponent list and then converts the resulting
- % power into a distributed form.
- % Special care with square-roots.
- if eqcar(var,'sqrt) and (exprn>1) then
- mulpower(vp1(var,exprn,z),vp2 z)
- else (vp1(var,exprn,z) .* (1 ./ 1)) .+ nil;
- symbolic procedure dfconst q;
- % Makes a distributed form from standard quotient constant Q;
- if numr q=nil then nil
- else ((vp2 zlist) .* q) .+ nil;
- %df2q moved to a section of its own.
- symbolic procedure df2printform p;
- %Convert to a standard form good enough for printing.
- if null p then nil
- else begin
- scalar mv,co;
- mv:=xl2q(lpow p,zlist,indexlist);
- if mv=(1 ./ 1) then <<
- co:=lc p;
- if denr co=1 then return addf(numr co,
- df2printform red p);
- co:=mksp(mk!*sq co,1);
- return (co .* 1) .+ df2printform red p >>;
- co:=lc p;
- if not (denr co=1) then mv:=!*multsq(mv,1 ./ denr co);
- mv:=mksp(mk!*sq mv,1) .* numr co;
- return mv .+ df2printform red p
- end;
- symbolic procedure xl2q(l,z,il);
- % L is an exponent list from a D.F.,Z is the Z-list, IL is the list of
- % indices. Value is L converted to standard quotient. ;
- if null z then 1 ./ 1
- else if car l=0 then xl2q(cdr l,cdr z,cdr il)
- else if not atom car l then
- begin scalar temp;
- if caar l=0 then temp:= car il
- else temp:=list('plus,car il,caar l);
- temp:=mksp(list('expt,car z,temp),1);
- return !*multsq(((temp .* 1) .+ nil) ./ 1,
- xl2q(cdr l,cdr z,cdr il))
- end
- else if minusp car l then
- !*multsq(!*invsq(((mksp(car z,-car l) .* 1) .+ nil) ./ 1),
- xl2q(cdr l,cdr z,cdr il))
- else !*multsq(((mksp(car z,car l) .* 1) .+ nil) ./ 1,
- xl2q(cdr l,cdr z,cdr il));
- %symbolic procedure sub1ind power;
- % if atom power then power-1
- % else list sub1 car power;
- symbolic procedure multbyarbpowers u;
- % Multiplies the ordinary D.F., U, by arbitrary powers
- % of the z-variables;
- % i-1 j-1 k-1
- % i.e. x z z ... so result is D.F. with the exponent list
- % 1 2
- %appropriately altered to contain list elements instead of numeric ones.
- if null u then nil
- else ((addarbexptsdf lpow u) .* lc u) .+ multbyarbpowers red u;
- symbolic procedure addarbexptsdf x;
- % Adds the arbitrary powers to powers in exponent list, X, to produce
- % new exponent list. e.g. 3 -> (2) to represent x**3 now becoming :
- % 3 i-1 i+2 ;
- % x * x = x . ;
- if null x then nil
- else list exptplus(car x,-1) . addarbexptsdf cdr x;
- endmodule;
- module divide; % Exact division of standard forms to give a S Q.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(residue sqrtlist zlist);
- global '(!*trdiv !*trint);
- exports fquotf,testdivdf,dfquotdf;
- imports df2q,f2df,gcdf,interr,multdf,negdf,plusdf,printdf,printsf,
- quotf,multsq,invsq,negsq;
- % Intended for dividing out known factors as produced by the
- % integration program. horrible and slow, i expect!!
- symbolic procedure dfquotdf(a,b);
- begin scalar residue;
- if (!*trint or !*trdiv) then <<
- printc "Dfquotdf called on ";
- printdf a; printdf b>>;
- a:=dfquotdf1(a,b);
- if (!*trint or !*trdiv) then << printc "Quotient given as ";
- printdf a >>;
- if not null residue then begin
- scalar gres,w;
- if !*trint or !*trdiv then <<
- printc "Residue in dfquotdf =";
- printdf residue;
- printc "Which should be zero";
- w:=residue;
- gres:=numr lc w; w:=red w;
- while not null w do <<
- gres:=gcdf(gres,numr lc w);
- w:=red w >>;
- printc "I.e. the following vanishes";
- printsf gres>>;
- interr "Non-exact division due to a log term"
- end;
- return a
- end;
- symbolic procedure fquotf(a,b);
- % Input: a and b standard quotients with (a/b) an exact
- % division with respect to the variables in zlist,
- % but not necessarily obviously so. the 'non-obvious' problems
- % will be because of (e.g.) square-root symbols in b
- % output: standard quotient for (a/b)
- % (prints message if remainder is not 'clearly' zero.
- % A must not be zero.
- begin scalar t1;
- if null a then interr "A=0 in fquotf";
- t1:=quotf(a,b); %try it the easy way
- if not null t1 then return t1 ./ 1; %ok
- return df2q dfquotdf(f2df a,f2df b)
- end;
- symbolic procedure dfquotdf1(a,b);
- begin scalar q;
- if null b then interr "Attempt to divide by zero";
- q:=sqrtlist; %remove sqrts from denominator, maybe.
- while not null q do begin
- scalar conj;
- conj:=conjsqrt(b,car q); %conjugate wrt given sqrt
- if not (b=conj) then <<
- a:=multdf(a,conj);
- b:=multdf(b,conj) >>;
- q:=cdr q end;
- q:=dfquotdf2(a,b);
- residue:=reversewoc residue;
- return q
- end;
- symbolic procedure dfquotdf2(a,b);
- % As above but a and b are distributed forms, as is the result.
- if null a then nil
- else begin scalar xd,lcd;
- xd:=xpdiff(lpow a,lpow b);
- if xd='failed then <<
- xd:=lt a; a:=red a;
- residue:=xd .+ residue;
- return dfquotdf2(a,b) >>;
- lcd:= !*multsq(lc a,!*invsq lc b);
- if null numr lcd then return dfquotdf2(red a,b);
- % Should not be necessary;
- lcd := xd .* lcd;
- xd:=plusdf(a,multdf(negdf (lcd .+ nil),b));
- if xd and (lpow xd = lpow a % Again, should not be necessary;
- or xpdiff(lpow xd,lpow b) = 'failed)
- then <<if !*trint or !*trdiv
- then <<printc "Dfquotdf trouble:"; printdf xd>>;
- xd := rootextractdf xd;
- if !*trint or !*trdiv then printdf xd>>;
- return lcd .+ dfquotdf2(xd,b)
- end;
- symbolic procedure rootextractdf u;
- if null u then nil
- else begin scalar v;
- v := resimp rootextractsq lc u;
- return if null numr v then rootextractdf red u
- else (lpow u .* v) .+ rootextractdf red u
- end;
- symbolic procedure rootextractsq u;
- if null numr u then u
- else rootextractf numr u ./ rootextractf denr u;
- symbolic procedure rootextractf v;
- if domainp v then v
- else begin scalar u,r,c,x,p;
- u := mvar v; p := ldeg v;
- r := rootextractf red v;
- c := rootextractf lc v;
- if null c then return r
- else if atom u then return (lpow v .* c) .+ r
- else if car u eq 'sqrt
- or car u eq 'expt and eqcar(caddr u,'quotient)
- and car cdaddr u = 1 and numberp cadr cdaddr u
- then <<p := divide(p,if car u eq 'sqrt then 2
- else cadr cdaddr u);
- if car p = 0
- then return if null c then r else (lpow v .* c) .+ r
- else if numberp cadr u
- then <<c := multd(cadr u ** car p,c); p := cdr p>>
- else <<x := simpexpt list(cadr u,car p);
- if denr x = 1
- then <<c := multf(numr x,c); p := cdr p>>>>>>;
- return if p=0 then addf(c,r)
- else if null c then r
- else ((u to p) .* c) .+ r
- end;
- % The following hack makes sure that the results of differentiation
- % gets passed through ROOTEXTRACT
- % a) This should not be done this way, since the effect is global
- % b) Should this be done via TIDYSQRT?
- put('df,'simpfn,'simpdf!*);
- symbolic procedure simpdf!* u;
- begin scalar v,v1;
- v:=simpdf u;
- v1:=rootextractsq v;
- if not(v1=v) then return resimp v1
- else return v
- end;
- symbolic procedure xpdiff(a,b);
- %Result is list a-b, or 'failed' if a member of this would be negative.
- if null a then if null b then nil
- else interr "B too long in xpdiff"
- else if null b then interr "A too long in xpdiff"
- else if car b>car a then 'failed
- else (lambda r;
- if r='failed then 'failed
- else (car a-car b) . r) (xpdiff(cdr a,cdr b));
- symbolic procedure conjsqrt(b,var);
- % Subst(var=-var,b).
- if null b then nil
- else conjterm(lpow b,lc b,var) .+ conjsqrt(red b,var);
-
- symbolic procedure conjterm(xl,coef,var);
- % Ditto but working on a term.
- if involvesp(xl,var,zlist) then xl .* negsq coef
- else xl .* coef;
-
- symbolic procedure involvesp(xl,var,zl);
- % Check if exponent list has non-zero power for variable.
- if null xl then interr "Var not found in involvesp"
- else if car zl=var then (not zerop car xl)
- else involvesp(cdr xl,var,cdr zl);
- endmodule;
- module driver; % Driving routines for integration program.
- % Author: Mary Ann Moore and Arthur C. Norman.
- % Modifications by: John P. Fitch.
- fluid '(!*backtrace
- !*exp
- !*gcd
- !*keepsqrts
- !*mcd
- !*nolnr
- !*purerisch
- !*rationalize
- !*sqrt
- !*structure
- !*uncached
- basic!-listofnewsqrts
- basic!-listofallsqrts
- expression
- gaussiani
- intvar
- listofnewsqrts
- listofallsqrts
- loglist
- sqrt!-intvar
- sqrt!-places!-alist
- variable
- varlist
- xlogs
- zlist);
- global '(!*algint !*failhard !*trint);
- exports integratesq,simpint,purge,simpint1;
- imports algebraiccase,algfnpl,findzvars,getvariables,interr,printsq,
- transcendentalcase,varsinlist,kernp,simpcar,prepsq,mksq,simp,
- opmtch,formlnr;
- switch algint,nolnr,trint;
- % Form is int(expr,var,x1,x2,...);
- % meaning is integrate expr wrt var, given that the result may
- % contain logs of x1,x2,...
- % x1, etc are intended for use when the system has to be helped
- % in the case that expr is algebraic.
- % Extended arguments x1, x2, etc., are not currently supported.
- symbolic procedure simpint u;
- % Simplifies an integral. First two components of U are the integrand
- % and integration variable respectively. Optional succeeding components
- % are log forms for the final integral;
- begin scalar ans,expression,variable,loglist,w,
- !*purerisch,intvar,listofnewsqrts,listofallsqrts,
- sqrtfn,sqrt!-intvar,sqrt!-places!-alist,
- basic!-listofallsqrts,basic!-listofnewsqrts;
- if atom u or null cdr u then rederr "Not enough arguments for INT";
- variable := !*a2k cadr u;
- w := cddr u;
- if w then rederr "Too many arguments to INT";
- listofnewsqrts:= list mvar gaussiani; % Initialize for SIMPSQRT.
- listofallsqrts:= list (argof mvar gaussiani . gaussiani);
- sqrtfn := get('sqrt,'simpfn);
- put('sqrt,'simpfn,'proper!-simpsqrt);
- % We need explicit settings of several switches during integral
- % evaluation. In addition, the current code cannot handle domains
- % like floating point, so we suppress it while the integral is
- % calculated. UNCACHED is turned on since integrator does its own
- % caching.
- begin scalar dmode!*,!*exp,!*gcd,!*keepsqrts,!*mcd,!*sqrt,
- !*rationalize,!*structure,!*uncached;
- !*keepsqrts := !*sqrt := t;
- !*exp := !*gcd := !*mcd := !*structure := !*uncached := t;
- dmode!* := nil;
- if !*algint
- then <<intvar:=variable; % until fix JHD code
- % Start a clean slate (in terms of SQRTSAVE) for this integral
- sqrt!-intvar:=!*q2f simpsqrti variable;
- if (red sqrt!-intvar) or (lc sqrt!-intvar neq 1)
- or (ldeg sqrt!-intvar neq 1)
- then interr "Sqrt(x) not properly formed"
- else sqrt!-intvar:=mvar sqrt!-intvar;
- basic!-listofallsqrts:=listofallsqrts;
- basic!-listofnewsqrts:=listofnewsqrts;
- sqrtsave(basic!-listofallsqrts,basic!-listofnewsqrts,
- list(variable . variable))>>;
- expression := int!-simp car u;
- % loglist := for each x in w collect int!-simp x;
- ans := errorset('(integratesq expression variable loglist),
- !*backtrace,!*backtrace);
- end;
- if errorp ans
- then return <<put('sqrt,'simpfn,sqrtfn);
- if !*failhard then error1();
- simpint1(expression . variable . w)>>
- else ans := car ans;
- expression := sqrtchk numr ans ./ sqrtchk denr ans;
- % We now need to check that all simplifications have been done
- % but we have to make sure INT is not resimplified.
- put('int,'simpfn,'simpiden);
- ans := errorset('(resimp expression),t,!*backtrace);
- put('int,'simpfn,'simpint);
- put('sqrt,'simpfn,sqrtfn);
- return if errorp ans then error1() else car ans
- end;
- symbolic procedure sqrtchk u;
- % U is a standard form. Result is another standard form with square
- % roots replaced by half powers.
- if domainp u then u
- else if not eqcar(mvar u,'sqrt)
- then addf(multpf(lpow u,sqrtchk lc u),sqrtchk red u)
- else addf(multpf(mksp(list('expt,cadr mvar u,'(quotient 1 2)),
- ldeg u),
- sqrtchk lc u),
- sqrtchk red u);
- symbolic procedure int!-simp u;
- %converts U to canonical form, including the resimplification of
- % *sq forms;
- subs2 resimp simp!* u;
- put('int,'simpfn,'simpint);
- symbolic procedure integratesq(integrand,var,xlogs);
- begin scalar varlist,zlist;
- if !*trint then <<
- printc "Integrand is...";
- printsq integrand >>;
- varlist:=getvariables integrand;
- varlist:=varsinlist(xlogs,varlist); %in case more exist in xlogs
- zlist:=findzvars(varlist,list var,var,nil); %important kernels
- %the next section causes problems with nested exponentials or logs;
- begin scalar oldzlist;
- while oldzlist neq zlist do <<
- oldzlist:=zlist;
- foreach zz in oldzlist do
- zlist:=findzvars(distexp(pseudodiff(zz,var)),zlist,var,t)>>
- end;
- if !*trint then <<
- printc "with 'new' functions :";
- print zlist >>;
- if !*purerisch and not allowedfns zlist
- then return simpint1 (integrand . var.nil);
- % If it is not suitable for Risch;
- varlist:=purge(zlist,varlist);
- % Now zlist is list of things that depend on x, and varlist is list
- % of constant kernels in integrand;
- if !*algint and cdr zlist and algfnpl(zlist,var)
- then return algebraiccase(integrand,zlist,varlist)
- else return transcendentalcase(integrand,var,xlogs,zlist,varlist)
- end;
- symbolic procedure distexp(l);
- if null l then nil
- else if atom car l then car l . distexp cdr l
- else if (caar l = 'expt) and (cadar l = 'e) then
- begin scalar ll;
- ll:=caddr car l;
- if eqcar(ll,'plus) then <<
- ll:=foreach x in cdr ll collect list('expt,'e,x);
- return ('times . ll) . distexp cdr l >>
- else return car l . distexp cdr l
- end
- else distexp car l . distexp cdr l;
- symbolic procedure pseudodiff(a,var);
- if atom a then nil
- else if car a memq '(atan equal log plus quotient sqrt times)
- then begin scalar aa,bb;
- foreach zz in cdr a do <<
- bb:=pseudodiff(zz,var);
- if aa then aa:=bb . aa else bb >>;
- return aa
- end
- else if car a eq 'expt
- then if depends(cadr a,var) then
- prepsq simp list('log,cadr a) .
- cadr a .
- caddr a .
- append(pseudodiff(cadr a,var),pseudodiff(caddr a,var))
- else caddr a . pseudodiff(caddr a,var)
- else list prepsq simpdf(list(a,var));
- symbolic procedure simpint1 u;
- begin scalar v,!*sqrt;
- u := 'int . prepsq car u . cdr u;
- if (v := formlnr u) neq u
- then if !*nolnr
- then <<v:= simp subst('int!*,'int,v);
- return remakesf numr v ./ remakesf denr v>>
- else <<!*nolnr:= nil . !*nolnr;
- u:=errorset(list('simp,mkquote v),
- !*backtrace,!*backtrace);
- if pairp u then v:=car u;
- !*nolnr:= cdr !*nolnr;
- return v>>;
- return if (v := opmtch u) then simp v
- else if !*failhard then rederr "FAILHARD switch set"
- else mksq(u,1)
- end;
- mkop 'int!*;
- put('int!*,'simpfn,'simpint!*);
- symbolic procedure simpint!* u;
- begin scalar x;
- return if (x := opmtch('int . u)) then simp x
- else simpiden('int!* . u)
- end;
- symbolic procedure remakesf u;
- %remakes standard form U, substituting operator INT for INT!*;
- if domainp u then u
- else addf(multpf(if eqcar(mvar u,'int!*)
- then mksp('int . cdr mvar u,ldeg u)
- else lpow u,remakesf lc u),
- remakesf red u);
- symbolic procedure allowedfns u;
- if null u
- then t
- else if atom car u or
- flagp(caar u,'transcendental)
- then allowedfns cdr u
- else nil;
- symbolic procedure purge(a,b);
- if null a then b
- else if null b then nil
- else purge(cdr a,delete(car a,b));
- endmodule;
- module d3d4; % Splitting of cubics and quartics.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(knowndiscrimsign zlist);
- global '(!*trint);
- exports cubic,quartic;
- imports covecdf,cuberootf,nth,forceazero,makepolydf,multdf,multdfconst,
- !*multf,negdf,plusdf,printdf,printsf,quadratic,sqrtf,vp1,vp2,addf,
- negf;
- symbolic procedure cubic(pol,var,res);
- %Split the univariate (wrt z-vars) cubic pol, at least if a
- %change of origin puts it in the form (x-a)**3-b=0;
- begin scalar a,b,c,d,v,shift,p;
- v:=covecdf(pol,var,3);
- shift:=forceazero(v,3); %make coeff x**2 vanish.
- %also checks univariate.
- % if shift='failed then go to prime;
- a:=getv(v,3); b:=getv(v,2); %=0, I hope!;
- c:=getv(v,1); d:=getv(v,0);
- if !*trint then << printc "Cubic has coefficients";
- printsf a; printsf b;
- printsf c; printsf d >>;
- if not null c then <<
- if !*trint then printc "Cubic too hard to split";
- go to exit >>;
- a:=cuberootf(a); %can't ever fail;
- d:=cuberootf(d);
- if !*trint then << printc "Cube roots of a and d are";
- printsf a; printsf d>>;
- %now a*(x+shift)+d is a factor of pol;
- %create x+shift in p;
- p:=(vp2 zlist .* shift) .+ nil;
- p:=(vp1(var,1,zlist) .* (1 ./ 1)) .+ p; %(x+shift);
- b:=nil;
- b:=(vp2 zlist .* (d ./ 1)) .+ b;
- b:=plusdf(b,multdfconst(a ./ 1,p));
- b:=makepolydf b; %get rid of denominator.
- if !*trint then << printc "One factor of the cubic is";
- printdf b >>;
- res:=('log . b) . res;
- %now form the (quadratic) cofactor;
- b:=(vp2 zlist .* (!*multf(d,d) ./ 1)) .+ nil;
- b:=plusdf(b,multdfconst(negf !*multf(a,d) ./ 1,p));
- b:=plusdf(b,multdfconst(!*multf(a,a) ./ 1,
- multdf(p,p)));
- return quadratic(makepolydf b,var,res); %deal with what is left;
- prime:
- if !*trint then printc "The following cubic does not split";
- exit:
- if !*trint then printdf pol;
- return ('log . pol) . res
- end;
- symbolic procedure quartic(pol,var,res);
- %Splits univariate (wrt z-vars) quartics that can be written
- %in the form (x-a)**4+b*(x-a)**2+c;
- begin scalar a,b,c,d,ee,v,shift,p,q,p1,p2,dsc;
- v:=covecdf(pol,var,4);
- shift:=forceazero(v,4); %make coeff x**3 vanish;
- % if shift='failed then go to prime;
- a:=getv(v,4); b:=getv(v,3); %=0, I hope.
- c:=getv(v,2); d:=getv(v,1);
- ee:=getv(v,0);
- if !*trint then << printc "Quartic has coefficients";
- printsf a; printsf b;
- printsf c; printsf d;
- printsf ee >>;
- if d
- then <<if !*trint then printc "Quartic too hard to split";
- go to exit >>;
- b:=c; c:=ee; %squash up the notation;
- if knowndiscrimsign eq 'negative then go to complex;
- dsc := addf(!*multf(b,b),multf(-4,!*multf(a,c)));
- p2 := minusf c;
- if not p2 and minusf dsc then go to complex;
- p1 := null b or minusf b;
- if not p1 then if p2 then p1 := t else p2 := t;
- p1 := if p1 then 'positive else 'negative;
- p2 := if p2 then 'negative else 'positive;
- a := sqrtf a;
- dsc := sqrtf dsc;
- if a eq 'failed or dsc eq 'failed then go to prime;
- ee := invsq(addf(a,a) ./ 1);
- d := multsq(addf(b,negf dsc) ./ 1,ee);
- ee := multsq(addf(b,dsc) ./ 1,ee);
- if !*trint
- then <<printc "Quadratic factors will have coefficients";
- printsf a; print 0; printsq d;
- printc "or"; printsq ee>>;
- p := (vp2 zlist .* shift) .+ nil;
- p := (vp1(var,1,zlist) .* (1 ./ 1)) .+ p; %(x+shift);
- q := multdf(p,p); %square of same;
- q := multdfconst(a ./ 1,q);
- p := plusdf(q,(vp2 zlist .* d) .+ nil);
- q := plusdf(q,(vp2 zlist .* ee) .+ nil);
- if !*trint
- then <<printc "Allowing for change of origin:";
- printdf p; printdf q>>;
- knowndiscrimsign := p1;
- res := quadratic(p,var,res);
- knowndiscrimsign := p2;
- res := quadratic(q,var,res);
- go to quarticdone;
- complex:
- a:=sqrtf(a);
- c:=sqrtf(c);
- if a eq 'failed or c eq 'failed then go to prime;
- b:=addf(!*multf(2,!*multf(a,c)),negf b);
- b:=sqrtf b;
- if b eq 'failed then go to prime;
- %now a*(x+shift)**2 (+/-) b*(x+shift) + c is a factor.
- if !*trint
- then << printc "Quadratic factors will have coefficients";
- printsf a; printsf b; printsf c>>;
- p:=(vp2 zlist .* shift) .+ nil;
- p:=(vp1(var,1,zlist) .* (1 ./ 1)) .+ p; %(x+shift);
- q:=multdf(p,p); %square of same;
- p:=multdfconst(b ./ 1,p);
- q:=multdfconst(a ./ 1,q);
- q:=plusdf(q,(vp2 zlist .* (c ./ 1)) .+ nil);
- if !*trint then <<
- printc "Allowing for change of origin, p (+/-) q with p,q=";
- printdf p; printdf q>>;
- %now p+q and p-q are the factors of the quartic;
- knowndiscrimsign := 'negative;
- res:=quadratic(plusdf(q,p),var,res);
- res:=quadratic(plusdf(q,negdf p),var,res);
- quarticdone:
- knowndiscrimsign := nil;
- if !*trint then printc "Quartic done";
- return res;
- prime:
- if !*trint then printc "The following quartic does not split";
- exit:
- if !*trint then printdf pol;
- return ('log . pol) . res
- end;
- endmodule;
- module factr; % Crude factorization routine for integrator.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(zlist);
- global '(!*trint);
- exports int!-fac,var2df;
- imports cubic,df2q,f2df,interr,multdf,printdf,quadratic,quartic,unifac,
- uniform,vp1,vp2,sub1;
- symbolic procedure int!-fac x;
- % Input: primitive, square-free polynomial (s.form).
- %output:
- % list of 'factors' wrt zlist
- % each item in this list is either
- % log . sq
- % or atan . sq
- % and these logs and arctans are all that is needed in the
- % integration of 1/(argument).
- begin scalar res,pol,dset,var,degree,vars;
- pol:=f2df x; %convert to distributed form
- dset:=degreeset(pol);
- %now extract factors of the form 'x' or 'log(x)' etc;
- %these correspond to items in dset with a non-zero cdr.
- begin scalar zl,ds;
- zl:=zlist; ds:=dset;
- while not null ds do <<
- if onep cdar ds then <<
- res:=('log . var2df(car zl,1,zlist)) . res;
- %record in answer.
- pol:=multdf(var2df(car zl,-1,zlist),pol);
- %divide out.
- if !*trint then << printc "Trivial factor found";
- printdf cdar res>>;
- rplaca(ds,sub1 caar ds . cdar ds) >>
- else if null zerop cdar ds then
- interr "Repeated trivial factor in arg to factor";
- zl:=cdr zl; ds:=cdr ds >>;
- end; %single term factors all removed now.
- dset:=mapcar(dset,function car); %get lower bounds.
- if !*trint
- then printc ("Upper bounds of remaining factors are now: " .
- dset);
- if dset=vp2 zlist then go to finished; %thing left is constant.
- begin scalar ds,zl;
- var:=car zlist; degree:=car dset;
- if not zerop degree then vars:=var . vars;
- ds:=cdr dset; zl:=cdr zlist;
- while not null ds do <<
- if not zerop car ds then <<
- vars:=car zl . vars;
- if zerop degree or degree>car ds then <<
- var:=car zl; degree:=car ds >> >>;
- zl:=cdr zl; ds:=cdr ds >>
- end;
- % Now var is variable that this poly involves to lowest degree.
- % Degree is the degree of the poly in same variable.
- if !*trint
- then printc ("Best var is " . var . "with exponent " .
- degree);
- if onep degree then <<
- res:=('log . pol) . res; %certainly irreducible.
- if !*trint
- then << printc "The following is certainly irreducible";
- printdf pol>>;
- go to finished >>;
- if degree=2 then <<
- if !*trint then << printc "Quadratic";
- printdf pol>>;
- res:=quadratic(pol,var,res);
- go to finished >>;
- dset:=uniform(pol,var);
- if not (dset='failed) then <<
- if !*trint then << printc "Univariate polynomial";
- printdf pol >>;
- res:=unifac(dset,var,degree,res);
- go to finished >>;
- if not null cdr vars then go to nasty; %only try univariate now.
- if degree=3 then <<
- if !*trint then << printc "Cubic";
- printdf pol>>;
- res:=cubic(pol,var,res);
- % if !*overlaymode then excise 'd3d4;
- go to finished >>;
- if degree=4 then <<
- if !*trint then << printc "Quartic";
- printdf pol>>;
- res:=quartic(pol,var,res);
- % if !*overlaymode then excise 'd3d4;
- go to finished>>;
- %else abandon hope and hand back some rubbish.
- nasty:
- res:=('log . pol) . res;
- printc
- "The following polynomial has not been properly factored";
- printdf pol;
- go to finished;
- finished: %res is a list of d.f. s as required
- pol:=nil; %convert back to standard forms
- while not null res do
- begin scalar type,arg;
- type:=caar res; arg:=cdar res;
- arg:=df2q arg;
- if type='log then rplacd(arg,1);
- pol:=(type . arg) . pol;
- res:=cdr res end;
- return pol
- end;
- symbolic procedure var2df(var,n,zlist);
- ((vp1(var,n,zlist) .* (1 ./ 1)) .+ nil);
- symbolic procedure degreeset pol;
- % Finds degree bounds for all vars in distributed form poly.
- degreesub(dbl lpow pol,red pol);
- symbolic procedure dbl x;
- % Converts list of x into list of (x . x).
- if null x then nil
- else (car x . car x) . dbl cdr x;
- symbolic procedure degreesub(cur,pol);
- % Update degree bounds 'cur' to include info about pol.
- <<
- while not null pol do <<
- cur:=degreesub1(cur,lpow pol);
- pol:=red pol >>;
- cur >>;
- symbolic procedure degreesub1(cur,nxt);
- %Merge information from exponent set next into cur.
- if null cur then nil
- else degreesub2(car cur,car nxt) . degreesub1(cdr cur,cdr nxt);
- symbolic procedure degreesub2(two,one);
- max(car two,one) . min(cdr two,one);
- endmodule;
- module ibasics; % Some basic support routines for integrator.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(!*backtrace !*gcd !*sqfree indexlist sqrtflag sqrtlist
- varlist zlist);
- global '(!*trint);
- exports partialdiff,printdf,rationalintegrate,interr;
- imports df2printform,printsf,varsinsf,addsq,multsq,multd,mksp;
- symbolic procedure printdf u;
- % Print distributed form via cheap conversion to reduce structure.
- begin scalar !*gcd;
- printsf df2printform u;
- end;
- symbolic procedure !*n2sq(u1);
- if u1=0 then nil . 1 else u1 . 1;
- symbolic procedure indx(n);
- if n<2 then (list 1) else(n . indx(isub1 n));
- symbolic procedure interr mess;
- <<(!*trint or !*backtrace)
- and <<prin2 "***** INTEGRATION PACKAGE ERROR: "; printc mess>>;
- error1()>>;
- symbolic procedure rationalintegrate(x,var);
- begin scalar n,d;
- n:=numr x; d:=denr x;
- if not var member varsinsf(d,nil) then
- return !*multsq(polynomialintegrate(n,var),1 ./ d);
- rederr "Rational integration not coded yet"
- end;
- symbolic procedure polynomialintegrate(x,v);
- % Integrate standard form. result is standard quotient.
- if null x then nil ./ 1
- else if atom x then ((mksp(v,1) .* 1) .+ nil) ./ 1
- else begin scalar r;
- r:=polynomialintegrate(red x,v); % deal with reductum
- if v=mvar x then begin scalar degree,newlt;
- degree:=1+tdeg lt x;
- newlt:=((mksp(v,degree) .* lc x) .+ nil) ./ 1; % up exponent
- r:=addsq(!*multsq(newlt,1 ./ degree),r)
- end
- else begin scalar newterm;
- newterm:=(((lpow x) .* 1) .+ nil) ./ 1;
- newterm:=!*multsq(newterm,polynomialintegrate(lc x,v));
- r:=addsq(r,newterm)
- end;
- return r
- end;
- symbolic procedure partialdiff(p,v);
- % Partial differentiation of p wrt v - p is s.f. as is result.
- if domainp p then nil
- else
- if v=mvar p then
- (lambda x; if x=1 then lc p
- else ((mksp(v,x-1) .* multd(x,lc p))
- .+ partialdiff(red p,v)))
- (tdeg lt p)
- else
- (lambda x; if null x then partialdiff(red p,v)
- else ((lpow p .* x) .+ partialdiff(red p,v)))
- (partialdiff(lc p,v));
- put('pdiff,'simpfn,'simppdiff);
- symbolic procedure ncdr(l,n);
- % we can use small integer arithmetic here.
- if n=0 then l else ncdr(cdr l,isub1 n);
- symbolic procedure mkilist(old,term);
- if null old then nil
- else term.mkilist(cdr old,term);
- %symbolic procedure addin(lista,first,listb);
- %if null lista
- % then nil
- % else ((first.car listb).car lista).addin(cdr lista,first,cdr listb);
- symbolic procedure removeduplicates(u);
- % Purges duplicates from the list passed to it.
- if null u then nil
- else if (atom u) then u.nil
- else if member(car u,cdr u)
- then removeduplicates cdr u
- else (car u).removeduplicates cdr u;
- symbolic procedure jsqfree(sf,var);
- begin
- varlist:=getvariables(sf ./ 1);
- zlist:=findzvars(varlist,list var,var,nil);
- sqrtlist:=findsqrts varlist; % before the purge
- sqrtflag:=not null sqrtlist;
- varlist:=purge(zlist,varlist);
- if sf eq !*sqfree
- then return list list sf
- else return sqfree(sf,zlist)
- end;
- symbolic procedure jfactor(sf,var);
- begin
- scalar varlist,zlist,indexlist,sqrtlist,sqrtflag;
- scalar prim,answer,u,v; % scalar var2
- prim:=jsqfree(sf,var);
- indexlist:=createindices zlist;
- prim:=factorlistlist (prim,t);
- while prim do <<
- if caar prim eq 'log then <<
- u:=cdar prim;
- u:=!*multsq(numr u ./ 1,1 ./ cdr stt(numr u,var));
- v:=denr u;
- while not atom v do v:=lc v;
- if (numberp v) and (0> v)
- then u:=(negf numr u) ./ (negf denr u);
- answer:=u.answer >>
- else if caar prim eq 'atan then <<
- % We can ignore this, since we also get LOG (U**2+1) as another term.
- >>
- else interr "Unexpected term in jfactor";
- prim:=cdr prim >>;
- return answer
- end;
- symbolic procedure stt(u,x);
- if domainp u
- then if u eq nil
- then ((-1) . nil)
- else (0 . u)
- else if mvar u eq x
- then ldeg u . lc u
- else if ordop(x,mvar u)
- then (0 . u)
- else begin
- scalar ltlc,ltrest;
- ltlc:=stt(lc u,x);
- ltrest:= stt(red u,x);
- if car ltlc = car ltrest then go to merge;
- if car ltlc > car ltrest
- then return car ltlc .
- !*multf(cdr ltlc,(lpow u .* 1) .+ nil)
- else return ltrest;
- merge:
- return car ltlc.addf(cdr ltrest,
- !*multf(cdr ltlc,(lpow u .* 1) .+ nil))
- end;
- symbolic procedure gcdinonevar(u,v,x);
- % Gcd of u and v, regarded as polynnmials in x.
- if null u
- then v
- else if null v
- then u
- else begin
- scalar u1,v1,z,w;
- u1:=stt(u,x);
- v1:=stt(v,x);
- loop:
- if (car u1) > (car v1)
- then go to ok;
- z:=u1;u1:=v1;v1:=z;
- z:=u;u:=v;v:=z;
- ok:
- if car v1 iequal 0
- then interr "Coprimeness in gcd";
- z:=gcdf(cdr u1,cdr v1);
- w:=quotf(cdr u1,z);
- if (car u1) neq (car v1)
- then w:=!*multf(w,!*p2f mksp(x,(car u1)-(car v1)));
- u:=addf(!*multf(v,w),
- !*multf(u,negf quotf(cdr v1,z)));
- if null u
- then return v;
- u1:=stt(u,x);
- go to loop
- end;
- symbolic procedure mapply(funct,l);
- if null l then rederr "Empty list to mapply"
- else if null cdr l then car l
- else apply(funct,list(car l,mapply(funct,cdr l)));
- symbolic procedure !*lcm!*(u,v);
- !*multf(u,quotf(v,gcdf(u,v)));
- symbolic procedure multsql(u,l);
- % Multiplies (!*multsq) each element of l by u.
- if null l
- then nil
- else !*multsq(u,car l).multsql(u,cdr l);
- symbolic procedure intersect(x,y);
- if null x then nil else if member(car x,y) then
- car(x) . intersect(cdr x,y) else
- intersect(cdr x,y);
- symbolic procedure mapvec(v,f);
- begin
- scalar n;
- n:=upbv v;
- for i:=0:n do
- apply(f,list getv(v,i))
- end;
- endmodule;
- module jpatches; % Routines for manipulating sf's with power folding.
- % Author: James H. Davenport.
- fluid '(sqrtflag);
- exports !*addsq,!*multsq,!*invsq,!*multf,squashsqrtsq,!*exptsq,!*exptf;
- % !*MULTF(A,B) multiplies the polynomials (standard forms) U and V
- % in much the same way as MULTF(U,V) would, EXCEPT...
- % (1) !*MULTF inhibits the action of OFF EXP and of non-commutative
- % multiplications
- % (2) Within !*MULTF powers of square roots, and powers of
- % exponential kernels are reduced as if substitution rules
- % such as FOR ALL X LET SQRT(X)**2=X were being applied;
- % Note that !*MULTF comes between MULTF and !*Q2F SUBS2F MULTF in its
- % behaviour, and that it is the responsibility of the user to call it
- % in sensible places where its services are needed;
- % similarly for the other functions defined here;
- %symbolic procedure !*addsq(u,v);
- %U and V are standard quotients.
- % %Value is canonical sum of U and V;
- % if null numr u then v
- % else if null numr v then u
- % else if denr u=1 and denr v=1 then addf(numr u,numr v) ./ 1
- % else begin scalar nu,du,nv,dv,x;
- % x := gcdf(du:=denr u,dv:=denr v);
- % du:=quotf(du,x); dv:=quotf(dv,x);
- % nu:=numr u; nv:=numr v;
- % u:=addf(!*multf(nu,dv),!*multf(nv,du));
- % if u=nil then return nil ./ 1;
- % v:=!*multf(du,denr v);
- % return !*ff2sq(u,v)
- % end;
- %symbolic procedure !*multsq(a,b);
- % begin
- % scalar n,d;
- % n:=!*multf(numr a,numr b);
- % d:=!*multf(denr a,denr b);
- % return !*ff2sq(n,d)
- % end;
- %symbolic procedure !*ff2sq(a,b);
- % begin
- % scalar gg;
- % if null a then return nil ./ 1;
- % gg:=gcdf(a,b);
- % if not (gg=1) then <<
- % a:=quotf(a,gg);
- % b:=quotf(b,gg) >>;
- % if minusf b then <<
- % a:=negf a;
- % b:=negf b >>;
- % return a ./ b
- % end;
- symbolic procedure !*addsq(u,v);
- %U and V are standard quotients.
- %Value is canonical sum of U and V;
- if null numr u then v
- else if null numr v then u
- else if denr u=1 and denr v=1 then addf(numr u,numr v) ./ 1
- else begin scalar du,dv,x,y,z;
- x := gcdf(du:=denr u,dv:=denr v);
- du:=quotf(du,x); dv:=quotf(dv,x);
- y:=addf(!*multf(dv,numr u),!*multf(du,numr v));
- if null y then return nil ./ 1;
- z:=!*multf(denr u,dv);
- if minusf z then <<y := negf y; z := negf z>>;
- if x=1 then return y ./ z;
- x := gcdf(y,x);
- return if x=1 then y ./ z else quotf(y,x) ./ quotf(z,x)
- end;
- symbolic procedure !*multsq(u,v);
- %U and V are standard quotients. Result is the canonical product of
- %U and V with surd powers suitably reduced.
- if null numr u or null numr v then nil ./ 1
- else if denr u=1 and denr v=1 then !*multf(numr u,numr v) ./ 1
- else begin scalar w,x,y;
- x := gcdf(numr u,denr v);
- y := gcdf(numr v,denr u);
- w := !*multf(quotf(numr u,x),quotf(numr v,y));
- x := !*multf(quotf(denr u,y),quotf(denr v,x));
- if minusf x then <<w := negf w; x := negf x>>;
- y := gcdf(w,x); % another factor may have been generated.
- return if y=1 then w ./ x else quotf(w,y) ./ quotf(x,y)
- end;
- symbolic procedure !*invsq a;
- % Note that several examples (e.g., int(1/(x**8+1),x)) give a more
- % compact result when SQRTFLAG is true if SQRT2TOP is not called.
- if sqrtflag then sqrt2top invsq a else invsq a;
- symbolic procedure !*multf(u,v);
- % U and V are standard forms
- % Value is SF for U*V;
- begin
- scalar x,y;
- if null u or null v
- then return nil
- else if u = 1
- then return squashsqrt v
- else if v = 1
- then return squashsqrt u
- else if domainp u
- then return multd(u,squashsqrt v)
- else if domainp v
- then return multd(v,squashsqrt u);
- x:=mvar u;
- y:=mvar v;
- if x eq y
- then go to c
- else if ordop(x,y)
- then go to b;
- x:=!*multf(u,lc v);
- y:=!*multf(u,red v);
- return if null x then y
- else if not domainp lc v
- and mvar u eq mvar lc v
- and not atom mvar u
- and car mvar u memq '(expt sqrt)
- then addf(!*multf(x,!*p2f lpow v),y) % what about noncom?
- else makeupsf(lpow v,x,y);
- b: x:=!*multf(lc u,v);
- y:=!*multf(red u,v);
- return if null x then y
- else if not domainp lc u
- and mvar lc u eq mvar v
- and not atom mvar v
- and car mvar v memq '(expt sqrt)
- then addf(!*multf(!*p2f lpow u,x),y)
- else makeupsf(lpow u,x,y);
- c: y:=addf(!*multf(list lt u,red v),!*multf(red u,v));
- if eqcar(x,'sqrt)
- then return addf(squashsqrt y,!*multfsqrt(x,
- !*multf(lc u,lc v),ldeg u + ldeg v))
- else if eqcar(x,'expt) and prefix!-rational!-numberp caddr x
- then return addf(squashsqrt y,!*multfexpt(x,
- !*multf(lc u,lc v),ldeg u + ldeg v));
- x:=mkspm(x,ldeg u + ldeg v);
- return if null x or null (u:=!*multf(lc u,lc v))
- then y
- else x .* u .+ y
- end;
- symbolic procedure makeupsf(u,x,y);
- % Makes u .* x .+ y except when u is not a valid lpow (because of
- % sqrts).
- if atom car u or cdr u = 1 then u .* x .+ y
- else if caar u eq 'sqrt then addf(!*multfsqrt(car u,x,cdr u),y)
- else if <<begin scalar v;
- v:=car u;
- if car v neq 'expt then return nil;
- v:=caddr v;
- if atom v then return nil;
- return (car v eq 'quotient
- and numberp cadr v
- and numberp caddr v)
- end >>
- then addf(!*multfexpt(car u,x,cdr u),y)
- else u .* x .+ y;
- symbolic procedure !*multfsqrt(x,u,w);
- % This code (Due to Norman a& Davenport) squashes SQRT(...)**2.
- begin scalar v;
- w:=divide(w,2);
- v:=!*q2f simp cadr x;
- u:=!*multf(u,exptf(v,car w));
- if not zerop cdr w then u:=!*multf(u,!*p2f mksp(x,1));
- return u
- end;
- symbolic procedure !*multfexpt(x,u,w);
- begin scalar expon,v;
- expon:=caddr x;
- x:=cadr x;
- w:=w * cadr expon;
- expon:=caddr expon;
- v:=gcdn(w,expon);
- w:=w/v;
- v:=expon/v;
- if not (w > 0) then rederr "Invalid exponent"
- else if v = 1
- then return !*multf(u,exptf(if numberp x then x
- else if atom x then !*k2f x
- else !*q2f if car x eq '!*sq
- then argof x
- else simp x,
- w));
- expon:=0;
- while not (w < v) do <<expon:=expon + 1; w:=w-v>>;
- if expon>0 then u:=!*multf(u,exptf(!*q2f simp x,expon));
- if w = 0 then return u;
- x:=list('expt,x,list('quotient,1,v));
- return multf(squashsqrt u,!*p2f mksp(x,w))
- end;
- symbolic procedure prefix!-rational!-numberp u;
- % Tests for m/n in prefix representation.
- eqcar(u,'quotient) and numberp cadr u and numberp caddr u;
- symbolic procedure squashsqrtsq sq;
- !*multsq(squashsqrt numr sq ./ 1,
- 1 ./ squashsqrt denr sq);
- symbolic procedure squashsqrt sf;
- if (not sqrtflag) or atom sf or atom mvar sf
- then sf
- else if car mvar sf eq 'sqrt and ldeg sf > 1
- then addf(squashsqrt red sf,!*multfsqrt(mvar sf,lc sf,ldeg sf))
- else if car mvar sf eq 'expt
- and prefix!-rational!-numberp caddr mvar sf
- and ldeg sf >= caddr caddr mvar sf
- then addf(squashsqrt red sf,!*multfexpt(mvar sf,lc sf,ldeg sf))
- else (lpow sf .* squashsqrt lc sf) .+ squashsqrt red sf;
- %remd 'simpx1;
- %symbolic procedure simpx1(u,m,n);
- % %u,m and n are prefix expressions;
- % %value is the standard quotient expression for u**(m/n);
- % begin scalar flg,z;
- % if null frlis!* or null xn(frlis!*,flatten (m . n))
- % then go to a;
- % exptp!* := t;
- % return !*k2q list('expt,u,if n=1 then m
- % else list('quotient,m,n));
- % a: if numberp m and fixp m then go to e
- % else if atom m then go to b
- % else if car m eq 'minus then go to mns
- % else if car m eq 'plus then go to pls
- % else if car m eq 'times and numberp cadr m and fixp cadr m
- % and numberp n
- % then go to tms;
- % b: z := 1;
- % c: if atom u and not numberp u then flag(list u,'used!*);
- % u := list('expt,u,if n=1 then m else list('quotient,m,n));
- % if not u member exptl!* then exptl!* := u . exptl!*;
- % d: return mksq(u,if flg then -z else z); %u is already in lowest
- %% %terms;
- % e: if numberp n and fixp n then go to int;
- % z := m;
- % m := 1;
- % go to c;
- % mns: m := cadr m;
- % if !*mcd then return invsq simpx1(u,m,n);
- % flg := not flg;
- % go to a;
- % pls: z := 1 ./ 1;
- % pl1: m := cdr m;
- % if null m then return z;
- % z := multsq(simpexpt list(u,
- % list('quotient,if flg then list('minus,car m)
- % else car m,n)),
- % z);
- % go to pl1;
- % tms: z := gcdn(n,cadr m);
- % n := n/z;
- % z := cadr m/z;
- % m := retimes cddr m;
- % go to c;
- % int:z := divide(m,n);
- % if cdr z<0 then z:= (car z - 1) . (cdr z+n);
- % if 0 = cdr z
- % then return simpexpt list(u,car z);
- % if n = 2
- % then return multsq(simpexpt list(u,car z),
- % simpsqrti u);
- % return multsq(simpexpt list(u,car z),
- % mksq(list('expt,u,list('quotient,1,n)),cdr z))
- % end;
- symbolic procedure !*exptsq(a,n);
- % raise A to the power N using !*MULTSQ;
- if n=0 then 1 ./ 1
- else if n=1 then a
- else if n<0 then !*exptsq(invsq a,-n)
- else begin
- scalar q,r;
- q:=divide(n,2);
- r:=cdr q; q:=car q;
- q:=!*exptsq(!*multsq(a,a),q);
- if r=0 then return q
- else return !*multsq(a,q)
- end;
- symbolic procedure !*exptf(a,n);
- % raise A to the power N using !*MULTF;
- if n=0 then 1
- else if n=1 then a
- else begin
- scalar q,r;
- q:=divide(n,2);
- r:=cdr q; q:=car q;
- q:=!*exptf(!*multf(a,a),q);
- if r=0 then return q
- else return !*multf(a,q)
- end;
- endmodule;
- module hacksqrt; % Routines for manipulation of sqrt expressions.
- % Author: James H. Davenport.
- fluid '(nestedsqrts thisplace);
- exports sqrtsintree,sqrtsinsq,sqrtsinsql,sqrtsinsf,sqrtsign;
- exports degreenest,sortsqrts;
- imports mkvect,interr,getv,dependsp,union;
- symbolic procedure sqrtsintree(u,var,slist);
- % Adds to slist all the sqrts in the prefix-type tree u.
- if atom u
- then slist
- else if car u eq '!*sq
- then union(slist,sqrtsinsq(cadr u,var))
- else if car u eq 'sqrt
- then if dependsp(argof u,var)
- then <<
- slist:=sqrtsintree(argof u,var,slist);
- % nested square roots
- if member(u,slist)
- then slist
- else u.slist >>
- else slist
- else sqrtsintree(car u,var,sqrtsintree(cdr u,var,slist));
- symbolic procedure sqrtsinsq(u,var);
- % Returns list of all sqrts in sq.
- sqrtsinsf(denr u,sqrtsinsf(numr u,nil,var),var);
- symbolic procedure sqrtsinsql(u,var);
- % Returns list of all sqrts in sq list.
- if null u
- then nil
- else sqrtsinsf(denr car u,
- sqrtsinsf(numr car u,sqrtsinsql(cdr u,var),var),var);
- symbolic procedure sqrtsinsf(u,slist,var);
- % Adds to slist all the sqrts in sf.
- if domainp u or null u
- then slist
- else <<
- if eqcar(mvar u,'sqrt) and
- dependsp(argof mvar u,var) and
- not member(mvar u,slist)
- then begin
- scalar slist2;
- slist2:=sqrtsintree(argof mvar u,var,nil);
- if slist2
- then <<
- nestedsqrts:=t;
- slist:=union(slist2,slist) >>;
- slist:=(mvar u).slist
- end;
- sqrtsinsf(lc u,sqrtsinsf(red u,slist,var),var) >>;
- symbolic procedure easysqrtsign(slist,things);
- % This procedure builds a list of all substitutions for all possible
- % combinations of square roots in list.
- if null slist
- then things
- else easysqrtsign(cdr slist,
- nconc(mapcons(things,(car slist).(car slist)),
- mapcons(things,
- list(car slist,'minus,car slist))));
- symbolic procedure hardsqrtsign(slist,things);
- % This procedure fulfils the same role for nested sqrts
- % ***assumption: the simpler sqrts come further up the list.
- if null slist
- then things
- else begin
- scalar thisplace,answers,pos,neg;
- thisplace:=car slist;
- answers:=mapcar(things,function (lambda u;sublis(u,thisplace).u));
- pos:=mapcar(answers,function (lambda u;(thisplace.car u).(cdr u)));
- % pos is sqrt(f) -> sqrt(innersubst f)
- neg:=mapcar(answers,
- function (lambda u;list(thisplace,'minus,car u).(cdr u)));
- % neg is sqrt(f) -> -sqrt(innersubst f)
- return hardsqrtsign(cdr slist,nconc(pos,neg))
- end;
- symbolic procedure degreenest(pf,var);
- % Returns the maximum degree of nesting of var
- % inside sqrts in the prefix form pf.
- if atom pf
- then 0
- else if car pf eq 'sqrt
- then if dependsp(cadr pf,var)
- then iadd1 degreenest(cadr pf,var)
- else 0
- else if car pf eq 'expt
- then if dependsp(cadr pf,var)
- then if eqcar(caddr pf,'quotient)
- then iadd1 degreenest(cadr pf,var)
- else degreenest(cadr pf,var)
- else 0
- else degreenestl(cdr pf,var);
- symbolic procedure degreenestl(u,var);
- %Returns max degreenest from list of pfs u.
- if null u
- then 0
- else max(degreenest(car u,var),
- degreenestl(cdr u,var));
- symbolic procedure sortsqrts(u,var);
- % Sorts list of sqrts into order required by hardsqrtsign
- % (and many other parts of the package).
- begin
- scalar i,v;
- v:=mkvect(10); %should be good enough!
- while u do <<
- i:=degreenest(car u,var);
- if i iequal 0
- then interr "Non-dependent sqrt found";
- if i > 10
- then interr
- "Degree of nesting exceeds 10 (recompile with 10 increased)";
- putv(v,i,(car u).getv(v,i));
- u:=cdr u >>;
- u:=getv(v,10);
- for i :=9 step -1 until 1 do
- u:=nconc(getv(v,i),u);
- return u
- end;
- symbolic procedure sqrtsign(sqrts,x);
- if nestedsqrts then hardsqrtsign(sortsqrts(sqrts,x),list nil)
- else easysqrtsign(sqrts,list nil);
- endmodule;
- module kron; % Kronecker factorization of univ. polys over integers.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- global '(!*trint);
- exports linfac,quadfac;
- imports zfactor;
- % Only linear and quadratic factors are found.
- symbolic procedure linfac(w);
- trykr(w,'(0 1));
- symbolic procedure quadfac(w);
- trykr(w,'(-1 0 1));
- symbolic procedure trykr(w,points);
- %Look for factor of w by evaluation at (points) and use of
- % interpolate. Return (fac . cofac) with fac=nil if none
- % found and cofac=nil if nothing worthwhile is left.
- begin scalar values,attempt;
- if null w then return nil . nil;
- if (length points > car w) then return w . nil;
- %that says if w is already tiny, it is already factored.
- values:=mapcar(points,function (lambda x;
- evalat(w,x)));
- if !*trint then << printc ("At x= " . points);
- printc ("p(x)= " . values)>>;
- if 0 member values then go to lucky; %(x-1) is a factor!
- values:=mapcar(values,function zfactors);
- rplacd(values,mapcar(cdr values,function (lambda y;
- append(y,mapcar(y,function minus)))));
- if !*trint then <<printc "Possible factors go through some of";
- print values>>;
- attempt:=search4fac(w,values,nil);
- if null attempt then attempt:=nil . w;
- return attempt;
- lucky: %here (x-1) is a factor because p(0) or p(1) or p(-1)
- %vanished and cases p(0), p(-1) will have been removed
- %elsewhere.
- attempt:='(1 1 -1); %the factor
- return attempt . testdiv(w,attempt)
- end;
- symbolic procedure zfactors n;
- % Produces a list of all (positive) integer factors of the integer n.
- if n=0 then list 0
- else if (n:=abs n)=1 then list 1
- else combinationtimes zfactor n;
- symbolic procedure search4fac(w,values,cv);
- % Combinatorial search. cv gets current selected value-set.
- % Returns nil if fails, else factor . cofactor.
- if null values then tryfactor(w,cv)
- else begin scalar ff,q;
- ff:=car values; %try all values here
- loop: if null ff then return nil; %no factor found
- q:=search4fac(w,cdr values,(car ff) . cv);
- if null q then << ff:=cdr ff; go to loop>>;
- return q
- end;
- symbolic procedure tryfactor(w,cv);
- % Tests if cv represents a factor of w.
- begin scalar ff,q;
- if null cddr cv then ff:=linethrough(cadr cv,car cv)
- else ff:=quadthrough(caddr cv,cadr cv,car cv);
- if ff='failed then return nil; %it does not interpolate
- q:=testdiv(w,ff);
- if q='failed then return nil; %not a factor
- return ff . q
- end;
- symbolic procedure evalat(p,n);
- % Evaluate polynomial at integer point n.
- begin scalar r;
- r:=0;
- p:=cdr p;
- while not null p do <<
- r:=n*r+car p;
- p:=cdr p >>;
- return r
- end;
- symbolic procedure testdiv(a,b);
- % Quotient a/b or failed.
- begin scalar q;
- q:=testdiv1(cdr a,car a,cdr b,car b);
- if q='failed then return q;
- return (car a-car b) . q
- end;
- symbolic procedure testdiv1(a,da,b,db);
- if da<db then begin
- check0: if null a then return nil
- else if not zerop car a then return 'failed;
- a:=cdr a;
- go to check0
- end
- else begin scalar q;
- q:=divide(car a,car b);
- if zerop cdr q then q:=car q
- else return 'failed;
- a:=testdiv1(ambq(cdr a,cdr b,q),da-1,b,db);
- if a='failed then return a;
- return q . a
- end;
- symbolic procedure ambq(a,b,q);
- % A-B*Q with Q an integer.
- if null b then a
- else ((car a)-(car b)*q) . ambq(cdr a,cdr b,q);
- symbolic procedure linethrough(y0,y1);
- begin scalar a;
- a:=y1-y0;
- if zerop a then return 'failed;
- if a<0 then <<a:=-a; y0:=-y0 >>;
- if onep gcdn(a,y0) then return list(1,a,y0);
- return 'failed
- end;
- symbolic procedure quadthrough(ym1,y0,y1);
- begin scalar a,b,c;
- a:=divide(ym1+y1,2);
- if zerop cdr a then a:=(car a)-y0
- else return 'failed;
- if zerop a then return 'failed; %linear things already done.
- c:=y0;
- b:=divide(y1-ym1,2);
- if zerop cdr b then b:=car b
- else return 'failed;
- if not onep gcdn(a,gcd(b,c)) then return 'failed;
- if a<0 then <<a:=-a; b:=-b; c:=-c>>;
- return list(2,a,b,c)
- end;
- endmodule;
- module lowdeg; % Splitting of low degree polynomials.
- % Author: To be determined.
- fluid '(clogflag knowndiscrimsign zlist);
- global '(!*trint);
- exports forceazero,makepolydf,quadratic,covecdf,exponentdf;
- imports dfquotdf,gcdf,interr,minusdfp,multdf,multdfconst,!*multf,
- negsq,minusp,printsq,multsq,invsq,pnth,nth,mknill,
- negdf,plusdf,printdf,printsq,quotf,sqrtdf,var2df,vp2,addsq,sub1;
- symbolic procedure covecdf(pol,var,degree);
- % Extract coefficients of polynomial wrt var, given a degree-bound
- % degree. Result is a lisp vector.
- begin scalar v,x,w;
- w:=pol;
- v:=mkvect(degree);
- while not null w do <<
- x:=exponentof(var,lpow w,zlist);
- if (x<0) or (x>degree) then interr "Bad degree in covecdf";
- putv(v,x,lt w . getv(v,x));
- w:=red w >>;
- for i:=0:degree do putv(v,i,multdf(reversewoc getv(v,i),
- var2df(var,-i,zlist)));
- return v
- end;
- symbolic procedure quadratic(pol,var,res);
- % Add in to res logs or arctans corresponding to splitting the
- % polynomial. Pol given that it is quadratic wrt var.
- % Does not assume pol is univariate.
- begin scalar a,b,c,w,discrim;
- w:=covecdf(pol,var,2);
- a:=getv(w,2); b:=getv(w,1); c:=getv(w,0);
- % that split the quadratic up to find the coefficients a,b,c.
- if !*trint then << printc "a="; printdf a;
- printc "b="; printdf b;
- printc "c="; printdf c>>;
- discrim:=plusdf(multdf(b,b),
- multdfconst((-4) . 1,multdf(a,c)));
- if !*trint then << printc "Discriminant is";
- printdf discrim>>;
- if null discrim then interr "Discrim=0 in quadratic";
- if knowndiscrimsign
- then <<if knowndiscrimsign eq 'negative then go to atancase>>
- else if (not clogflag) and (minusdfp discrim)
- then go to atancase;
- discrim:=sqrtdf(discrim);
- if discrim='failed then go to nofactors;
- if !*trint then << printc "Square root is";
- printdf discrim>>;
- w:=var2df(var,1,zlist);
- w:=multdf(w,a);
- b:=multdfconst(1 ./ 2,b);
- discrim:=multdfconst(1 ./ 2,discrim);
- w:=plusdf(w,b); %a*x+b/2.
- a:=plusdf(w,discrim); b:=plusdf(w,negdf(discrim));
- if !*trint then << printc "Factors are";
- printdf a; printdf b>>;
- return ('log . a) . ('log . b) . res;
- atancase:
- discrim:=sqrtdf negdf discrim; %sqrt(4*a*c-b**2) this time!
- if discrim='failed then go to nofactors; %sqrt did not exist?
- res := ('log . pol) . res; %one part of the answer
- a:=multdf(a,var2df(var,1,zlist));
- a:=plusdf(b,multdfconst(2 ./ 1,a));
- a:=dfquotdf(a,discrim); %assumes division is exact
- return ('atan . a) . res;
- nofactors:
- if !*trint
- then <<printc
- "The following quadratic does not seem to factor";
- printdf pol>>;
- return ('log . pol) . res
- end;
- symbolic procedure exponentof(var,l,zl);
- if null zl then interr "Var not found in exponentof"
- else if var=car zl then car l
- else exponentof(var,cdr l,cdr zl);
- symbolic procedure df2sf a;
- if null a then nil
- else if ((null red a) and
- (denr lc a = 1) and
- (lpow a=vp2 zlist)) then numr lc a
- else interr "Nasty cubic or quartic";
- symbolic procedure makepolydf p;
- % Multiply df by lcm of denominators of all coefficient denominators.
- begin scalar h,w;
- if null(w:=p) then return nil; %poly is zero already.
- h:=denr lc w; %a good start.
- w:=red w;
- while not null w do <<
- h:=quotf(!*multf(h,denr lc w),gcdf(h,denr lc w));
- w:=red w >>;
- %h is now lcm of denominators.
- return multdfconst(h ./ 1,p)
- end;
- symbolic procedure forceazero(p,n);
- %Shift polynomial p so that coeff of x**(n-1) vanishes.
- %Return the amount of the shift, update (vector) p.
- begin scalar r,i,w;
- for i:=0:n do putv(p,i,df2sf getv(p,i)); %convert to polys.
- r:=getv(p,n-1);
- if null r then return nil ./ 1; %already zero.
- r:= !*multsq(r ./ 1,invsq(!*multf(n,getv(p,n)) ./ 1));
- % Used to be subs2q multsq
- %the shift amount.
- %now I have to set p:=subst(x-r,x,p) and then reduce to sf again.
- if !*trint then << printc "Shift is by ";
- printsq r>>;
- w:=mkvect(n); %workspace vector.
- for i:=0:n do putv(w,i,nil ./ 1); %zero it.
- i:=n;
- while not minusp i do <<
- mulvecbyxr(w,negsq r,n); %W:=(X-R)*W;
- putv(w,0,addsq(getv(w,0),getv(p,i) ./ 1));
- i:=i-1 >>;
- if !*trint then << printc "SQ shifted poly is";
- print w>>;
- for i:=0:n do putv(p,i,getv(w,i));
- w:=denr getv(p,0);
- for i:=1:n do w:=quotf(!*multf(w,denr getv(p,i)),
- gcdf(w,denr getv(p,i)));
- for i:=0:n do putv(p,i,numr !*multsq(getv(p,i),w ./ 1));
- % Used to be subs2q multsq
- w:=getv(p,0);
- for i:=1:n do w:=gcdf(w,getv(p,i));
- if not (w=1) then
- for i:=0:n do putv(p,i,quotf(getv(p,i),w));
- if !*trint then << printc "Final shifted poly is ";
- print p>>;
- return r
- end;
- symbolic procedure mulvecbyxr(w,r,n);
- % W is a vector representing a poly of degree n.
- % Multiply it by (x+r).
- begin scalar i,im1;
- i:=n;
- im1:=sub1 i;
- while not minusp im1 do <<
- putv(w,i,!*addsq(getv(w,im1),!*multsq(r,getv(w,i))));
- % Used to be subs2q addsq/multsq
- i:=im1; im1:=sub1 i >>;
- putv(w,0,!*multsq(getv(w,0),r));
- % Used to be subs2q multsq
- return w
- end;
- endmodule;
- module reform; % Reformulate expressions using C-constant substitution.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(cmap cval loglist ulist);
- global '(!*trint);
- exports logstosq,substinulist;
- imports prepsq,mksp,nth,multsq,addsq,domainp,invsq,plusdf;
- symbolic procedure substinulist ulist;
- % Substitutes for the C-constants in the values of the U's given in
- % ULIST. Result is a D.F.
- if null ulist then nil
- else begin scalar temp,lcu;
- lcu:=lc ulist;
- temp:=evaluateuconst numr lcu;
- if null numr temp then temp:=nil
- else temp:=((lpow ulist) .*
- !*multsq(temp,!*invsq(denr lcu ./ 1))) .+ nil;
- return plusdf(temp,substinulist red ulist)
- end;
- symbolic procedure evaluateuconst coefft;
- % Substitutes for the C-constants into COEFFT (=S.F.). Result is S.Q.;
- if null coefft or domainp coefft then coefft ./ 1
- else begin scalar temp;
- if null(temp:=assoc(mvar coefft,cmap)) then
- temp:=(!*p2f lpow coefft) ./ 1
- else temp:=getv(cval,cdr temp);
- temp:=!*multsq(temp,evaluateuconst(lc coefft));
- % Next line had addsq previously
- return !*addsq(temp,evaluateuconst(red coefft))
- end;
- symbolic procedure logstosq;
- % Converts LOGLIST to sum of the log terms as a S.Q.;
- begin scalar lglst,logsq,i,temp;
- i:=1;
- lglst:=loglist;
- logsq:=nil ./ 1;
- loop: if null lglst then return logsq;
- temp:=cddr car lglst;
- if !*trint
- then <<printc "SF arg for log etc ="; printc temp>>;
- if not (caar lglst='iden) then <<
- temp:=prepsq temp; %convert to prefix form.
- temp:=list(caar lglst,temp); %function name.
- temp:=((mksp(temp,1) .* 1) .+ nil) ./ 1 >>;
- temp:=!*multsq(temp,getv(cval,i));
- % Next line had addsq previously
- logsq:=!*addsq(temp,logsq);
- lglst:=cdr lglst;
- i:=i+1;
- go to loop
- end;
- endmodule;
- module simplog; % Simplify logarithms.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- exports simplog,simplogsq;
- imports quotf,prepf,mksp,simp!*,!*multsq,simptimes,addsq,minusf,negf,
- addf,comfac,negsq,mk!*sq,carx;
- symbolic procedure simplog(exxpr); simplogi carx(exxpr,'simplog);
- symbolic procedure simplogi(sq);
- begin
- if atom sq then go to simplify;
- if car sq eq 'times
- then return simpplus(for each u in cdr sq
- collect mk!*sq simplogi u);
- if car sq eq 'quotient
- then return addsq(simplogi cadr sq,
- negsq simplogi caddr sq);
- if car sq eq 'expt
- then return simptimes list(caddr sq,
- mk!*sq simplogi cadr sq);
- if car sq eq 'nthroot
- then return !*multsq(1 ./ caddr sq,simplogi cadr sq);
- % we had (nthroot of n).
- if car sq eq 'sqrt
- then return !*multsq(1 ./ 2,simplogi argof sq);
- if car sq = '!*sq
- then return simplogsq cadr sq;
- simplify:
- sq:=simp!* sq;
- return simplogsq sq
- end;
- symbolic procedure simplogsq sq;
- addsq((simplog2 numr sq),negsq(simplog2 denr sq));
- symbolic procedure simplog2(sf);
- if atom sf
- then if null sf then rederr "Log 0 formed"
- else if numberp sf
- then if sf iequal 1
- then nil ./ 1
- else if sf iequal 0 then rederr "Log 0 formed"
- else((mksp(list('log,sf),1) .* 1) .+ nil) ./ 1
- else formlog(sf)
- else begin
- scalar form;
- form:=comfac sf;
- if not null car form
- then return addsq(formlog(form .+ nil),
- simplog2 quotf(sf,form .+ nil));
- % we have killed common powers.
- form:=cdr form;
- if form neq 1
- then return addsq(simplog2 form,
- simplog2 quotf(sf,form));
- % remove a common factor from the sf.
- return (formlog sf)
- end;
- symbolic procedure formlogterm(sf);
- begin
- scalar u;
- u:=mvar sf;
- if not atom u and (car u member '(times sqrt expt nthroot))
- then u:=addsq(simplog2 lc sf,
- !*multsq(simplogi u,simp!* ldeg sf))
- else if (lc sf iequal 1) and (ldeg sf iequal 1)
- then u:=((mksp(list('log,u),1) .* 1) .+ nil) ./ 1
- else u:=addsq(simptimes list(list('log,u),ldeg sf),
- simplog2 lc sf);
- return u
- end;
- symbolic procedure formlog sf;
- if null red sf
- then formlogterm sf
- else if minusf sf
- then addf((mksp(list('log,-1),1) .* 1) .+ nil,
- formlog2 negf sf) ./ 1
- else (formlog2 sf) ./ 1;
- symbolic procedure formlog2 sf;
- ((mksp(list('log,prepf sf),1) .* 1) .+ nil);
- endmodule;
- module simpsqrt; % Simplify square roots.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- % Heavily modified J.H. Davenport for algebraic functions.
- fluid '(!*backtrace !*conscount !*galois !*pvar basic!-listofallsqrts
- gaussiani basic!-listofnewsqrts kord!* knowntobeindep
- listofallsqrts listofnewsqrts sqrtflag sqrtlist
- sqrt!-places!-alist variable varlist zlist);
- global '(!*tra !*trint);
- % This module should be rewritten in terms of the REDUCE function
- % SIMPSQRT;
- % remd 'simpsqrt;
- exports proper!-simpsqrt,simpsqrti,simpsqrtsq,simpsqrt2,sqrtsave,
- newplace,actualsimpsqrt,formsqrt;
- symbolic procedure proper!-simpsqrt(exprn);
- simpsqrti carx(exprn,'proper!-simpsqrt);
- symbolic procedure simpsqrti sq;
- begin
- scalar u;
- if atom sq
- then if numberp sq
- then return (simpsqrt2 sq) ./ 1
- else if (u:=get(sq,'avalue))
- then return simpsqrti cadr u
- % BEWARE!!! This is VERY system dependent.
- else return simpsqrt2((mksp(sq,1) .* 1) .+ nil) ./ 1;
- % If it doesnt have an AVALUE then it is itself;
- if car sq eq 'times
- then return mapply(function multsq,
- mapcar(cdr sq,function simpsqrti));
- if car sq eq 'quotient
- then return multsq(simpsqrti cadr sq,
- invsq simpsqrti caddr sq);
- if car sq eq 'expt and numberp caddr sq
- then if evenp caddr sq
- then return simpexpt list(cadr sq,caddr sq / 2)
- else return simpexpt
- list(mk!*sq simpsqrti cadr sq,caddr sq);
- if car sq = '!*sq
- then return simpsqrtsq cadr sq;
- return simpsqrtsq tidysqrt simp!* sq
- end;
- symbolic procedure simpsqrtsq sq;
- (simpsqrt2 numr sq) ./ (simpsqrt2 denr sq);
- symbolic procedure simpsqrt2 sf;
- if minusf sf
- then if sf iequal -1
- then gaussiani
- else begin
- scalar u;
- u:=negf sf;
- if numberp u
- then return multf(gaussiani,simpsqrt3 u);
- % we cannot negate general expressions for the following reason:
- % (%%%thesis remark%%%)
- % sqrt(x*x-1) under x->1/x gives sqrt(1-x*x)/x=i*sqrt(x*x-1)/x
- % under x->1/x gives x*i*sqrt(-1+1/x*x)=i**2*sqrt(x*x-1)
- % hence an abysmal catastrophe;
- return simpsqrt3 sf
- end
- else simpsqrt3 sf;
- symbolic procedure simpsqrt3 sf;
- begin
- scalar u;
- u:=assoc(sf,listofallsqrts);
- if u
- then return cdr u;
- % now see if 'knowntobeindep'can help.
- u:=atsoc(listofnewsqrts,knowntobeindep);
- if null u
- then go to no;
- u:=assoc(sf,cdr u);
- if u
- then <<
- listofallsqrts:=u.listofallsqrts;
- return cdr u >>;
- no:
- u:=actualsimpsqrt sf;
- listofallsqrts:=(sf.u).listofallsqrts;
- return u
- end;
- symbolic procedure sqrtsave(u,v,place);
- begin
- scalar a;
- %u is new value of listofallsqrts, v of new.
- a:=assoc(place,sqrt!-places!-alist);
- if null a
- then sqrt!-places!-alist:=(place.(listofnewsqrts.listofallsqrts))
- .sqrt!-places!-alist
- else rplacd(a,listofnewsqrts.listofallsqrts);
- listofnewsqrts:=v;
- % throw away things we are not going to need in future.
- if not !*galois
- then listofallsqrts:=u;
- % we cannot guarantee the validity of our calculations.
- if listofallsqrts eq u
- then return nil;
- v:=listofallsqrts;
- while not (cdr v eq u) do
- v:=cdr v;
- rplacd(v,nil);
- % listofallsqrts is all those added since routine was entered.
- v:=atsoc(listofnewsqrts,knowntobeindep);
- if null v
- then knowntobeindep:=(listofnewsqrts.listofallsqrts)
- . knowntobeindep
- else rplacd(v,union(cdr v,listofallsqrts));
- listofallsqrts:=u;
- return nil
- end;
- symbolic procedure newplace(u);
- % Says to restart algebraic bases at a new place u.
- begin
- scalar v;
- v:=assoc(u,sqrt!-places!-alist);
- if null v
- then <<
- listofallsqrts:=basic!-listofallsqrts;
- listofnewsqrts:=basic!-listofnewsqrts >>
- else <<
- v:=cdr v;
- listofnewsqrts:=car v;
- listofallsqrts:=cdr v >>;
- return if v then v
- else listofnewsqrts.listofallsqrts
- end;
- symbolic procedure mknewsqrt u;
- % U is prefix form.
- begin
- scalar v,w;
- if not !*galois then go to new;
- % no checking required.
- v:=addf(!*p2f mksp(!*pvar,2),negf !*q2f tidysqrt simp u);
- % count !*conscount;
- w:=errorset(list('afactor,mkquote v,mkquote !*pvar),t,!*backtrace);
- % if !*tra then <<
- % princ "*** That took ";
- % princ (!*conscount - count nil);
- % printc " conses" >>;
- % count 0;
- if atom w
- then go to new
- else w:=car w; %the actual result of afactor.
- if cdr w
- then go to notnew;
- new:
- w:=sqrtify u;
- listofnewsqrts:=w . listofnewsqrts;
- return !*kk2f w;
- notnew:
- w:=car w;
- v:=stt(w,!*pvar);
- if car v neq 1
- then rederr "HELP ...";
- w:=addf(w,multf(cdr v,(mksp(!*pvar,car v) .* -1) .+nil));
- w:=sqrt2top(w ./ cdr v);
- w:=quotf(numr w,denr w);
- if null w
- then rederr "Division failure";
- return w
- end;
- symbolic procedure actualsimpsqrt(sf);
- if sf iequal -1
- then gaussiani
- else actualsqrtinner(sf,listofnewsqrts);
- symbolic procedure actualsqrtinner(sf,l);
- if null l
- then actualsimpsqrt2 sf
- else begin
- scalar z;
- % z:=simp argof car l;
- % if denr z neq 1 or (z := numr z) iequal -1
- z:=!*q2f simp argof car l;
- if z iequal -1
- then return actualsqrtinner(sf,cdr l);
- z:=quotf(sf,z);
- if null z
- then return actualsqrtinner(sf,cdr l);
- return !*multf(!*kk2f car l,actualsimpsqrt z)
- end;
- symbolic procedure actualsimpsqrt2(sf);
- if atom sf
- then if null sf
- then nil
- else if numberp sf
- then if sf < 0
- then multf(gaussiani,actualsimpsqrt2(- sf))
- %Above 2 lines inserted JHD 4 Sept 80;
- % test case: SQRT(B*X**2-C)/SQRT(X);
- else begin
- scalar n;
- n:=int!-sqrt sf;
- % Changed for conformity with DEC20 LISP JHD July 1982;
- if not fixp n
- then return mknewsqrt sf
- else return n
- end
- else mknewsqrt(sf)
- else begin
- scalar form;
- form:=comfac sf;
- if car form
- then return multf((if null cdr sf and (car sf = form)
- then formsqrt(form .+ nil)
- else simpsqrt2(form .+ nil)),
- %The above 2 lines changed by JHD;
- %(following suggestions of Morrison);
- %to conform to Standard LISP 4 Sept 80;
- simpsqrt2 quotf(sf,form .+ nil));
- % we have killed common powers.
- form:=cdr form;
- if form neq 1
- then return multf(simpsqrt2 form,
- simpsqrt2 quotf(sf,form));
- % remove a common factor from the sf.
- return formsqrt sf
- end;
- symbolic procedure int!-sqrt n;
- % Return sqrt of n if same is exact, or something non-numeric
- % otherwise.
- if not numberp n then 'nonnumeric
- else if n<0 then 'negative
- else if floatp n then sqrt!-float n
- else if n<2 then n
- else int!-nr(n,(n+1)/2);
- symbolic procedure int!-nr(n,root);
- % root is an overestimate here. nr moves downwards to root;
- begin
- scalar w;
- w:=root*root;
- if n=w then return root;
- w:=(root+n/root)/2;
- if w>=root then return !*q2f simpsqrt list n;
- return int!-nr(n,w)
- end;
- symbolic procedure formsqrt(sf);
- if (null red sf)
- then if (lc sf iequal 1) and (ldeg sf iequal 1)
- then mknewsqrt mvar sf
- else multf(if evenp ldeg sf
- then !*p2f mksp(mvar sf,ldeg sf / 2)
- else exptf(mknewsqrt mvar sf,ldeg sf),simpsqrt2 lc sf)
- else begin
- scalar varlist,zlist,sqrtlist,sqrtflag;
- scalar v,l,n,w;
- % This returns a list, the i-th member of which is
- % a list of the factors of multiplicity i (as s.f's);
- v:=jsqfree(sf,if variable and involvesf(sf,variable)
- then variable
- else findatom mvar sf);
- % VARIABLE is the best thing to do square-free
- % decompositions with respect to, but anything
- % else will do if VARIABLE is not set;
- if null cdr v and null cdar v
- then return mknewsqrt prepf sf;
- % The JSQFREE did nothing;
- l:=nil;
- n:=0;
- while v do <<
- n:=n+1;
- w:=car v;
- while w do <<
- l:=list('expt,mk!*sq !*f2q car w,n) . l;
- w:=cdr w >>;
- v:=cdr v >>;
- if null cdr l
- then l:=car l
- else l:='times.l;
- % makes L into a valid prefix form;
- return !*q2f simpsqrti l
- end;
- symbolic procedure findatom pf;
- if atom pf
- then pf
- else findatom argof pf;
- symbolic procedure sqrtify u;
- % Actually creates the sqrt.
- begin
- scalar v,n,prinlist;
- n:=degreenest(u,nil);
- % v:=list('sqrt,u);
- v := mksqrt u; % To ensure sqrt**2 rule set.
- prinlist:=member(v,kord!*);
- if prinlist then return car prinlist;
- % This might improve sharing.
- % anyway, we mustn't re-add this object to KORD!*;
- while kord!* and
- eqcar(car kord!*,'sqrt) and
- (degreenest(argof car kord!*,nil) > n) do <<
- prinlist:=(car kord!*) . prinlist;
- kord!*:=cdr kord!* >>;
- kord!*:=v . kord!*;
- while prinlist do <<
- kord!*:=(car prinlist) . kord!*;
- prinlist:=cdr prinlist >>;
- return v
- end;
- % deflist ('((sqrt (((x) quotient (sqrt x) (times 2 x))))),'dfn);
- % put('sqrt,'simpfn,'proper!-simpsqrt); % Now in driver.
- endmodule;
- module isolve; % Routines for solving the final reduction equation.
- % Author: Mary Ann Moore and Arthur C. Norman.
- % Modifications by: John P. Fitch.
- fluid '(badpart
- ccount
- cmap
- cmatrix
- cval
- indexlist
- lhs!*
- lorder
- nnn
- orderofelim
- pt
- rhs!*
- sillieslist
- tanlist
- ulist
- zlist);
- global '(!*number!* !*statistics !*trint);
- exports solve!-for!-u;
- imports nth,findpivot,gcdf,int!-gensym1,mkvect,interr,multdfconst,
- !*multf!*,negdf,orddf,plusdf,printdf,printsf,printspreadc,printsq,
- quotf,putv,spreadc,subst4eliminatedcs,mknill,pnth,domainp,addf,
- invsq,multsq;
- symbolic procedure uterm(powu,rhs!*);
- % Finds the contribution from RHS!* of reduction equation, of the;
- % U-coefficient given by POWU. Result is in D.F.;
- if null rhs!* then nil
- else begin scalar coef,power;
- power:=addinds(powu,lpow rhs!*);
- coef:=evaluatecoeffts(numr lc rhs!*,powu);
- if null coef then return uterm(powu,red rhs!*);
- coef:=coef ./ denr lc rhs!*;
- return plusdf((power .* coef) .+ nil,uterm(powu,red rhs!*))
- end;
- symbolic procedure solve!-for!-u(rhs!*,lhs!*,ulist);
- % Solves the reduction eqn LHS!*=RHS!*. Returns list of U-coefficients
- % and their values (ULIST are those we have so far), and a list of
- % C-equations to be solved (CLIST are the eqns we have so far).
- if null lhs!* then ulist
- else begin scalar u,lpowlhs;
- lpowlhs:=lpow lhs!*;
- begin scalar ll,mm,chge; ll:=maxorder(rhs!*,zlist,0);
- mm:=lorder;
- while mm do << if car ll < car mm then
- << chge:=t; rplaca(mm,car ll) >>;
- ll:=cdr ll; mm:=cdr mm >>;
- if !*trint and chge then << print ("Maxorder now ".lorder) >>
- end;
- u:=pickupu(rhs!*,lpow lhs!*,t);
- if null u then
- << if !*trint then << printc "***** C-equation to solve:";
- printsf numr lc lhs!*;
- printc " = 0";
- printc " ">>;
- % Remove a zero constant from the lhs, rather than use
- % Gauss Elim;
- if gausselimn(numr lc lhs!*,lt lhs!*) then
- lhs!*:=squashconstants(red lhs!*)
- else lhs!*:=red lhs!* >>
- else
- << ulist:=(car u .
- !*multsq(coefdf(lhs!*,lpowlhs),invsq cdr u)).ulist;
- % used to be subs2q multsq
- if !*statistics then !*number!*:=!*number!*+1;
- if !*trint then <<prin2 "***** U"; prin2 car u; prin2t " =";
- printsq multsq(coefdf(lhs!*,lpowlhs),invsq cdr u);
- printc " ">>;
- lhs!*:=plusdf(lhs!*,
- negdf multdfconst(cdar ulist,uterm(car u,rhs!*))) >>;
- if !*trint then << printc ".... LHS is now:";
- printdf lhs!*;
- printc " ">>;
- return solve!-for!-u(rhs!*,lhs!*,ulist)
- end;
- symbolic procedure squashconstants(express);
- begin scalar constlst,ii,xp,cl,subby,cmt,xx;
- constlst:=reverse cmap;
- cmt:=cmatrix;
- xxx: xx:=car cmt; % Look at next row of Cmatrix;
- cl:=constlst; % and list of the names;
- ii:=1; % will become index of removed constant;
- while not getv(xx,ii) do
- << ii:=ii+1; cl:=cdr cl >>;
- subby:=caar cl; %II is now index, and SUBBY the name;
- if member(subby,sillieslist) then
- <<cmt:=cdr cmt; go to xxx>>; %This loop must terminate;
- % This is because at least one constant remains;
- xp:=prepsq !*f2q getv(xx,0); % start to build up the answer;
- cl:=cdr cl;
- if not (ccount=ii) then for jj:=ii+1:ccount do <<
- if getv(xx,jj) then
- xp:=list('plus,xp,
- list('times,caar cl,
- prepsq !*f2q getv(xx,jj)));
- cl:=cdr cl >>;
- xp:=list('quotient,list('minus,xp),
- prepsq !*f2q getv(xx,ii));
- if !*trint then << prin2 "Replace "; prin2 subby;
- prin2 " by "; printsq simp xp >>;
- sillieslist:=subby . sillieslist;
- return subdf(express,xp,subby)
- end;
- symbolic procedure checku(ulist,u);
- % Checks that U is not already in ULIST - ie. that this u-coefficient;
- % has not already been given a value;
- if null ulist then nil
- else if (car u) = caar ulist then t
- else checku(cdr ulist,u);
- symbolic procedure checku1(powu,rhs!*);
- %Checks that use of a particular U-term will not cause trouble;
- %by introducing negative exponents into lhs when it is used;
- begin
- top:
- if null rhs!* then return nil;
- if negind(powu,lpow rhs!*) then
- if not null evaluatecoeffts(numr lc rhs!*,powu) then return t;
- rhs!*:=red rhs!*;
- go to top
- end;
- symbolic procedure negind(pu,pr);
- %check if substituting index values in power gives rise to -ve
- % exponents;
- if null pu then nil
- else if (car pu+caar pr)<0 then t
- else negind(cdr pu,cdr pr);
- symbolic procedure evaluatecoeffts(coefft,indlist);
- % Substitutes the values of the i,j,k,...'s that appear in the S.F. ;
- % COEFFT (=coefficient of r.h.s. of reduction equation). Result is S.F.;
- if null coefft or domainp coefft then
- if coefft=0 then nil else coefft
- else begin scalar temp;
- if mvar coefft member indexlist then
- temp:=valuecoefft(mvar coefft,indlist,indexlist)
- else temp:=!*p2f lpow coefft;
- temp:=!*multf(temp,evaluatecoeffts(lc coefft,indlist));
- return addf(temp,evaluatecoeffts(red coefft,indlist))
- end;
- symbolic procedure valuecoefft(var,indvalues,indlist);
- % Finds the value of VAR, which should be in INDLIST, given INDVALUES;
- % - the corresponding values of INDLIST variables;
- if null indlist then interr "Valuecoefft - no value"
- else if var eq car indlist then
- if car indvalues=0 then nil
- else car indvalues
- else valuecoefft(var,cdr indvalues,cdr indlist);
- symbolic procedure addinds(powu,powrhs);
- % Adds indices in POWU to those in POWRHS. Result is LPOW of D.F.;
- if null powu then if null powrhs then nil
- else interr "Powrhs too long"
- else if null powrhs then interr "Powu too long"
- else (car powu + caar powrhs).addinds(cdr powu,cdr powrhs);
- symbolic procedure pickupu(rhs!*,powlhs,flg);
- % Picks up the 'lowest' U coefficient from RHS!* if it exists and
- % returns it in the form of LT of D.F..
- % Returns NIL if no legal term in RHS!* can be found.
- % POWLHS is the power we want to match (LPOW of D.F).
- % and COEFFU is the list of previous coefficients that must be zero;
- begin scalar coeffu,u;
- pt:=rhs!*;
- top:
- if null pt then return nil; %no term found - failed;
- u:=nextu(lt pt,powlhs); %check this term...;
- if null u then go to notthisone;
- if not testord(car u,lorder) then go to neverthisone;
- if not checkcoeffts(coeffu,car u) then go to notthisone;
- %that inhibited clobbering things already passed over;
- if checku(ulist,u) then go to notthisone;
- %that avoided redefining a u value;
- if checku1(car u,rhs!*) then go to neverthisone;
- %avoid introduction of negative exponents;
- if flg then
- u:=patchuptan(list u,powlhs,red pt,rhs!*);
- return u;
- neverthisone:
- coeffu:=(lc pt) . coeffu;
- notthisone:
- pt:=red pt;
- go to top
- end;
- symbolic procedure patchuptan(u,powlhs,rpt,rhs!*);
- begin
- scalar uu,cc,dd,tanlist,redu,redu1;
- pt:=rpt;
- while pt do <<
- if (uu:=pickupu(pt,powlhs,nil))
- and testord(car uu,lorder) then <<
- % Nasty found, patch it up;
- cc:=(int!-gensym1('!C).caar u).cc;
- % CC is an alist of constants;
- if !*trint then <<prin2 "***** U";
- prin2 caar u;
- prin2t " =";
- print caar cc >>;
- redu:=plusdf(redu,
- multdfconst(!*k2q caar cc,uterm(caar u,rhs!*)));
- u:=uu.u
- >>;
- if pt then pt:=red pt >>;
- redu1:=redu;
- while redu1 do begin scalar xx; xx:=car redu1;
- if !*trint then << prin2 "Introduced residue "; print xx >>;
- if (not testord(car xx,lorder)) then <<
- if !*trint then <<
- printsq cdr xx; printc " = 0" >>;
- if dd:=killsingles(cadr xx,cc) then <<
- redu:=subdf(redu,0,car dd);
- redu1:=subdf(redu1,0,car dd);
- ulist:=((cdr dd).(nil ./ 1)).ulist;
- u:=rmve(u,cdr dd);
- cc:=purgeconst(cc,dd) >>
- else redu1:=cdr redu1 >>
- else redu1:=cdr redu1 end;
- for each xx in redu do <<
- if (not testord(car xx,lorder)) then <<
- while cc do <<
- addctomap(caar cc);
- ulist:=((cdar cc).(!*k2q caar cc))
- . ulist;
- if !*statistics
- then !*number!*:=!*number!*+1;
- cc:=cdr cc >>;
- gausselimn(numr lc redu,lt redu)>> >>;
- if redu then << while cc do << addctomap(caar cc);
- ulist:=((cdar cc).(!*k2q caar cc)).ulist;
- if !*statistics then !*number!*:=!*number!*+1;
- cc:=cdr cc >>;
- lhs!*:=plusdf(lhs!*,negdf redu) >>;
- return car u
- end;
- symbolic procedure killsingles(xx,cc);
- if atom xx then nil
- else if not (cdr xx eq nil) then nil
- else begin scalar dd;
- dd:=assoc(caaar xx,cc);
- if dd then return dd;
- return killsingles(cdar xx,cc)
- end;
- symbolic procedure rmve(l,x);
- if caar l=x then cdr l else cons(car l,rmve(cdr l,x));
- symbolic procedure subdf(a,b,c);
- % SUBSTITUTE B FOR C INTO THE DF A;
- % Used to get rid of silly constants introduced;
- if a=nil then nil else
- begin scalar x;
- x:=subs2q subf(numr lc a,list (c . b)) ;
- if x=(nil . 1) then return subdf(red a,b,c)
- else return plusdf(
- list ((lpow a).((car x).!*multf(cdr x,denr lc a))),
- subdf(red a,b,c))
- end;
- symbolic procedure testord(a,b);
- % Test order of two DF's in recursive fashion;
- if null a then t
- else if car a leq car b then testord(cdr a,cdr b)
- else nil;
- symbolic procedure tanfrom(rhs!*,z,nnn);
- % We notice that in all bad cases we have (j-num)tan**j...;
- % Extract the num;
- begin scalar n,zz,r,rr;
- r:=rhs!*;
- n:=0; zz:=zlist;
- while car zz neq z do << n:=n+1; zz:=cdr zz >>;
- a: if null r then go to b;
- rr:=caar r; % The list of powers;
- for i:=1:n do rr:=cdr rr;
- if fixp caar rr then if caar rr>0 then <<
- rr:=numr cdar r;
- if null red rr then rr:=nil ./ 1
- else if fixp (rr:=quotf(red rr,lc rr))
- then rr:=-rr else rr:=0>>;
- if atom rr then go to b;
- r:=cdr r;
- go to a;
- b: if null r then return maxfrom(lhs!*,nnn)+1;
- return max(rr,maxfrom(lhs!*,nnn)+1)
- end;
- symbolic procedure coefdf(y,u);
- if y=nil then nil
- else if lpow y=u then lc y
- else coefdf(red y,u);
- symbolic procedure purgeconst(a,b);
- % Remove a const from and expression. May be the same as DELETE?;
- if null a then nil
- else if car a=b then purgeconst(cdr a,b)
- else cons(car a,purgeconst(cdr a,b));
- symbolic procedure maxorder(rhs!*,z,n);
- % Find a limit on the order of terms, theis is ad hoc;
- if null z then nil
- else if eqcar(car z,'sqrt) then
- cons(1,maxorder(rhs!*,cdr z,n+1))
- else if (atom car z) or (caar z neq 'tan) then
- cons(maxfrom(lhs!*,n)+1,maxorder(rhs!*,cdr z,n+1))
- else cons(tanfrom(rhs!*,car z,n),maxorder(rhs!*,cdr z,n+1));
- symbolic procedure maxfrom(l,n);
- % Largest order in the nth varable;
- if null l then 0
- else max(nth(caar l,n+1),maxfrom(cdr l,n));
- symbolic procedure copy u;
- if atom u then u
- else cons(copy car u,copy cdr u);
- symbolic procedure addctomap cc;
- begin
- scalar ncval;
- ccount:=ccount+1;
- ncval:=mkvect(ccount);
- for i:=0:(ccount-1) do putv(ncval,i,getv(cval,i));
- putv(ncval,ccount,nil ./ 1);
- cval:=ncval;
- cmap:=(cc . ccount).cmap;
- if !*trint then << prin2 "Constant map changed to "; print cmap >>;
- cmatrix:=mapcar(cmatrix,function addtovector);
- end;
- symbolic procedure addtovector v;
- begin scalar vv;
- vv:=mkvect(ccount);
- for i:=0:(ccount-1) do putv(vv,i,getv(v,i));
- putv(vv,ccount,nil);
- return vv
- end;
- symbolic procedure checkcoeffts(cl,indv);
- % checks to see that the coefficients in CL (coefficient list - S.Q.s);
- % are zero when the i,j,k,... are given values in INDV (LPOW of;
- % D.F.). if so the result is true else NIL=false;
- if null cl then t
- else begin scalar res;
- res:=evaluatecoeffts(numr car cl,indv);
- if not(null res or res=0) then return nil
- else return checkcoeffts(cdr cl,indv)
- end;
- symbolic procedure nextu(ltrhs,powlhs);
- % picks out the appropriate U coefficients for term: LTRHS to match the
- % powers of the z-variables given in POWLHS (= exponent list of D.F.).
- % return this coefficient in form LT of D.F. If U coefficient does
- % not exist then result is NIL. If it is multiplied by a zero then
- % result is NIL;
- if null ltrhs then nil
- else begin scalar indlist,ucoefft;
- indlist:=subtractinds(powlhs,car ltrhs,nil);
- if null indlist then return nil;
- ucoefft:=evaluatecoeffts(numr cdr ltrhs,indlist);
- if null ucoefft or ucoefft=0 then return nil;
- return indlist .* (ucoefft ./ denr cdr ltrhs)
- end;
- symbolic procedure subtractinds(powlhs,l,sofar);
- % subtract the indices in list L from those in POWLHS to find;
- % appropriate values for i,j,k,... when equating coefficients of terms;
- % on lhs of reduction eqn. SOFAR is the resulting value list we;
- % have constructed so far. if any i,j,k,... value is -ve then result;
- % is NIL;
- if null l then reversewoc sofar
- else if ((car powlhs)-(caar l))<0 then nil
- else subtractinds(cdr powlhs,cdr l,
- ((car powlhs)-(caar l)) . sofar);
- symbolic procedure gausselimn(equation,tokill);
- % Performs Gaussian elimination on the matrix for the c-equations;
- % as each c-equation is found. EQUATION is the next one to deal with;
- begin scalar newrow,pivot;
- if zerop ccount then go to noway; %failure
- newrow:=mkvect(ccount);
- spreadc(equation,newrow,1);
- subst4eliminatedcs(newrow,reverse orderofelim,reverse cmatrix);
- pivot:=findpivot newrow;
- if null pivot then go to nopivotfound;
- orderofelim:=pivot . orderofelim;
- newrow:=makeprim newrow; %remove hcf from new equation
- cmatrix:=newrow . cmatrix;
- % if !*trint then printspreadc newrow;
- return t;
- nopivotfound:
- if null getv(newrow,0) then <<
- if !*trint then printc "Already included";
- return nil>>; %equation was 0=0
- noway:
- badpart:=tokill . badpart; %non-integrable term.
- if !*trint then printc "Inconsistent";
- return nil
- end;
- symbolic procedure makeprim row;
- begin scalar g;
- g:=getv(row,0);
- for i:=1:ccount do g:=gcdf(g,getv(row,i));
- if g neq 1 then
- for i:=0:ccount do putv(row,i,quotf(getv(row,i),g));
- for i := 0:ccount do
- <<g := getv(row,i);
- if g and not domainp g
- then putv(row,i,numr resimp((rootextractf g) ./ 1))>>;
- return row
- end;
- endmodule;
- module sqrtf; % Square root of standard forms.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(!*noextend zlist);
- exports minusdfp,sqrtdf,nrootn,domainp,minusf;
- imports contentsmv,gcdf,interr,!*multf,partialdiff,printdf,quotf,
- simpsqrt2,vp2;
- symbolic procedure minusdfp a;
- % Test sign of leading coedd of d.f.
- if null a then interr "Minusdfp 0 illegal"
- else minusf numr lc a;
- symbolic procedure sqrtdf l;
- % Takes square root of distributive form. "Failed" usually means
- % that the square root is not among already existing objects.
- if null l then nil
- else begin scalar c;
- if lpow l=vp2 zlist then go to ok;
- c:=sqrtsq df2q l;
- if numr c eq 'failed
- then return 'failed;
- if denr c eq 'failed
- then return 'failed;
- return for each u in f2df numr c
- collect (car u).!*multsq(cdr u,1 ./ denr c);
- ok: c:=sqrtsq lc l;
- if numr c eq 'failed or
- denr c eq 'failed
- then return 'failed
- else return (lpow l .* c) .+nil
- end;
- symbolic procedure sqrtsq a;
- sqrtf numr a ./ sqrtf denr a;
- symbolic procedure sqrtf p;
- begin scalar ip,qp;
- if null p then return nil;
- ip:=sqrtf1 p;
- qp:=cdr ip;
- ip:=car ip; %respectable and nasty parts of the sqrt.
- if qp=1 then return ip; %exact root found.
- if !*noextend then return 'failed;
- % We cannot add new square roots in this case, since it is
- % then impossible to determine if one square root depends
- % on another if new ones are being added all the time.
- if zlistp qp then return 'failed;
- % Liouville's theorem tells you that you never need to add
- % new algebraics depending on the variable of integration.
- qp:=simpsqrt2 qp;
- return !*multf(ip,qp)
- end;
- symbolic procedure zlistp qp;
- if atom qp then member(qp,zlist)
- else or(member(mvar qp,zlist),zlistp lc qp,zlistp red qp);
- symbolic procedure sqrtf1 p;
- % Returns a . b with p=a**2*b.
- if domainp p
- then if fixp p then nrootn(p,2)
- else !*q2f simpsqrt list prepf p . 1
- else begin scalar co,pp,g,pg;
- co:=contentsmv(p,mvar p,nil); %contents of p.
- pp:=quotf(p,co); %primitive part.
- co:=sqrtf1(co); %process contents via recursion.
- g:=gcdf(pp,partialdiff(pp,mvar pp));
- pg:=quotf(pp,g);
- g:=gcdf(g,pg); %a repeated factor of pp.
- if g=1 then pg:=1 . pp
- else <<
- pg:= quotf(pp,!*multf(g,g)); %what is still left.
- pg:=sqrtf1(pg); %split that up.
- rplaca(pg,!*multf(car pg,g))>>;
- %put in the thing found here.
- rplaca(pg, !*multf(car pg,car co));
- rplacd(pg, !*multf(cdr pg,cdr co));
- return pg
- end;
- % NROOTN removed as in REDUCE base.
- endmodule;
- module tdiff; % Differentiation routines for integrator.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- exports !-!-simpdf;
- imports simpcar,kernp,diffsq,prepsq,msgpri;
- flag('(!-!-simpdf),'lose);
- symbolic procedure !-!-simpdf u;
- % U is a list of forms, the first an expression and the remainder
- % kernels and numbers.
- % Value is derivative of first form wrt rest of list.
- begin scalar v,x,y,tt;
- tt := time(); %start the clock;
- v := cdr u;
- u := simpcar u;
- a: if null v or null numr u then go to exit;
- x := if null y or y=0 then simpcar v else y;
- if null kernp x then go to e;
- x := caaaar x;
- v := cdr v;
- if null v then go to c;
- y := simpcar v;
- if null numr y then go to d
- else if not denr y=1 or not numberp numr y then go to c;
- y := car y;
- v := cdr v;
- b: if y=0 then go to a;
- u := diffsq(u,x);
- y := y-1;
- go to b;
- c: u := diffsq(u,x);
- go to a;
- d: y := nil;
- v := cdr v;
- go to a;
- exit:
- print list('time,time()-tt);
- return u;
- e: msgpri("Differentiation wrt",prepsq x,"not allowed",nil,t)
- end;
- put('tdf,'simpfn,'!-!-simpdf);
- endmodule;
- module tidysqrt; % General tidying up of square roots.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- % Modifications by J.H. Davenport.
- exports sqrt2top,tidysqrt;
- %symbolic procedure tidysqrtdf a;
- % if null a then nil
- % else begin scalar tt,r;
- % tt:=tidysqrt lc a;
- % r:=tidysqrtdf red a;
- % if null numr tt then return r;
- % return ((lpow a) .* tt) .+ r
- % end;
- %
- symbolic procedure tidysqrt q;
- begin scalar nn,dd;
- nn:=tidysqrtf numr q;
- if null nn then return nil ./ 1; %answer is zero.
- dd:=tidysqrtf denr q;
- return multsq(nn,invsq dd)
- end;
- symbolic procedure tidysqrtf p;
- %Input - standard form.
- %Output - standard quotient.
- %Simplifies sqrt(a)**n with n>1.
- if domainp p then p ./ 1
- else begin scalar v,w;
- v:=lpow p;
- if car v='i then v:=mksp('(sqrt -1),cdr v); %I->sqrt(-1);
- if eqcar(car v,'sqrt) and not onep cdr v
- then begin scalar x;
- %here we have a reduction to apply.
- x:=divide(cdr v,2); %halve exponent.
- w:=exptsq(simp cadar v,car x); %rational part of answer.
- if not zerop cdr x then w:=multsq(w,
- ((mksp(car v,1) .* 1) .+ nil) ./ 1);
- %the next line allows for the horrors of nested sqrts.
- w:=tidysqrt w
- end
- else w:=((v .* 1) .+ nil) ./ 1;
- v:=multsq(w,tidysqrtf lc p);
- return addsq(v,tidysqrtf red p)
- end;
- symbolic procedure multoutdenr q;
- % Move sqrts in a sq to the numerator.
- begin scalar n,d,root,conj;
- n:=numr q;
- d:=denr q;
- while (root:=findsquareroot d) do <<
- conj:=conjugatewrt(d,root);
- n:=!*multf(n,conj);
- d:=!*multf(d,conj) >>;
- while (root:=findnthroot d) do <<
- conj:=conjugateexpt(d,root,kord!*);
- n:=!*multf(n,conj);
- d:=!*multf(d,conj) >>;
- return (n . d);
- end;
- symbolic procedure conjugateexpt(d,root,kord!*);
- begin scalar ord,ans,repl,xi;
- ord:=caddr caddr root; % the denominator of the exponent;
- ans:=1;
- kord!*:= (xi:=gensym()) . kord!*;
- % XI is an ORD'th root of unity;
- for i:=1:ord-1 do <<
- ans:=!*multf(ans,numr subf(d,
- list(root . list('times,root,list('explt,xi,i)))));
- while (mvar ans eq xi) and ldeg ans > ord do
- ans:=addf(red ans,(xi) to (ldeg ans - ord) .* lc ans .+ nil);
- if (mvar ans eq xi) and ldeg ans = ord then
- ans:=addf(red ans,lc ans) >>;
- if (mvar ans eq xi) and ldeg ans = ord-1 then <<
- repl:=-1;
- for i:=1:ord-2 do
- repl:=(xi) to i .* -1 .+ repl;
- ans:=addf(red ans,!*multf(lc ans,repl)) >>;
- if not domainp ans and mvar ans eq xi
- then interr "Conjugation failure";
- return ans;
- end;
- symbolic procedure sqrt2top q;
- begin
- scalar n,d;
- n:=multoutdenr q;
- d:=denr n;
- n:=numr n;
- if d eq denr q
- then return q;%no change.
- if d iequal 1
- then return (n ./ 1);
- q:=gcdcoeffsofsqrts n;
- if q iequal 1
- then if minusf d
- then return (negf n ./ negf d)
- else return (n ./ d);
- q:=gcdf(q,d);
- n:=quotf(n,q);
- d:=quotf(d,q);
- if minusf d
- then return (negf n ./ negf d)
- else return (n ./ d)
- end;
- %symbolic procedure denrsqrt2top q;
- %begin
- % scalar n,d;
- % n:=multoutdenr q;
- % d:=denr n;
- % n:=numr n;
- % if d eq denr q
- % then return d; % no changes;
- % if d iequal 1
- % then return 1;
- % q:=gcdcoeffsofsqrts n;
- % if q iequal 1
- % then return d;
- % q:=gcdf(q,d);
- % if q iequal 1
- % then return d
- % else return quotf(d,q)
- % end;
- symbolic procedure findsquareroot p;
- % Locate a sqrt symbol in poly p.
- if domainp p then nil
- else begin scalar w;
- w:=mvar p; %check main var first.
- if atom w
- then return nil; %we have passed all sqrts.
- if eqcar(w,'sqrt) then return w;
- w:=findsquareroot lc p;
- if null w then w:=findsquareroot red p;
- return w
- end;
- symbolic procedure findnthroot p;
- nil; % Until corrected.
- symbolic procedure x!-findnthroot p;
- % Locate an n-th root symbol in poly p.
- if domainp p then nil
- else begin scalar w;
- w:=mvar p; %check main var first.
- if atom w
- then return nil; %we have passed all sqrts.
- if eqcar(w,'expt) and eqcar(caddr w,'quotient) then return w;
- w:=findnthroot lc p;
- if null w then w:=findnthroot red p;
- return w
- end;
- symbolic procedure conjugatewrt(p,var);
- % Var -> -var in form p.
- if domainp p then p
- else if mvar p=var then begin
- scalar x,c,r;
- x:=tdeg lt p; %degree
- c:=lc p; %coefficient
- r:=red p; %reductum
- x:=remainder(x,2); %now just 0 or 1.
- if x=1 then c:=negf c; %-coefficient.
- return (lpow p .* c) .+ conjugatewrt(r,var) end
- else if ordop(var,mvar p) then p
- else (lpow p .* conjugatewrt(lc p,var)) .+
- conjugatewrt(red p,var);
- symbolic procedure gcdcoeffsofsqrts u;
- if atom u
- then if numberp u and minusp u
- then -u
- else u
- else if eqcar(mvar u,'sqrt)
- then begin
- scalar v;
- v:=gcdcoeffsofsqrts lc u;
- if v iequal 1
- then return v
- else return gcdf(v,gcdcoeffsofsqrts red u)
- end
- else begin
- scalar root;
- root:=findsquareroot u;
- if null root
- then return u;
- u:=makemainvar(u,root);
- root:=gcdcoeffsofsqrts lc u;
- if root iequal 1
- then return 1
- else return gcdf(root,gcdcoeffsofsqrts red u)
- end;
- endmodule;
- module trcase; % Driving routine for integration of transcendental fns.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- % Modifications by: John P. Fitch.
- fluid '(!*backtrace
- !*nowarnings
- !*purerisch
- !*reverse
- badpart
- ccount
- cmap
- cmatrix
- content
- cuberootflag
- cval
- denbad
- denominator
- indexlist
- lhs!*
- loglist
- lorder
- orderofelim
- rhs!*
- sillieslist
- sqfr
- sqrtflag
- sqrtlist
- tanlist
- svar
- varlist
- xlogs
- zlist);
- % !*reverse: flag to re-order zlist.
- % !*nowarnings: flag to lose messages.
- global '(!*failhard
- !*number!*
- !*ratintspecial
- !*seplogs
- !*spsize!*
- !*statistics
- !*trint
- gensymcount);
- switch failhard;
- exports transcendentalcase;
- imports backsubst4cs,countz,createcmap,createindices,df2q,dfnumr,
- difflogs,fsdf,factorlistlist,findsqrts,findtrialdivs,gcdf,mkvect,
- interr,logstosq,mergin,multbyarbpowers,!*multf,multsqfree,
- printdf,printsq,quotf,rationalintegrate,putv,
- simpint1,solve!-for!-u,sqfree,sqmerge,sqrt2top,substinulist,trialdiv,
- mergein,negsq,addsq,f2df,mknill,pnth,invsq,multsq,domainp,mk!*sq,
- mksp,prettyprint,prepsq;
- % Note that SEPLOGS keeps logarithmic part of result together as a
- % kernel form, but this can lead to quite messy results.
- symbolic
- procedure transcendentalcase(integrand,svar,xlogs,zlist,varlist);
- begin scalar divlist,jhd!-content,content,prim,sqfr,dfu,indexlist,
- % JHD!-CONTENT is local, while CONTENT is free (set in SQFREE).
- sillieslist,originalorder,wrongway,
- sqrtlist,tanlist,loglist,dflogs,eprim,dfun,unintegrand,
- sqrtflag,badpart,rhs!*,lhs!*,gcdq,cmap,cval,orderofelim,cmatrix;
- scalar cuberootflag,ccount,denominator,result,denbad;
- gensymcount:=0;
- integrand:=sqrt2top integrand; % Move the sqrts to the numerator.
- if !*trint then << printc "Extension variables z<i> are";
- print zlist>>;
- if !*ratintspecial and null cdr zlist then
- return rationalintegrate(integrand,svar);
- % *** now unnormalize integrand, maybe ***.
- begin scalar w,gg;
- gg:=1;
- foreach z in zlist do <<
- w:=subs2 diffsq(simp z,svar);
- gg:=!*multf(gg,quotf(denr w,gcdf(denr w,gg))) >>;
- gg:=quotf(gg,gcdf(gg,denr integrand));
- unintegrand:=(!*multf(gg,numr integrand)
- ./ !*multf(gg,denr integrand));
- if !*trint then <<
- printc "Unnormalized integrand =";
- printsq unintegrand >> end;
- divlist:=findtrialdivs zlist;
- %also puts some things on loglist sometimes.
- % if !*trint
- % then << printc "Exponentials and tans to try dividing:";
- % print divlist>>;
- sqrtlist:=findsqrts zlist;
- % if !*trint then << printc "Square-root z-variables";
- % print sqrtlist >>;
- divlist:=trialdiv(denr unintegrand,divlist);
- % if !*trint then << printc "Divisors:";
- % print car divlist;
- % print cdr divlist>>;
- %n.b. the next line also sets 'content' as a free variable.
- % Since SQFREE may be used later, we copy it into JHD!-CONTENT.
- prim:=sqfree(cdr divlist,zlist);
- jhd!-content:=content;
- printfactors(prim,nil);
- eprim:=sqmerge(countz car divlist,prim,nil);
- printfactors(eprim,t);
- % if !*trint then << terpri();
- % printsf denominator;
- % terpri();
- % printc "...content is:";
- % printsf jhd!-content>>;
- sqfr:=for each u in eprim collect multup u;
- % sqfr:=multsqfree eprim;
- % if !*trint then << printc "...sqfr is:";
- % superprint sqfr>>;
- if !*reverse then zlist:=reverse zlist; %ALTER ORDER FUNCTION;
- indexlist:=createindices zlist;
- % if !*trint then << printc "...indices are:";
- % superprint indexlist>>;
- dfu:=dfnumr(svar,car divlist);
- % if !*trint then << terpri();
- % printc "************ Derivative of u is:";
- % printsq dfu>>;
- loglist:=append(loglist,factorlistlist (prim,nil));
- loglist:=mergein(xlogs,loglist);
- loglist:=mergein(tanlist,loglist);
- cmap:=createcmap();
- ccount:=length cmap;
- if !*trint then << printc "Loglist ";
- print loglist >>;
- dflogs:=difflogs(loglist,denr unintegrand,svar);
- if !*trint then << printc "************ 'Derivative' of logs is:";
- printsq dflogs>>;
- dflogs:=addsq((numr unintegrand) ./ 1,negsq dflogs);
- % Put everything in reduction eqn over common denominator.
- gcdq:=gcdf(denr dflogs,denr dfu);
- dfun:= !*multf(numr dfu,
- denbad:=quotf(denr dflogs,gcdq));
- denbad:=!*multf(denr dfu,denbad);
- denbad:= !*multf(denr unintegrand,denbad);
- dflogs:= !*multf(numr dflogs,quotf(denr dfu,gcdq));
- dfu:=dfun;
- % Now DFU and DFLOGS are S.F.s.
- rhs!*:=multbyarbpowers f2df dfu;
- if checkdffail(rhs!*,svar) then interr "Simplification failure";
- if !*trint then << printc "Distributed Form of U is:";
- printdf rhs!*>>;
- lhs!*:=f2df dflogs;
- if checkdffail(lhs!*,svar) then interr "Simplification failure";
- if !*trint then << printc "Distributed Form of l.h.s. is:";
- printdf lhs!*;
- terpri()>>;
- cval:=mkvect(ccount);
- for i:=0 : ccount do putv(cval,i,nil ./ 1);
- lorder:=maxorder(rhs!*,zlist,0);
- originalorder:=lorder;
- if !*trint then << printc "Maximum order determined as ";
- print lorder >>;
- if !*statistics then << !*number!*:=0;
- !*spsize!*:=1;
- foreach xx in lorder do
- !*spsize!*:=!*spsize!* * (xx+1) >>;
- % That calculates the largest U that can appear.
- dfun:=solve!-for!-u(rhs!*,lhs!*,nil);
- backsubst4cs(nil,orderofelim,cmatrix);
- % if !*trint then if not (ccount=0) then printvecsq cval;
- if !*statistics then << prin2 !*number!*; prin2 " used out of ";
- printc !*spsize!* >>;
- badpart:=substinulist badpart;
- %substitute for c<i> still in badpart.
- dfun:=df2q substinulist dfun;
- % if !*trint then superprint dfun;
- result:= !*multsq(dfun,!*invsq(denominator ./ 1));
- result:= !*multsq(result,!*invsq(jhd!-content ./ 1));
- % if !*trint then superprint result;
- dflogs:=logstosq();
- if not null numr dflogs then <<
- if !*seplogs and (not domainp numr result) then <<
- result:=mk!*sq result;
- result:=(mksp(result,1) .* 1) .+ nil;
- result:=result ./ 1 >>;
- result:=addsq(result,dflogs)>>;
- if !*trint then << superprint result;
- terpri();
- printc
- "*****************************************************";
- printc
- "************ THE INTEGRAL IS : **********************";
- printc
- "*****************************************************";
- terpri();
- printsq result;
- terpri()>>;
- if not null badpart then <<
- if !*trint then printc "plus a bad part";
- lhs!*:=badpart;
- lorder:=maxorder(rhs!*,zlist,0);
- while lorder do <<
- if car lorder > car originalorder then
- wrongway:=t;
- lorder:=cdr lorder;
- originalorder:=cdr originalorder >>;
- dfun:=df2q badpart;
- if !*trint
- then <<printsq dfun; printc "Denbad = "; printsf denbad>>;
- dfun:= !*multsq(dfun,invsq(denbad ./ 1));
- if wrongway then << result:= nil ./ 1; dfun:=integrand >>;
- if rootcheckp(unintegrand,svar) then
- return simpint1(integrand . svar.nil)
- else if !*purerisch or allowedfns zlist then
- dfun:=simpint1 (dfun . svar.nil)
- else << !*purerisch:=t;
- if !*trint
- then <<printc " [Transforming ..."; printsq dfun>>;
- denbad:=transform(dfun,svar);
- if denbad=dfun
- then dfun:=simpint1(dfun . svar.nil)
- else <<denbad:=errorset('(integratesq denbad svar xlogs),
- !*backtrace,!*backtrace);
- if not atom denbad then dfun:=untan car denbad
- else dfun:=simpint1(dfun . svar.nil) >> >>;
- if !*trint then printsq dfun;
- if !*failhard then rederr "FAILHARD switch set";
- if !*seplogs and not domainp result then <<
- result:=mk!*sq result;
- if not numberp result
- then result:=(mksp(result,1) .* 1) .+ nil;
- result:=result ./ 1>>;
- result:=addsq(result,dfun) >>;
- % if !*overlaymode then excise transcode;
- return sqrt2top result
- end;
- symbolic procedure checkdffail(u,v);
- u and (depends(lc u,v) or checkdffail(red u,v));
- symbolic procedure printfactors(w,prdenom);
- % W is a list of factors to each power. If PRDENOM is true
- % this prints denominator of answer, else prints square-free
- % decomposition.
- begin scalar i,wx;
- i:=1;
- if prdenom then <<
- denominator:=1;
- if !*trint
- then printc "Denominator of 1st part of answer is:";
- if not null w then w:=cdr w >>;
- loopx: if w=nil then return;
- if !*trint then <<prin2 "Factors of multiplicity "; print i>>;
- wx:=car w;
- while not null wx do <<
- if !*trint then printsf car wx;
- for j:=1 : i do
- denominator:= !*multf(car wx,denominator);
- wx:=cdr wx >>;
- i:=i+1;
- w:=cdr w;
- go to loopx
- end;
- % unfluid '(dfun svar xlogs);
- endmodule;
- module halfangle; % Routines for conversion to half angle tangents.
- % Author: Steve Harrington.
- % Modifications by: John P. Fitch.
- fluid '(!*gcd);
- exports halfangle,untan;
- symbolic procedure transform(u,x);
- % Transform the SQ U to remove the 'bad' functions sin, cos, cot etc
- % in favor of half angles;
- halfangle(u,x);
- symbolic procedure quotqq(u1,v1);
- multsq(u1, invsq(v1));
- symbolic procedure !*subtrq(u1,v1);
- addsq(u1, negsq(v1));
- symbolic procedure !*int2qm(u1);
- if u1=0 then nil . 1 else u1 . 1;
- symbolic procedure halfangle(r,x);
- % Top level procedure for converting;
- % R is a rational expression to be converted,
- % X the integration variable.
- % A rational expression is returned.
- quotqq(hfaglf(numr(r),x), hfaglf(denr(r),x));
- symbolic procedure hfaglf(p,x);
- % Converting polynomials, a rational expression is returned.
- if domainp(p) then !*f2q(p)
- else subs2q addsq(multsq(exptsq(hfaglk(mvar(p),x), ldeg(p)),
- hfaglf(lc(p),x)),
- hfaglf(red(p),x));
- symbolic procedure hfaglk(k,x);
- % Converting kernels, a rational expression is returned.
- begin
- scalar kt;
- if atom k or not member(x,flatten(cdr(k))) then return !*k2q k;
- k := car(k) . hfaglargs(cdr(k), x);
- kt := simp list('tan, list('quotient, cadr(k), 2));
- return if car(k) = 'sin
- then quotqq(multsq(!*int2qm(2),kt), addsq(!*int2qm(1),
- exptsq(kt,2)))
- else if car(k) = 'cos
- then quotqq(!*subtrq(!*int2qm(1),exptsq(kt,2)),addsq(!*int2qm(1),
- exptsq(kt,2)))
- else if car(k) = 'tan
- then quotqq(multsq(!*int2qm(2),kt), !*subtrq(!*int2qm(1),
- exptsq(kt,2)))
- else if car(k) = 'sinh then
- quotqq(!*subtrq(exptsq(!*k2q('expt.('e. cdr k)),2),
- !*int2qm(1)), multsq(!*int2qm(2), !*k2q('expt . ('e . cdr(k)))))
- else if car(k) = 'cosh then
- quotqq(addsq(exptsq(!*k2q('expt.('e. cdr k)),2),
- !*int2qm(1)), multsq(!*int2qm(2), !*k2q('expt . ('e . cdr(k)))))
- else if car(k) = 'tanh then
- quotqq(!*subtrq(exptsq(!*k2q('expt.('e. cdr k)),2),
- !*int2qm(1)), addsq(exptsq(!*k2q ('expt.('e.cdr(k))),2),
- !*int2qm(1)))
- else !*k2q(k); % additional transformation might be added here.
- end;
- symbolic procedure hfaglargs(l,x);
- % Conversion of argument list.
- if null l then nil
- else prepsq(hfaglk(car(l),x)) . hfaglargs(cdr(l), x);
- symbolic procedure untanf x;
- % This should be done by a table.
- begin scalar y,z,w;
- if domainp x then return x . 1;
- y := mvar x;
- if eqcar(y,'int) then error1(); % assume all is hopeless.
- z := ldeg x;
- w := 1 . 1;
- y :=
- if atom y then !*k2q y
- else if car y eq 'tan
- then if evenp z
- then <<z := z/2;
- simp list('quotient,
- list('plus,
- list('minus,
- list('cos,
- 'times
- . (2 . cdr y))),
- 1),list('plus,
- list('cos,
- 'times
- . (2 . cdr y)),
- 1))>>
- else if z=1
- then simp list('quotient,
- list('plus,
- list('minus,
- list('cos,
- 'times . (2 . cdr y))),
- 1),list('sin,
- 'times . (2 . cdr y)))
- else <<z := (z - 1)/2;
- w :=
- simp list('quotient,
- list('plus,
- list('minus,
- list('cos,
- 'times
- . (2 . cdr y))),
- 1),list('sin,
- 'times
- . (2 . cdr y)));
- simp list('quotient,
- list('plus,
- list('minus,
- list('cos,
- 'times
- . (2 . cdr y))),
- 1),list('plus,
- list('cos,
- 'times
- . (2 . cdr y)),
- 1))>>
- else simp y;
- return addsq(multsq(multsq(exptsq(y,z),untanf lc x),w),
- untanf red x)
- end;
- symbolic procedure untanlist(y);
- if null y then nil
- else (prepsq (untan(simp car y)) . untanlist(cdr y));
- symbolic procedure untan(x);
- % Expects x to be canonical quotient.
- begin scalar y;
- y:=cossqchk sinsqrdchk multsq(untanf(numr x),
- invsq untanf(denr x));
- return if length flatten y>length flatten x then x else y
- end;
- symbolic procedure sinsqrdchk(x);
- multsq(sinsqchkf(numr x), invsq sinsqchkf(denr x));
- symbolic procedure sinsqchkf(x);
- begin
- scalar y,z,w;
- if domainp x then return x . 1;
- y := mvar x;
- z := ldeg x;
- w := 1 . 1;
- y := if eqcar(y,'sin) then if evenp z
- then <<z := quotient(z,2);
- simp list('plus,1,list('minus,
- list('expt,('cos . cdr(y)),2)))>>
- else if z = 1 then !*k2q y
- else << z := quotient(difference(z,1),2); w := !*k2q y;
- simp list('plus,1,list('minus,
- list('expt,('cos . cdr(y)),2)))>>
- else !*k2q y;
- return addsq(multsq(multsq(exptsq(y,z),sinsqchkf(lc x)),w),
- sinsqchkf(red x));
- end;
- symbolic procedure cossqchkf(x);
- begin
- scalar y,z,w,x1,x2;
- if domainp x then return x . 1;
- y := mvar x;
- z := ldeg x;
- w := 1 . 1;
- x1 := cossqchkf(lc x);
- x2 := cossqchkf(red x);
- x := addsq(multsq(!*p2q lpow x,x1),x2);
- y := if eqcar(y,'cos) then if evenp z
- then <<z := quotient(z,2);
- simp list('plus,1,list('minus,
- list('expt,('sin . cdr(y)),2)))>>
- else if z = 1 then !*k2q y
- else << z := quotient(difference(z,1),2); w := !*k2q y;
- simp list('plus,1,list('minus,
- list('expt,('sin . cdr(y)),2)))>>
- else !*k2q y;
- y := addsq(multsq(multsq(exptsq(y,z),w),x1),x2);
- return if length(y) > length(x) then x else y;
- end;
- symbolic procedure cossqchk(x);
- begin scalar !*gcd;
- !*gcd := t;
- return multsq(cossqchkf(numr x), invsq cossqchkf(denr x))
- end;
- symbolic procedure lrootchk(l,x);
- % Checks each member of list l for a root.
- if null l then nil else krootchk(car l, x) or lrootchk(cdr l, x);
- symbolic procedure krootchk(f,x);
- % Checks a kernel to see if it is a root.
- if atom f then nil
- else if car(f) = 'sqrt and member(x, flatten cdr f) then t
- else if car(f) = 'expt
- and not atom caddr(f)
- and caaddr(f) = 'quotient
- and member(x, flatten cadr f) then t
- else lrootchk(cdr f, x);
- symbolic procedure rootchk1p(f,x);
- % Checks polynomial for a root.
- if domainp f then nil
- else krootchk(mvar f,x) or rootchk1p(lc f,x) or rootchk1p(red f,x);
- symbolic procedure rootcheckp(f,x);
- % Checks rational (standard quotient) for a root.
- rootchk1p(numr f,x) or rootchk1p(denr f,x);
- endmodule;
- module trialdiv; % Trial division routines.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(denominator loglist tanlist);
- global '(!*trint);
- exports countz,findsqrts,findtrialdivs,trialdiv,simp,mksp;
- imports !*multf,printsf,quotf;
- symbolic procedure countz dl;
- % DL is a list of S.F.s;
- begin scalar s,n,rl;
- loop2: if null dl then return arrangelistz rl;
- n:=1;
- loop1: n:=n+1;
- s:=car dl;
- dl:=cdr dl;
- if not null dl and (s eq car dl) then
- go to loop1
- else rl:=(s.n).rl;
- go to loop2
- end;
- symbolic procedure arrangelistz d;
- begin scalar n,s,rl,r;
- n:=1;
- if null d then return rl;
- loopd: if (cdar d)=n then s:=(caar d).s
- else r:=(car d).r;
- d:=cdr d;
- if not null d then go to loopd;
- d:=r;
- rl:=s.rl;
- s:=nil;
- r:=nil;
- n:=n+1;
- if not null d then go to loopd;
- return reversewoc rl
- end;
- symbolic procedure findtrialdivs zl;
- %zl is list of kernels found in integrand. result is a list
- %giving things to be treated specially in the integration
- %viz: exps and tans.
- %Result is list of form ((a . b) ...)
- % with a a kernel and car a=expt or tan
- % and b a standard form for either expt or (1+tan**2).
- begin scalar dlists1,args1;
- while not null zl do <<
- if exportan car zl then <<
- if caar zl='tan
- then << args1:=(mksp(car zl,2) .* 1) .+ 1;
- tanlist:=(args1 ./ 1) . tanlist>>
- else args1:=!*k2f car zl;
- dlists1:=(car zl . args1) . dlists1>>;
- zl:=cdr zl >>;
- return dlists1
- end;
- symbolic procedure exportan dl;
- if atom dl then nil
- else begin
- % extract exp or tan fns from the z-list.
- if eq(car dl,'tan) then return t;
- nxt: if not eq(car dl,'expt) then return nil;
- dl:=cadr dl;
- if atom dl then return t;
- % Make sure we find nested exponentials?
- go to nxt
- end;
- symbolic procedure findsqrts z;
- begin scalar r;
- while not null z do <<
- if eqcar(car z,'sqrt) then r:=(car z) . r;
- z:=cdr z >>;
- return r
- end;
- symbolic procedure trialdiv(x,dl);
- begin scalar qlist,q;
- while not null dl do
- if not null(q:=quotf(x,cdar dl)) then <<
- if (caaar dl='tan) and not eqcar(qlist,cdar dl) then
- loglist:=('iden . simp cadr caar dl) . loglist;
- %tan fiddle!
- qlist:=(cdar dl).qlist;
- x:=q >>
- else dl:=cdr dl;
- return qlist.x
- end;
- endmodule;
- module unifac; % Univariate factorization for integration.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(knowndiscrimsign zlist);
- global '(!*trint);
- exports unifac;
- imports cubic,linfac,printdf,quadfac,quadratic,quartic,vp1,
- gcd,minusp,prettyprint;
- symbolic procedure unifac(pol,var,degree,res);
- begin scalar w,q,c;
- w:=pol;
- if !*trint then superprint w;
- %now try looking for linear factors.
- trylin: q:=linfac(w);
- if null car q then go to nomorelin;
- res := ('log . back2df(car q,var)) . res;
- w:=cdr q;
- go to trylin;
- nomorelin:
- q:=quadfac(w);
- if null car q then go to nomorequad;
- res := quadratic(back2df(car q,var),var,res);
- w:=cdr q;
- go to nomorelin;
- nomorequad:
- if null w then return res; %all done.
- degree:=car w; %degree of what is left.
- c:=back2df(w,var);
- if degree=3 then res:=cubic(c,var,res)
- else if degree=4 then res:=quartic(c,var,res)
- else if evenp degree and
- pairp (q := halfpower cddr w)
- then <<w := (degree/2) . (cadr w . q);
- w := unifac(w,var,car w,nil);
- res := pluckfactors(w,var,res)>>
- else <<
- printc "The following has not been split";
- printdf c;
- res:=('log . c) . res>>;
- return res
- end;
- symbolic procedure halfpower w;
- if null w then nil
- else if car w=0
- then (lambda r;
- if r eq 'failed then r else cadr w . r) halfpower cddr w
- else 'failed;
- symbolic procedure pluckfactors(w,var,res);
- begin scalar p,q,knowndiscrimsign;
- while w do
- <<p := car w;
- if car p eq 'atan then nil
- else if car p eq 'log
- then <<q := doublepower cdr p . q;
- %prin2 "q="; %printdf car q;
- >>
- else interr "Bad form";
- w := cdr w>>;
- while q do
- <<p := car q;
- if caaar p=4
- then <<knowndiscrimsign := 'negative;
- res := quartic(p,var,res);
- knowndiscrimsign := nil>>
- else if caaar p=2
- then res := quadratic(p,var,res)
- else res := ('log . p) . res;
- q := cdr q>>;
- return res
- end;
- symbolic procedure doublepower r;
- if null r then nil
- else ((for each j in caar r collect 2*j) . cdar r)
- . doublepower cdr r;
- symbolic procedure back2df(p,v);
- % Undo the effect of uniform.
- begin scalar r,n;
- n:=car p;
- p:=cdr p;
- while not minusp n do <<
- if not zerop car p then r:=
- (vp1(v,n,zlist) .* (car p ./ 1)) .+ r;
- p:=cdr p;
- n:=n-1 >>;
- return reversewoc r
- end;
- endmodule;
- module uniform; % Convert from D.F. to list of coefficients.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(zlist);
- exports uniform;
- imports exponentof;
- symbolic procedure uniform(p,v);
- %Convert from d.f. in one variable (v) to a simple list of
- %coeffs (with degree consed onto front).
- %Fails if coefficients are not all simple integers.
- if null p then 0 . (0 . nil)
- else begin scalar a,b,c,d;
- a:=exponentof(v,lpow p,zlist);
- b:=lc p;
- if not(denr b=1) then return 'failed;
- b:=numr b;
- if null b then b:=0
- else if not numberp b then return 'failed;
- if a=0 then return a . (b . nil); %constant term.
- c:=uniform(red p,v);
- if c='failed then return 'failed;
- d:=car c;
- c:=cdr c;
- d:=d+1;
- while not (a=d) do <<
- c:=0 . c;
- d:=d+1>>;
- return a . (b . c)
- end;
- endmodule;
- module makevars; % Make dummy variables for integration process.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- fluid '(!*gensymlist!* !*purerisch);
- exports getvariables,varsinlist,varsinsq,varsinsf,findzvars,
- createindices,mergein;
- imports dependsp,union;
- % Note that 'i' is already maybe committed for sqrt(-1),
- % also 'l' and 'o' are not used as they print badly on certain
- % terminals etc and may lead to confusion.
- !*gensymlist!* := '(! j ! k ! m ! n ! p ! q ! r ! s ! t ! u ! v ! w ! x
- ! y ! z);
- %mapc(!*gensymlist!*,function remob); %REMOB protection;
- symbolic procedure varsinlist(l,vl);
- % L is a list of s.q. - find all variables mentioned,
- % given thal vl is a list already known about.
- begin while not null l do <<
- vl:=varsinsf(numr car l,varsinsf(denr car l,vl));
- l:=cdr l >>;
- return vl
- end;
- symbolic procedure getvariables sq;
- varsinsf(numr sq,varsinsf(denr sq,nil));
- symbolic procedure varsinsq(sq,vl);
- varsinsf(numr sq,varsinsf(denr sq,vl));
- symbolic procedure varsinsf(form,l);
- if domainp form then l
- else begin
- while not domainp form do <<
- l:=varsinsf(lc form,union(l,list mvar form));
- form:=red form >>;
- return l
- end;
- symbolic procedure findzvars(vl,zl,var,flg);
- begin scalar v;
- % VL is the crude list of variables found in the original integrand;
- % ZL must have merged into it all EXP, LOG etc terms from this.
- % If FLG is true then ignore DF as a function.
- scan: if null vl then return zl;
- v:=car vl; % next variable.
- vl:=cdr vl;
- % at present items get put onto ZL if they are non-atomic
- % and they depend on the main variable. The arguments of
- % functions are decomposed by recursive calls to findzvar.
- %give up if V has been declared dependent on other things;
- if atom v and v neq var and depends(v,var) then
- rederr "Can't integrate in the presence of side-relations"
- else if not atom v and (not v member zl) and dependsp(v,var)
- then if car v='!*sq then zl:=findzvarssq(cadr v,zl,var)
- else if car v memq '(times quotient plus minus difference int)
- or (((car v) eq 'expt) and fixp caddr v)
- then
- zl:=findzvars(cdr v,zl,var,flg)
- else if flg and car v eq 'df
- then <<!*purerisch := t; return zl>> % try and stop it
- else zl:=v . findzvars(cdr v,zl,var,flg);
- % scan arguments of fn.
- %ACH: old code used to look only at CADR if a DF involved.
- go to scan
- end;
- symbolic procedure findzvarssq(sq,zl,var);
- findzvarsf(numr sq,findzvarsf(denr sq,zl,var),var);
- symbolic procedure findzvarsf(sf,zl,var);
- if domainp sf then zl
- else findzvarsf(lc sf,
- findzvarsf(red sf,
- findzvars(list mvar sf,zl,var,nil),
- var),
- var);
- symbolic procedure createindices zl;
- % Produces a list of unique indices, each associated with a ;
- % different Z-variable;
- reversewoc crindex1(zl,!*gensymlist!*);
-
- symbolic procedure crindex1(zl,gl);
- begin if null zl then return nil;
- if null gl then << gl:=list int!-gensym1 'i; %new symbol needed;
- nconc(!*gensymlist!*,gl) >>;
- return (car gl) . crindex1(cdr zl,cdr gl) end;
- symbolic procedure rmember(a,b);
- if null b then nil
- else if a=cdar b then car b
- else rmember(a,cdr b);
- symbolic procedure mergein(dl,ll);
- % Adjoin logs of things in dl to existing list ll.
- if null dl then ll
- else if rmember(car dl,ll) then mergein(cdr dl,ll)
- else mergein(cdr dl,('log . car dl) . ll);
- endmodule;
- module vect; % Vector support routines.
- % Authors: Mary Ann Moore and Arthur C. Norman.
- % Modified by: James H. Davenport.
- exports mkuniquevect,mkvec,mkvecf2q,mkidenm,copyvec,vecsort,swap,
- non!-null!-vec,mkvect2;
- symbolic procedure mkuniquevect v;
- begin scalar u,n;
- n:=upbv v;
- for i:=0:n do begin
- scalar uu;
- uu:=getv(v,i);
- if not (uu member u)
- then u:=uu.u
- end;
- return mkvec u
- end;
- symbolic procedure mkvec(l);
- begin scalar v,i;
- v:=mkvect(isub1 length l);
- i:=0;
- while l do <<putv(v,i,car l); i:=iadd1 i; l:=cdr l>>;
- return v
- end;
- symbolic procedure mkvecf2q(l);
- begin
- scalar v,i,ll;
- v:=mkvect(isub1 length l);
- i:=0;
- while l do <<
- ll:=car l;
- if ll = 0 then ll:=nil;
- putv(v,i,!*f2q ll);
- i:=iadd1 i;
- l:=cdr l >>;
- return v
- end;
- symbolic procedure mkidenm n;
- begin
- scalar ans,u;
- scalar c0,c1;
- c0:=nil ./ 1;
- c1:= 1 ./ 1;
- % constants.
- ans:=mkvect(n);
- for i:=0 step 1 until n do <<
- u:=mkvect n;
- for j:=0 step 1 until n do
- if i iequal j
- then putv(u,j,c1)
- else putv(u,j,c0);
- putv(ans,i,u) >>;
- return ans
- end;
- symbolic procedure copyvec(v,n);
- begin scalar new;
- new:=mkvect(n);
- for i:=0:n do putv(new,i,getv(v,i));
- return new
- end;
- symbolic procedure vecsort(u,l);
- % Sorts vector v of numbers into decreasing order.
- % Performs same interchanges of all vectors in the list l.
- begin
- scalar j,k,n,v,w;
- n:=upbv u;% elements 0...n exist.
- % algorithm used is a bubble sort.
- for i:=1:n do begin
- v:=getv(u,i);
- k:=i;
- loop:
- j:=k;
- k:=isub1 k;
- w:=getv(u,k);
- if v<=w
- then goto ordered;
- putv(u,k,v);
- putv(u,j,w);
- mapc(l,function (lambda u;swap(u,j,k)));
- if k>0
- then goto loop;
- ordered:
- end;
- return nil
- end;
- symbolic procedure swap(u,j,k);
- if null u
- then nil
- else begin
- scalar v;
- %swaps elements i,j of vector u.
- v:=getv(u,j);
- putv(u,j,getv(u,k));
- putv(u,k,v)
- end;
- symbolic procedure non!-null!-vec v;
- begin
- scalar cnt;
- cnt := 0;
- for i:=0:upbv v do
- if getv(v,i)
- then cnt:=iadd1 cnt;
- return cnt
- end;
- symbolic procedure mkvect2(n,initial);
- begin
- scalar u;
- u:=mkvect n;
- for i:=0:n do
- putv(u,i,initial);
- return u
- end;
- endmodule;
- end;
|