crack.red 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199
  1. comment
  2. Title: CRACK
  3. Authors:
  4. Andreas Brand
  5. Institut fuer Angewandte und Technische Informatik
  6. Friedrich Schiller Universitaet Jena
  7. 07740 Jena, Germany
  8. email: maa@hpux.rz.uni-jena.de
  9. tel.: + 49 3641 630790 ,
  10. Thomas Wolf
  11. School of Mathematical Sciences
  12. Queen Mary and Westfield College
  13. University of London
  14. London E1 4NS
  15. email: T.Wolf@maths.qmw.ac.uk
  16. tel.: + 44 71 975 5493
  17. Date of release: 25 August 93
  18. Abstract:
  19. CRACK is a package for solving overdetermined systems of partial or
  20. ordinary differential equations (PDEs, ODEs). Examples of programs
  21. which make use of CRACK for investigating ODEs (finding symmetries,
  22. first integrals, an equivalent Lagrangian or a "differential
  23. factorization") are added. The manual CRACKMAN gives further details.
  24. REDUCE version: 3.4.
  25. CRACK uses the package ODESOLVE of Malcolm MacCallum which is included
  26. in REDUCE 3.4.
  27. T. Wolf, An Analytic Algorithm for Decoupling and Integrating
  28. systems of Nonlinear Partial Differential Equations, J. Comp.
  29. Phys., no. 3, 60 (1985) 437-446.
  30. T. Wolf, The Symbolic Integration of Exact PDEs, preprint.
  31. M.A.H. MacCallum, An Ordinary Differential Equation Solver for REDUCE,
  32. Proc. ISAAC'88, Springer Lect. Notes in Comp Sci. 358,
  33. 196--205.
  34. Keywords: partial differential equations, computer analytic
  35. $
  36. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  37. % %
  38. % CRACK Version 25 Aug. 93 %
  39. % %
  40. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  41. %**********************************************************************
  42. module crackstar$
  43. %**********************************************************************
  44. % Main program
  45. % Author: Andreas Brand
  46. % 1991,1993
  47. symbolic fluid '(REDUCEFUNCTIONS_ cont_ odesolve_ fcteval_ print_
  48. logoprint_ sp_cases independence_ tr_gensep decouple_
  49. tr_genint contradiction_ poly_only fname_ factorize_ nfct_
  50. fnew_ special_cases genint_ ineq_ time_)$
  51. symbolic operator setcrackflags$
  52. symbolic procedure setcrackflags$
  53. <<REDUCEFUNCTIONS_:= '(ABS ACOS ACOSD ACOSH ACOT ACOTD ACOTH ACSC ACSCD
  54. ACSCH ASEC ASECD ASECH ASIN ASIND ASINH ATAN
  55. ATAND ATANH ATAN2 ATAN2D CBRT COS COSD COSH COT
  56. COTD COTH CSC CSCD CSCH EXP FACTORIAL HYPOT LN
  57. LOG LOGB LOG10 SEC SECD SECH SIN SIND SINH SQRT
  58. TAN TAND TANH PLUS DIFFERENCE DF MINUS TIMES
  59. QUOTIENT EXPT INT)$
  60. if not fixp nfct_ then
  61. nfct_:=1$ % index of new functions and constants initialized
  62. cont_:=nil$ % if t then the user will be asked if a de
  63. % is too long for integration or substitution
  64. sp_cases:=nil$ % special cases for arbitrary functions or constants
  65. % are not of interest
  66. independence_:=nil$% if t then the user will be asked whether or not
  67. % expr. are considered to be linear independent
  68. genint_:=nil$ % generalized integration disabled/enabled
  69. factorize_:=5$ % recursion depth for factorizing equations
  70. odesolve_:=100$ % maximal length of a de (number of terms) to be
  71. % integrated as ode
  72. fcteval_:=100$ % maximal length of an expression to be substituted
  73. % for a function
  74. decouple_:=2$ % max. number of decoupling processes for a function
  75. tr_gensep:=nil$ % Trace generalized separation
  76. tr_genint:=nil$ % Trace generalized integration
  77. fname_:='c$ % name of new functions and constants (integration)
  78. logoprint_:=t$ % print logo for crack call
  79. poly_only:=t$ % all equations are polynomials only
  80. time_:=t$ % print the time needed for running crack
  81. print_:=8>>$ % maximal length of an expression to be printed
  82. symbolic operator crackhelp$
  83. symbolic procedure crackhelp$
  84. <<
  85. terpri()$
  86. write "The call: CRACK({expr1,...,exprn},{fct1,...,fctm},",
  87. "{var1,...vark})"$
  88. terpri()$terpri()$
  89. write "expr1,...,exprn are the equations expr1=0,...,exprn=0."$
  90. write "fct1,...,fctm are the unknown functions depending on ",
  91. "arguments"$
  92. terpri()$
  93. write " declared by DEPEND fcti,...$ ."$terpri()$
  94. write "var1,...,vark are further independent free variables which"$
  95. terpri()$
  96. write " none of the fcti depends on."$terpri()$terpri()$
  97. write "The Return: {res1,...,resr}, each resi representing a",
  98. " solution of the form"$terpri()$
  99. write "resi = {list_remain_ness_and_suff_conditions, ",
  100. "list_solved_functions,"$
  101. terpri()$
  102. write " list_free_or_unsolved_functions}"$terpri()$
  103. write "i.e. CRACK returns {} if it found that no solution exists"$
  104. terpri()$terpri()$
  105. write "The performance of CRACK can be controlled with special flags."$
  106. terpri()$
  107. write "The procedure SETCRACKFLAGS() sets the defaults for all flags"$
  108. terpri()$
  109. write "and the procedure LISTCRACKFLAGS() shows the flags and their ",
  110. "defaults."$
  111. terpri()$
  112. write "All flags are GLOBAL or FLUID symbolic mode variables."$
  113. terpri()$
  114. write "They can be changed with: SYMBOLIC (flagname:=value)$"$
  115. terpri()$terpri()$
  116. write "This helptext can be recalled by: CRACKHP()"$terpri()$
  117. write "For more detailed information see the manual."
  118. >>$
  119. symbolic operator listcrackflags$
  120. symbolic procedure listcrackflags$
  121. <<
  122. write
  123. "The values in parenthesis are the defaults. ",
  124. "For more details see the manual."$
  125. terpri()$terpri()$write
  126. "CONT_ (nil): ",
  127. "if t then the user will be asked if a de is too long"$
  128. terpri()$write
  129. " (wrt. odesolve_, fcteval_) ",
  130. "for integration or substitution"$
  131. terpri()$write
  132. "DECOUPLE_ (2): maximal number of decoupling attempts ",
  133. "for each function"$
  134. terpri()$write
  135. "FACTORIZE_ (5): recursion depth for factorizing equations"$
  136. terpri()$write
  137. "FCTEVAL_ (100): maximal length of an expression to be ",
  138. "substituted"$
  139. terpri()$write
  140. " for a function"$
  141. terpri()$write
  142. "FNAME_ ('c): name of new functions and constants (integr.)"$
  143. terpri()$write
  144. "GENINT_ (nil): generalized integration disabled/enabled"$
  145. terpri()$write
  146. "INDEPENDENCE_ (nil): if t then the user will be asked whether or not"$
  147. terpri()$write
  148. " expressions are considered to be linear ",
  149. "independent"$
  150. terpri()$write
  151. "ODESOLVE_ (100): maximal length of a de (number of terms) to be"$
  152. terpri()$write
  153. " integrated as ode"$
  154. terpri()$write
  155. "PRINT_ (8): maximal length of an expression to be printed"$
  156. terpri()$write
  157. "SP_CASES (nil): if nil then dropping also such factors after ",
  158. "factorization"$
  159. terpri()$write
  160. " which contain unknown functions or constants ",
  161. "which are"$
  162. terpri()$write
  163. "TIME_ (T): print the time needed for running crack"$
  164. terpri()$write
  165. " parametric and not to calculate"$
  166. terpri()$write
  167. "TR_GENINT (nil): Trace generalized integration"$
  168. terpri()$write
  169. "TR_GENSEP (nil): Trace generalized separation"$
  170. terpri()$
  171. >>$
  172. symbolic operator crack$
  173. symbolic procedure crack(el,il,fl,vl)$
  174. begin scalar l,l1,l2,n,m,ezgcdold,mcdold,gcdold,expold,ratold,ratargold$
  175. if print_ and logoprint_ then
  176. <<
  177. "**************************************************************",
  178. "************"$
  179. terpri()$
  180. write
  181. "This is CRACK - a solver for overdetermined partial differential ",
  182. "equations"$
  183. terpri()$
  184. write "Version 25-08-1993"$terpri()$
  185. write
  186. "***************************************************************",
  187. "***********"$
  188. terpri()$
  189. >>$
  190. ezgcdold:=!*ezgcd$
  191. gcdold:=!*gcd$
  192. expold:=!*exp$
  193. mcdold:=!*mcd$
  194. ratold:=!*rational$
  195. ratargold:=!*ratarg$
  196. !*ezgcd:=t$
  197. !*gcd:=nil$
  198. !*exp:=t$
  199. !*mcd:=t$
  200. %!*rational:=nil$
  201. !*rational:=t$
  202. !*ratarg:=t$
  203. fnew_:=nil$
  204. special_cases:=nil$
  205. vl:=union(reverse argset cdr fl,cdr vl)$
  206. % if print_ then
  207. % <<terpri()$write "CRACK is called with :"$terpri()$
  208. % terpri()$write "equations : "$deprint cdr el$terpri()$
  209. % terpri()$write "functions : "$fctprint cdr fl$terpri()$
  210. % terpri()$write "variables : "$fctprint vl$terpri()>>$
  211. n:=time()$
  212. m:=gctime()$
  213. l:=union(crack1(cdr el,nil,cdr il,cdr fl,vl,factorize_,nil,nil),nil)$
  214. if !*time or time_ then
  215. <<terpri()$write "CRACK needed : ",time()-n," ms GC time : ",
  216. gctime()-m," ms">>$
  217. !*ezgcd:=ezgcdold$
  218. !*gcd:=gcdold$
  219. !*exp:=expold$
  220. !*mcd:=mcdold$
  221. !*rational:=ratold$
  222. !*ratarg:=ratargold$
  223. l:=for each a in l collect
  224. <<l1:=nil$
  225. l2:=caddr a$
  226. for each b in cadr a do
  227. if (pairp b) and (car b = 'EQUAL) then l1:=cons(b,l1)
  228. else l2:=cons(b,l2)$
  229. list(car a,l1,l2)>>$
  230. return if l then
  231. cons('LIST,for each a in l collect list('LIST,cons('LIST,car a),
  232. cons('LIST,cadr a),
  233. cons('LIST,caddr a)))
  234. else list('LIST)
  235. end$
  236. symbolic procedure crack1(ss,sf,ineq,forg,vl,fact,level,ass)$
  237. % Main program
  238. begin scalar q,p,s,ftem,fges,f,ls,lf,l,l1,se,ndecouple,decfl$
  239. contradiction_:=nil$
  240. ineq_:=ineq$
  241. ndecouple:=0$
  242. ss:=desort ss$ % sort the de's w.r.t. its length
  243. sf:=desort sf$
  244. fges:=union(smemberl(fnew_,append(forg,append(ss,sf))),forg)$
  245. % add new functions
  246. fnew_:=nil$
  247. rep: ftem:=smemberl(fges,union(ss,sf))$ % only occuring functions
  248. if print_ and (ss or sf) then
  249. <<terpri()$write "equations: "$
  250. deprint(ss)$
  251. deprint(sf)>>$
  252. if print_ and ineq_ then
  253. <<terpri()$write "non-vanishing expressions: "$
  254. for each aa in ineq_ do eqprint aa>>$
  255. if print_ then
  256. <<terpri()$write "functions: "$
  257. fctprint(forg)>>$
  258. if print_ then fctprint(setdiff(ftem,forg))$
  259. for each p in union(sf,ss) do
  260. if member(p,ftem) then l:=cons(cons(0,p),l)$
  261. while l or ss do
  262. <<for each p in l do
  263. <<l1:=ls:=lf:=nil$
  264. if print_ then
  265. <<terpri()$write "substitution : "$
  266. substprint(cdr p,car p)>>$
  267. if ineq_ and null (ineq_:=ineqsubst(p,ftem)) then l:=ss:=nil$
  268. while not contradiction_ and ss do
  269. <<s:=car ss$
  270. ss:=cdr ss$
  271. ls:=cons(reval subst(car p,cdr p,s),ls)$
  272. contradiction(s,fges)>>$
  273. while not contradiction_ and sf do
  274. <<s:=car sf$
  275. sf:=cdr sf$
  276. if freeof(s,cdr p) then lf:=cons(s,lf)
  277. else
  278. <<ls:=cons(reval subst(car p,cdr p,s),ls)$
  279. if contradiction(s,fges) then contradiction_:=t>> >>$
  280. if not contradiction_ then
  281. <<for each s in se do
  282. if freeof(s,cdr p) then l1:=cons(s,l1)$
  283. se:=reverse l1$
  284. ss:=desort delete(0,union(ls,nil))$
  285. sf:=desort delete(0,union(lf,nil))>>$
  286. forg:=fctsubst(car p,cdr p,forg)$
  287. ftem:=delete(cdr p,ftem)$
  288. fges:=delete(cdr p,fges)$
  289. >>$ % alle Fkt. subst.
  290. ls:=ss$
  291. l:=nil$
  292. while not contradiction_ and ls do
  293. <<q:=car ls$
  294. ls:=cdr ls$
  295. ss:=delete(q,ss)$
  296. if pairp q then
  297. <<l1:=desort gensep(q,smemberl(union(fnew_,ftem),q),vl)$
  298. sf:=union(reverse l1,sf)$
  299. ftem:=union(fnew_,smemberl(ftem,append(sf,ss)))$
  300. fges:=union(fnew_,smemberl(fges,append(sf,ss)))$
  301. for each p in l1 do
  302. if member(p,ftem) then l:=union(list cons(0,p),l)
  303. else se:=cons(p,se)$
  304. if l then ls:=nil>>
  305. else se:=cons(q,se)$
  306. se:=desort union(se,nil)$
  307. if not contradiction_ then
  308. while se and not l do
  309. <<if q:=fcteval(car se,ftem,vl) then
  310. <<l:=union(list q,l)$
  311. ls:=nil>>$
  312. se:=cdr se>>
  313. >>$
  314. while se and not l do
  315. <<if q:=fcteval(car se,ftem,vl) then l:=union(list q,l)$
  316. se:=cdr se>>
  317. >>$
  318. if contradiction_ then RETURN NIL$
  319. if fact and (fact>0) then
  320. q:=splitandcrack(sf,ineq_,forg,ftem,vl,fact,level,ass)
  321. else q:=nil$
  322. decfl:=makedecfl(fges,decfl)$
  323. if q then p:=nil
  324. else % decoupling process starts
  325. if (ndecouple<decouple_) and
  326. (p:=decouple(sf,forg,ftem,fges,vl,decfl,fact)) then
  327. if contradiction_ then RETURN NIL
  328. else
  329. <<ndecouple:=add1 ndecouple$
  330. if setdiff(car p,sf) or setdiff(sf,car p) or (cadr p) then
  331. <<sf:=car p$
  332. ss:=cadr p$
  333. forg:=caddr p$
  334. fges:=cadddr p$
  335. decfl:=car cddddr p$
  336. goto rep>> >>$
  337. if not q then
  338. <<q:=list list(
  339. sf,
  340. forg,
  341. smemberl(setdiff(fges,forg),
  342. append(sf,for each l in equallist forg collect cddr l)))$
  343. if print_ then resout(caar q,cadar q,caddar q)>>$
  344. ineq_:=ineq$
  345. return q
  346. end$ % of crack1
  347. symbolic procedure ineqsubst(p,ftem)$
  348. % tests all q's in ineq_ for subst(car p, cdr p,q)=0
  349. % result: nil, if 0 occurs
  350. % otherwise list of the subst(car p,...)
  351. begin scalar l,a$
  352. while ineq_ do
  353. if not freeof(car ineq_,cdr p) then
  354. <<a:=reval subst(car p, cdr p,car ineq_)$
  355. if zerop a then
  356. <<if print_ then
  357. <<terpri()$write "contradiction :"$
  358. eqprint list('EQUAL,cdr p,car p)$
  359. write "because of non-vanishing expression:"$
  360. deprint list car ineq_>>$
  361. contradiction_:=t$
  362. l:=nil$
  363. ineq_:=nil>>
  364. else
  365. <<if pairp a and (car a='QUOTIENT) then a:=cadr a$
  366. a:=cdr reval list('FACTORIZE,a)$
  367. for each s in a do
  368. if smemberl(ftem,s) and not member(s,l) then l:=cons(s,l)$
  369. ineq_:=cdr ineq_>> >>
  370. else
  371. <<l:=cons(car ineq_,l)$
  372. ineq_:=cdr ineq_>>$
  373. return reverse l$
  374. end$
  375. symbolic procedure contradiction(s,fges)$
  376. % tests expression s for contradiction an non-zero expressions
  377. if (s=0) or smemberl(fges,s) then
  378. if member(s,ineq_) then
  379. <<if print_ then
  380. <<terpri()$write "non-zero expression vanishes : "$
  381. deprint list s>>$
  382. t>>
  383. else nil
  384. else
  385. <<if print_ then
  386. <<terpri()$write "Contradiction found : "$
  387. deprint list s>>$
  388. t>>$
  389. symbolic procedure makedecfl(fges,decfl)$
  390. % makes decouple flag list of functions in fges
  391. begin scalar s$
  392. while decfl do
  393. <<if member(caar decfl,fges) then s:=cons(car decfl,s)$
  394. decfl:=cdr decfl>>$
  395. for each f in fges do
  396. if not assoc(f,s) then s:=cons(cons(f,decouple_),s)$
  397. return s$
  398. end$
  399. symbolic procedure resout(sorg,forg,fnew)$
  400. begin scalar l$
  401. if print_ then
  402. <<for each a in forg do
  403. if (pairp a) and (car a='EQUAL) then l:=cons(a,l)
  404. else fnew:=cons(a,fnew)$
  405. terpri()$write "End of this CRACK run"$terpri()$terpri()$
  406. write "The solution : "$
  407. if l then
  408. fctprint l$
  409. if sorg then
  410. <<write "Remaining conditions : "$
  411. deprint sorg$
  412. if fnew then
  413. <<write "for the functions : "$fctprint fnew>> >>
  414. else if fnew then
  415. <<write "Free functions or constants : "$fctprint fnew>>$
  416. terpri()$
  417. write
  418. "*************************************************************",
  419. "*************"$terpri()$terpri()>>$
  420. end$
  421. symbolic procedure splitandcrack(sorg,ineq,forg,ftem,vl,fact,level,ass)$
  422. % If possible one de form sorg is factoirized and
  423. % crack1 is called with each factor instead
  424. begin scalar l,p,q,a,n$
  425. l:=sorg$
  426. while l do
  427. if (p:=splitde(car l,ftem)) then % factorizing a de
  428. <<a:=car l$
  429. if print_ then
  430. <<terpri()$
  431. write "factorizing "$deprint(list a)$
  432. write "we get the alternative equations : "$deprint(p)>>$
  433. l:=nil>>
  434. else l:=cdr l$
  435. if p then
  436. <<n:=0$
  437. for each d in p do % for each factor
  438. if not member(d,ineq_) then
  439. <<ass:=cons(d,ass)$
  440. n:=n+1$
  441. level:=cons(n,level)$
  442. if print_ then
  443. <<terpri()$
  444. write "Level : "$
  445. for each m in reverse level do write m,"."$terpri()$
  446. write "CRACK is now called with the assumtion(s) : "$
  447. deprint(reverse ass)>>$
  448. % sorg:=cons(d,delete(a,sorg))$
  449. l:=crack1(list(d),delete(a,sorg),ineq,
  450. union(forg,smemberl(ftem,sorg)),
  451. vl, if fact<2 then nil else fact-1,level,ass)$
  452. ineq:=union(list d,ineq)$
  453. ass:=cdr ass$
  454. level:=cdr level$
  455. if l then q:=union(clearphantomfct(l,forg),q)>> >>$
  456. % crack1 is called
  457. return q
  458. end$
  459. symbolic procedure clearphantomfct(l,forg)$
  460. % functions from higher level ftem beeing removed from forg
  461. for each a in l collect clrphfct(a,forg)$
  462. symbolic procedure clrphfct(a,forg)$
  463. begin scalar l,l1,fl$
  464. if a then
  465. <<for each f in forg do
  466. if (pairp f) and (car f='EQUAL) then fl:=cons(cadr f,fl)
  467. else fl:=cons(f,fl)$ % List of functions in forg
  468. for each f in cadr a do
  469. if (pairp f) and (car f='EQUAL) then
  470. (if member(cadr f,fl) then l:=cons(f,l)) % Member of forg
  471. else l1:=cons(f,l1)$ % free or unknown function
  472. l1:=smemberl(l1,append(car a,append(fl,l)))$
  473. % occuring in forg or sorg
  474. return list(car a,l,union(l1,caddr a))>>
  475. end$
  476. endmodule$
  477. %********************************************************************
  478. module decoupling$
  479. %********************************************************************
  480. % Routines for decoupling de's
  481. % Author: Andreas Brand
  482. % August 1991
  483. symbolic procedure eqderiv(p,f,vl)$
  484. % yields a list of de's by differentiating p w.r.t all those
  485. % variables from vl on which f not depends
  486. begin scalar l$
  487. vl:=setdiff(vl,fctargs f)$ % variables on which f not depends
  488. for each v in vl do
  489. if not freeof(p,v) then l:=cons(reval list('DF,p,v),l)$
  490. return l
  491. end$
  492. symbolic procedure decouplelist(liste,f)$
  493. % produces a list of de's for decoupling process w.r.t function f
  494. % the elements are of the type: ((expr (deriv.pot)) flag),
  495. % f Funktion
  496. begin scalar p,q$
  497. p:=nexteq(liste,t)$ % find first de marked with t
  498. q:=nexteq(liste,nil)$ % find first de marked with nil
  499. return if minausdp(p,q) then
  500. append(derivlist(list(list(q,nil),list(p,t)),f,
  501. difdiff(cadr q,cadr p),fctargs f,t),liste)
  502. % simplier de is marked with t
  503. % the other with nil
  504. % than the de's are diff.
  505. else append(derivlist(list(list(p,t),list(q,nil)),f,
  506. difdiff(cadr p,cadr q),fctargs f,nil),liste)
  507. end$
  508. symbolic procedure nexteq(liste,flag)$
  509. % finds the first element in liste marked with flag
  510. begin scalar stop$
  511. while (liste and (not stop)) do
  512. if flag=cadar liste then stop:=t
  513. else liste:=cdr liste$
  514. return if stop then caar liste
  515. else nil$
  516. end$
  517. symbolic procedure derivlist(dl,f,l,v,flag)$
  518. % differentiates de's from dl, dl:list of de's
  519. % f:function, l:list of numbers, v:list of variables,
  520. % flag:de to be substituted by a simplier one
  521. begin scalar m,p,q,li$
  522. for each x in v do
  523. <<m:=car l$
  524. l:=cdr l$
  525. if m<0 then % second de to be diff.
  526. <<if not q then q:=car nexteq(dl,not flag)$
  527. q:=reval list('DF,q,x,list('MINUS,m))$
  528. li:=cons(list(cons(q,ldiff(q,f)),not flag),li)>>
  529. else if 0<m then % first de to be differentiated
  530. <<if not p then p:=car nexteq(dl,flag)$
  531. p:=reval list('DF,p,x,m)$
  532. li:=cons(list(cons(p,ldiff(p,f)),flag),li)>> >>$
  533. return li$
  534. end$
  535. symbolic procedure fctchoose(stem,fl)$
  536. % finds function from fl with the maximal number of arguments
  537. if null (fl:=smemberl(fl,stem)) then nil
  538. else begin
  539. scalar s,n$
  540. s:=car fl$
  541. n:=fctlength s$
  542. for each f in cdr fl do
  543. if length(fctargs f)>n then
  544. <<s:=f$n:=fctlength s>>$
  545. return s
  546. end$
  547. symbolic procedure dechoose(gl,f)$
  548. % chooses two de's from list gl witch are optimal to be decoupled
  549. % w.r.t function f
  550. begin scalar d,c$
  551. d:=shortdesearch(gl,f)$
  552. c:=secondde(delete(d,gl),d,f)$
  553. return if null c then list(list(d,nil),list(nil,t))
  554. else
  555. if minausdp(d,c) then list(list(c,nil),list(d,t))
  556. else list(list(d,nil),list(c,t))
  557. end$
  558. symbolic procedure shortdesearch(gl,f)$
  559. % finds shortest de from list gl in which function f occurs
  560. if null gl then nil
  561. else if freeof(caar gl,f) then shortdesearch(cdr gl,f)
  562. else shortde(car gl,shortdesearch(cdr gl,f))$
  563. symbolic procedure shortde(g1,g2)$
  564. % finds the shorter of two de's
  565. if null g1 then g2
  566. else if null g2 then g1
  567. else begin scalar n,m$
  568. n:=delength(car g1)$
  569. m:=delength(car g2)$
  570. return if n<m then g1
  571. else if n=m then minausd(g1,g2)
  572. % the simplier de
  573. else g2$
  574. end$
  575. symbolic procedure secondde(gl,g,f)$
  576. % Auswahl der 2. Dgl. aus gl,g 1.Dgl.,f Funktion
  577. begin scalar c$
  578. c:=secondde1(gl,g,f)$
  579. if null c then c:=shortdesearch(gl,f)$
  580. return c
  581. end$
  582. symbolic procedure secondde1(gl,g,f)$
  583. % Auswahl der kuerzesten Gl. aus gl, die die Funktion f enthaelt und
  584. % einfacher als die Gleichung g ist
  585. if null gl then nil
  586. else
  587. if freeof(caar gl,f) or minausdp(car gl,g) then secondde1(cdr gl,g,f)
  588. % Gl., die f nicht enthalten oder
  589. % schwieriger als g sind, nicht
  590. else shortde(car gl,secondde1(cdr gl,g,f))$
  591. % die kuerzere aus der 1. Gl. und
  592. % der kuerzesten des Rests
  593. symbolic procedure decouple(sorg,forg,ftem,fges,vl,decfl,fact)$
  594. begin scalar repe,a,f,fl,l,l1,s,p,q,r,ss,s13,stem,ftem1,ftem2,stop2,h,
  595. fctflag$
  596. fl:=t$
  597. repe:=1$
  598. ftem1:=ftem$
  599. stem:=sorg$
  600. rep:
  601. stop2:=nil$
  602. ftem1:=smemberl(ftem1,stem)$
  603. ftem2:=nil$
  604. for each a in ftem1 do
  605. if assoc(a,decfl) then ftem2:=cons(a,ftem2)$
  606. if null ftem2 then
  607. <<l:=union(setdiff(stem,sorg),setdiff(s13,sorg))$
  608. % new equations
  609. stop2:=t$
  610. if null l or repe<=0 then
  611. <<for each a in l do
  612. sorg:=union(list reval aeval a,sorg)$
  613. sorg:=desort sorg$
  614. fl:=nil>>
  615. else <<repe:=sub1 repe$
  616. for each a in l do sorg:=union(list reval aeval a,sorg)$
  617. sorg:=desort sorg>> >>
  618. else if (f:=fctchoose(stem,ftem2)) then
  619. <<fctflag:=t$
  620. f:=assoc(f,decfl)$
  621. decfl:=cons(cons(car f,sub1 cdr f),delete(f,decfl))$
  622. f:=car f$
  623. if print_ then
  624. <<terpri()$write "decoupling: "$eqprint(f)>>$
  625. stem:=powappend(stem,f)$
  626. if print_ then <<terpri()$write "new equations: ">>$
  627. begin scalar stop3$
  628. rep1: stop3:=nil$
  629. l1:=dechoose(stem,f)$ % optimale Gl. suchen
  630. p:=caar l1$ % p schwierigere Gl.
  631. if (null caadr l1) and fctflag then
  632. if length varslist(p,smemberl(ftem,p),vl)>fctlength f then
  633. % f kommt nur in einer
  634. % Gl. vor und haengt nicht
  635. % von allen Variablen ab
  636. <<fctflag:=nil$
  637. stem:=union(powappend(eqderiv(car p,f,vl),f),stem)$
  638. % Hinzufuegen neuer Gl.
  639. l1:=dechoose(stem,f)$
  640. p:=caar l1>>$
  641. if not null caadr l1 then
  642. <<repeat
  643. <<l1:=decouplelist(l1,f)$ %list of de's to be decoupled
  644. h:=mkldiff(f,cadaar l1)$ % h leading derivative
  645. s:=car nexteq(l1,t)$
  646. if pairp s and (car s='QUOTIENT) then
  647. <<if (a:=casecheck(caddr s,vl)) then
  648. ineq_:=union(list a,ineq_)$
  649. s:=cadr s$>>$
  650. r:=car nexteq(l1,nil)$
  651. if pairp r and (car r='QUOTIENT) then
  652. <<if (a:=casecheck(caddr r,vl)) then
  653. ineq_:=union(list a,ineq_)$
  654. r:=cadr r>>$
  655. s:=reval !*q2a simpresultant list(s,r,h)$ % alg. decoupl.
  656. s:=car simplifyde(s,ftem1,vl,nil)$
  657. if contradiction(s,ftem1) then
  658. <<stem:=nil$
  659. stop2:=t$
  660. stop3:=t$
  661. contradiction_:=t$
  662. fl:=nil>>
  663. else
  664. <<ftem1:=union(fnew_,ftem1)$
  665. fges:=union(fnew_,fges)$
  666. if freeof(s,f) and
  667. stardep(s,smemberl(ftem1,s),varslist(s,ftem1,vl)) then
  668. <<ss:=list s$
  669. sorg:=desort sorg$
  670. fges:=union(fnew_,fges)$
  671. stem:=nil$
  672. stop2:=t$
  673. stop3:=t>> >>$
  674. if not stop3 then
  675. if (q:=fcteval(s,ftem1,vl)) then
  676. <<if print_ then
  677. <<terpri()$write "substitution : "$
  678. substprint(cdr q,car q)>>$
  679. if member(cdr q,ftem) then
  680. <<l:=nil$
  681. while sorg do
  682. <<a:=car sorg$
  683. sorg:=cdr sorg$
  684. if freeof(a,cdr q) then l:=cons(a,l)
  685. else
  686. <<ss:=cons(reval subst(car q,cdr q,a),ss)$
  687. if contradiction(car ss,ftem) then sorg:=nil
  688. >>
  689. >>$
  690. if not contradiction_ then
  691. <<sorg:=desort reverse l$
  692. ss:=desort delete(0,union(ss,nil))$
  693. forg:=fctsubst(car q,cdr q,forg)$
  694. stop3:=t$
  695. stop2:=t>>
  696. >>
  697. else
  698. <<stem:=powdelete(stem)$
  699. stem:=substandsep(q,stem,ftem1,vl)$
  700. if not contradiction_ then
  701. <<stem:=powappend(stem,f)$
  702. s13:=substandsep(q,s13,ftem1,vl)>>$
  703. stop3:=t$
  704. if contradiction_ then
  705. <<stop2:=t$
  706. fl:=t>>
  707. >>$
  708. ftem1:=delete(cdr q,ftem1)>>$
  709. if not stop3 then
  710. <<s:=cons(s,ldiff(s,f))$ % fuehr. Abl. + Potenz
  711. l1:=reverse l1$ % Reihenfolge umkehren
  712. l:=list(car l1)$ % einfach. Ausgangsgl.
  713. l1:=cdr l1$ % Glgn., von denen eine
  714. % ersetzt wird
  715. while not null l1 and minausdsp(caar l1,s) do
  716. <<l:=cons(car l1,l)$ % erste einfachere Gl.
  717. l1:=cdr l1>>$
  718. l1:=cons(list(s,not cadar l),l)$ % durch s ersetzen
  719. l:=nil$
  720. stop3:=nil$
  721. if print_ and (length l1=2) then
  722. <<eqprint(list('EQUAL,0,car s))$
  723. write "with leading derivative "$
  724. write reval list('EXPT,mkldiff(f,cadr s),cddr s)$
  725. write " replaces a de with "$
  726. write reval list('EXPT,mkldiff(f,cadr p),cddr p)$
  727. terpri()>> >> >>
  728. until ((length(l1)=2) and not q) or stop3$
  729. if not stop3 then
  730. if null car s or zerop car s then
  731. <<stem:=delete(p,stem)$
  732. p:=nil$
  733. stop2:=nil>>
  734. else
  735. <<
  736. stem:=cons(s,delete(p,stem))$
  737. % stem:=cons(cons(algsimple(car s,f,ftem1,vl),cdr s),
  738. % delete(p,stem))$
  739. p:=s:=nil$
  740. stop2:=nil>> >>
  741. else
  742. <<s13:=cons(car p,s13)$
  743. stem:=delete(p,stem)$
  744. p:=nil$
  745. stop3:=t>>$
  746. if not stop3 then goto rep1$
  747. end$
  748. stem:=powdelete(stem)>>$
  749. if not stop2 then goto rep$
  750. return if fl then list(sorg,ss,forg,fges,decfl)
  751. else nil
  752. end$
  753. endmodule$
  754. %*********************************************************************
  755. module separation$
  756. %*********************************************************************
  757. % Routines for separation of de's
  758. % Author: Andreas Brand
  759. % June 1990
  760. symbolic procedure termsep(a,x)$
  761. % Separieren eines Produktes
  762. % a Ausdr. in LISP-Notation, x Var.
  763. % Ergebnis: nil, falls keine Sep. moegl.,sonst Liste von Produktpaaren
  764. % ((abh. von x)(unabh. von x))
  765. begin scalar l,p,q,sig,l1,l2$
  766. if atom a then if x=a then l:=list(a,1) % Variable
  767. else l:=list(1,a) % Konstante
  768. else if freeof(a,x) then l:=list(1,a) % a unabh. von x
  769. else
  770. <<if car a='MINUS then
  771. <<a:=cadr a$
  772. sig:=not sig>>$
  773. if pairp a and (car a='TIMES) then l:=cdr a
  774. else l:=list a$ % l Liste der Faktoren
  775. p:=nil$ % Liste der Faktoren,
  776. % die x enthalten
  777. q:=nil$ % Liste der Faktoren,
  778. % die x nicht enth.
  779. while l do
  780. <<if freeof(car l,x) then q:=cons(car l,q)
  781. % Faktor enth. x nicht
  782. else
  783. if pairp car l and (caar l='EXPT) and freeof(cadar l,x)
  784. and (pairp caddar l) and (car caddar l='PLUS) then
  785. <<for each s in cdr caddar l do
  786. if freeof(s,x) then l1:=cons(s,l1)
  787. else l2:=cons(s,l2)$
  788. if l1 then
  789. <<if cdr l1 then l1:=cons('PLUS,l1)
  790. else l1:=car l1$
  791. q:=cons(list('EXPT,cadar l,l1),q)>>$
  792. if l2 and cdr l2 then l2:=cons('PLUS,l2)
  793. else l2:=car l2$
  794. p:=cons(list('EXPT,cadar l,l2),p)>>
  795. else p:=cons(car l,p)$
  796. l:=cdr l>>$
  797. if p then
  798. if length p>1 then p:=cons('TIMES,p)
  799. else p:=car p$
  800. if q then
  801. if length q>1 then q:=cons('TIMES,q)
  802. else q:=car q$
  803. if p or q then % war Sep. moegl.?
  804. if null p then if sig then l:=list(1,list('MINUS,q))
  805. else l:=list(1,q)
  806. else
  807. if q then if sig then l:=list(p,list('MINUS,q))
  808. else l:=list(p,q)
  809. else if sig then l:=list(p,list('MINUS,1))
  810. else l:=list(p,1)>>$
  811. return l
  812. end$
  813. symbolic procedure sumsep(l,x)$
  814. % Separieren einer Liste von Summanden
  815. % l Liste von Ausdr. in LISP-Notation, x Var.
  816. % Ergebnis: nil, falls keine Sep. moegl.,
  817. % sonst Liste von Listen von Summanden
  818. begin scalar cl,p,q,s,qflag$
  819. while l do
  820. if pairp car l and (caar l='QUOTIENT) then
  821. <<p:=termsep(cadar l,x)$
  822. if not q then q:=termsep(caddar l,x)$ % Quotient immer gleich
  823. if p and q then
  824. <<l:=cdr l$
  825. if car q=1 then s:=car p
  826. else s:=list('QUOTIENT,car p,car q)$
  827. if cadr q=1 then p:=list(s,cadr p)
  828. else p:=list(s,list('QUOTIENT,cadr p,cadr q))$
  829. cl:=termsort(cl,p)>>
  830. else
  831. <<l:=nil$
  832. cl:=nil>> >>
  833. else
  834. <<p:=termsep(car l,x)$ % Separieren eines Summanden
  835. if p then % erfolgreich
  836. <<l:=cdr l$
  837. cl:=termsort(cl,p)>> % Terme einordnen
  838. else
  839. <<l:=nil$ % Abbruch
  840. cl:=nil>> >>$ % keine Separ. moegl.
  841. if cl and print_ and (length cl>1) then % output for test
  842. <<terpri()$write "separation w.r.t. "$fctprint list x$
  843. % of linear independence
  844. if pairp caar cl and (caaar cl='QUOTIENT) then
  845. l:=for each s in cl collect cadar s
  846. else l:=for each s in cl collect car s$
  847. if not linearindeptest(l,list x) then cl:=nil>>$
  848. return cl % Liste der Terme, die von x
  849. % unabh. sind
  850. end$
  851. symbolic procedure linearindeptest(l,vl)$
  852. begin scalar l1,flag$
  853. l1:=l$flag:=t$
  854. while flag and pairp l1 do
  855. if atom car l1 then l1:=cdr l1
  856. else if member(car l1,vl) then l1:=cdr l1
  857. else if caar l1='EXPT then
  858. if (numberp caddar l1) and member(cadar l1,vl)
  859. then l1:=cdr l1
  860. else flag:=nil
  861. else flag:=nil$
  862. if not flag then
  863. <<terpri()$write "linear independent expressions : "$
  864. for each x in l do eqprint(x)$
  865. if independence_ then
  866. if yesp "Are the expressions linear independent?"
  867. then flag:=t
  868. else flag:=nil
  869. else flag:=t>>$
  870. return flag$
  871. end$
  872. symbolic procedure termsort(cl,p)$
  873. % Zusammenfassen der Terme
  874. % cl Liste von Paaren,p Paar
  875. % Sind bei einem Element von cl und bei p die ersten Teile gleich,
  876. % wird der zweite Teil von p an den des Elements von cl angehaengt
  877. if null cl then list p
  878. else if caar cl=car p then cons(cons(car p,cons(cadr p,cdar cl)),cdr cl)
  879. else cons(car cl,termsort(cdr cl,p))$
  880. symbolic procedure eqsep(eql,ftem)$
  881. % Separieren einer Liste von: Gl. als Liste von Koeffizient + Summ.
  882. % + Liste der Var. nach denen schon erfolglos sep. wurde
  883. % + Liste der Var. nach denen noch nicht separiert wurde
  884. begin scalar vlist1,vlist2,a,x,l,eql1$
  885. while eql do
  886. <<a:=car eql$ % erste Gl. +Listen
  887. vlist1:=cadr a$ % Var. nach d. erfolglos sep. wurde
  888. vlist2:=caddr a$ % Var. nach denen nicht sep. wurde
  889. eql:=cdr eql$
  890. if vlist2 then % noch Var. zu sep.
  891. <<x:=car vlist2$
  892. vlist2:=cdr vlist2$
  893. if freeof(cdar a,x) then
  894. eql:=cons(list(car a,vlist1,vlist2),eql)
  895. else if fctdepend(list cdar a,x,ftem)
  896. then eql:=cons(list(car a,cons(x,vlist1),vlist2),eql)
  897. else <<l:=sumsep(cdar a,x)$
  898. % Liste der Gl. die sich durch Sep.
  899. % nach x ergeben
  900. if l then
  901. eql:=append(varapp(l,caar a,nil,append(vlist1,vlist2)),eql)
  902. % nach erfolgr. Sep. wird nach bisher
  903. % erfolglosen Var. sep.
  904. else
  905. eql:=cons(list(car a,cons(x,vlist1),vlist2),eql)>> >>
  906. % erfolgloses Sep.,x wird als
  907. % erfolglose Var. registriert
  908. else eql1:=cons(a,eql1)>>$
  909. return eql1$
  910. end$
  911. symbolic procedure separ(p,ftem,varl)$
  912. % Die Gl. p (in LISP-Notation) wird nach den Var. aus varl separiert
  913. % varl Liste der Variabl.
  914. begin scalar eql,eqlist,a,q,l,s$
  915. if p and not zerop p then
  916. if not (pairp p and (car p='QUOTIENT) and
  917. intersection(argset smemberl(ftem,cadr p),varl)) then
  918. <<if pairp p and (car p='QUOTIENT) then
  919. <<q:=cdr reval list('FACTORIZE,caddr p)$
  920. if length q>1 then q:=cons('TIMES,q)
  921. else q:=car q$
  922. p:=cadr p>>$
  923. if pairp p and (car p='PLUS) then
  924. a:=cons(nil,if not q then cdr p
  925. else for each b in cdr p collect list('QUOTIENT,b,q))
  926. else if not q then a:=list(nil,p)
  927. else a:=list(nil,List('QUOTIENT,p,q))$
  928. % Gl. als Liste von Summanden
  929. eql:=list(list(a,nil,varl))$
  930. % Listen der Var. anhaengen
  931. eql:=eqsep(eql,ftem)$
  932. while eql do
  933. <<a:=caar eql$ % Listen der Var. streichen
  934. if cddr a then a:=cons(car a,cons('PLUS,cdr a))
  935. else a:=cons(car a,cadr a)$ % PLUS eintragen
  936. if car a then
  937. if cdar a then a:=cons(cons('TIMES, car a),cdr a)
  938. else a:=cons(caar a,cdr a)
  939. else a:=cons(1,cdr a)$
  940. eqlist:=cons(a,eqlist)$
  941. eql:=cdr eql>>$
  942. if eqlist then eql:=union(cdr eqlist,list car eqlist)$
  943. eqlist:=nil$
  944. while eql do
  945. <<a:=car eql$
  946. l:=eql:=cdr eql$
  947. for each b in l do
  948. <<s:=reval list('QUOTIENT,cdr b,cdr a)$
  949. if not smemberl(append(varl,ftem),s) then
  950. <<eql:=delete(b,eql)$
  951. a:=cons(reval list('PLUS,car a,list('TIMES,s,car b)),cdr a)>>
  952. >>$
  953. eqlist:=cons(a,eqlist)>>
  954. >>
  955. else eqlist:=list cons(1,p) % FTEM functions in the DENR of p
  956. else eqlist:=list cons(0,0)$
  957. return eqlist
  958. end$
  959. symbolic procedure separate(p,ftem,vl)$
  960. % Separieren der Gleichung p
  961. % ftem Liste der Fkt., vl Liste der Variablen
  962. begin scalar l$
  963. l:=separ(p,ftem,vl)$
  964. return union(for each a in l collect cdr a,nil)$
  965. end$
  966. symbolic procedure stardep(p,ftem,vl)$
  967. % yields: nil, if a function (from ftem) in p depends
  968. % on all variables (from vl)
  969. % cons(v,n) otherweise, with v beeing the list of variables
  970. % on which depend a minimal number n of functions
  971. begin scalar ft,b,v,n,m$
  972. vl:=varslist(p,ftem,vl)$
  973. ft:=ftem$
  974. n:=length vl$ % number of all variables
  975. while not b and ft do % searching a fct of all vars
  976. if fctlength car ft=n then b:=t
  977. else ft:=cdr ft$
  978. if not b then
  979. <<n:=sub1 length ftem$
  980. while vl do % searching var.s on which depend a
  981. % minimal number of functions
  982. <<if n> (b:=for each h in ftem sum
  983. if member(car vl,fctargs h) then 1
  984. else 0)
  985. then
  986. <<n:=b$ % a new minimum
  987. v:=list car vl>>
  988. else if b=n then v:=cons(car vl,v)$
  989. vl:=cdr vl>> >>$
  990. return if v then cons(v,n) % on each varible from v depend n
  991. % functions
  992. else nil
  993. end$
  994. symbolic procedure gensep(p,ftem,vl)$
  995. begin scalar a,aa,q,l,l1,l2,ft,pl,pl1,x,vl1,deno$
  996. if pairp p and (car p = 'QUOTIENT) then
  997. <<casecheck(caddr p,vl)$
  998. p:=cadr p>>$
  999. ftem:=smemberl(ftem,p)$
  1000. vl:=varslist(p,ftem,vl)$
  1001. if not (a:=stardep(p,ftem,vl)) then pl:=list p
  1002. else
  1003. if zerop cdr a then pl:=separate(p,ftem,vl)
  1004. else % e.g. a=((x y z).2)
  1005. <<pl:=list p$
  1006. if print_ then <<terpri()$write "generalized separation ">>$
  1007. if tr_gensep then
  1008. <<terpri()$write "de to be separated : "$
  1009. deprint pl$
  1010. terpri()$write "variable list for separation : ",car a$
  1011. terpri()$write "for each of these variables ",cdr a,
  1012. " function(s) do(es) not depend on it ">>$
  1013. a:=car a$
  1014. while pairp a do % i.e. being able to make a separation for each x
  1015. <<x:=car a$
  1016. q:=p$ ft:=l2:=nil$
  1017. for each f in ftem do
  1018. if member(x,fctargs f) and not freeof(q,f) then ft:=cons(f,ft)$
  1019. if tr_gensep then
  1020. <<terpri()$write "to separate directly w.r.t. ",x$
  1021. write " the expression : "$deprint list q$
  1022. write "will be differentiated">>$
  1023. ft:=reverse fctsort ft$ % sorting w.r.t. number of args
  1024. while ft do % throwing out all functions ft
  1025. if (l1:=felim(q,car ft,ftem,vl,l2)) then
  1026. <<q:=car l1$
  1027. l2:=cadr l1$
  1028. aa:=stardep(q,smemberl(ftem,q),vl)$
  1029. if not aa or zerop cdr aa then ft:=nil
  1030. else ft:=smemberl(cdr ft,q)>>
  1031. else ft:=nil$
  1032. if l1 then
  1033. <<if (pairp q) and (car q='QUOTIENT) then
  1034. <<deno:=caddr q;
  1035. q:=cadr q;
  1036. ft:=smemberl(ftem,q)>> else ft:=nil$
  1037. if ft then
  1038. <<vl1:=nil$
  1039. for each y in vl do if freeof(ft,y) then vl1:=cons(y,vl1)
  1040. >> else vl1:=vl$
  1041. if aa and zerop cdr aa and not (q=0) then
  1042. <<if tr_gensep then
  1043. <<terpri()$write "trying direct separation of "$
  1044. deprint list q$
  1045. write "Remaining variables: ",vl1>>;
  1046. l1:=separate(q,ftem,vl1)$
  1047. if tr_gensep then
  1048. <<write "The result of direct separation: "$deprint l1>>$
  1049. if l1 and cdr l1 and tr_gensep then
  1050. <<terpri()$
  1051. write "direct separation yields ",length l1," equations">>
  1052. >>
  1053. else l1:=list q$
  1054. l1:=desort for each s in l1 collect
  1055. if deno then
  1056. backint(list('QUOTIENT,s,deno),l2,union(fnew_,ftem),vl)
  1057. else
  1058. backint(s,l2,union(fnew_,ftem),vl)$
  1059. ftem:=union(fnew_,ftem)$
  1060. pl:=union(l1,pl)$
  1061. while l1 do
  1062. <<if fctevalstrict(car l1,ftem,vl) then
  1063. <<pl1:=cons(car l1,pl1)$
  1064. a:=list nil$
  1065. ftem:=union(fnew_,ftem)>>$
  1066. l1:=cdr l1
  1067. >>
  1068. >>$
  1069. a:=cdr a$
  1070. >>$
  1071. >>$
  1072. if pl1 then
  1073. pl:=union(simplifyde(reval p,union(fnew_,ftem),vl,genint_),pl1)
  1074. else
  1075. <<if null pl then pl:=list p$
  1076. for each p in pl do
  1077. pl1:=union(simplifyde(reval p,union(fnew_,ftem),vl,genint_),pl1)$
  1078. pl:=pl1$
  1079. if cdr pl and print_ then
  1080. <<terpri()$write "separation yields ",length pl," equations"$
  1081. if tr_gensep then deprint pl>>
  1082. >>$
  1083. return pl$
  1084. end$
  1085. symbolic procedure felim(q,f,ftem,vl,l2)$
  1086. begin scalar a,b,l,l1,ft1,v,prflag$
  1087. v:=car setdiff(vl,fctargs f)$ % getting rid of f through diff. wrt. v
  1088. ft1:=nil$
  1089. for each f in ftem do if freeof(f,v) then ft1:=cons(f,ft1)$
  1090. if not (pairp q and (car q='QUOTIENT) and smemberl(ft1,caddr q)) then
  1091. <<prflag:=print_$print_:=nil$
  1092. l:=desort separ(q,ft1,list v)$ % det. all lin. ind. factors with v
  1093. if tr_gensep then
  1094. <<terpri()$write "To get rid of ",f,
  1095. " we differentiate w.r.t. : ",v>>$
  1096. print_:=prflag$
  1097. l1:=nil$
  1098. while l do
  1099. <<a:=car l$
  1100. b:=nil$
  1101. if not freeof(cdr a,f) and (not zerop car a) then
  1102. if (pairp cdr a) and (cadr a='PLUS) then
  1103. <<for each c in cddr a do if not freeof(c,f) then b:=cons(c,b)$
  1104. if b then b:=cons('PLUS,b)>> else b:=cdr a$
  1105. if b then
  1106. <<l1:=cons(car a,l1)$
  1107. % q:=reval list('DIFFERENCE,q,list('times,b,car a))
  1108. >>$
  1109. l:=cdr l
  1110. >>$
  1111. if tr_gensep then
  1112. <<terpri()$
  1113. write v," - depending coefficients of terms containing ",f," : "$
  1114. for each ss in l1 do eqprint ss>>$
  1115. while l1 do
  1116. <<b:=reval aeval car l1$
  1117. l1:=cdr l1$
  1118. if not zerop b then
  1119. <<a:=reval aeval list('QUOTIENT,q,b)$
  1120. % if not freeof(a,v) then
  1121. <<l:=cons(b,l)$ % for later backward integrations
  1122. l1:=for each c in l1 collect
  1123. reval list('DF,list('QUOTIENT,c,b),v)$
  1124. casecheck(b,vl)$
  1125. q:=reval list('DF,a,v)$
  1126. if tr_gensep then
  1127. <<write "The new equation: "$
  1128. eqprint q$
  1129. write "The remaining factors:"$
  1130. for each ss in l1 do eqprint ss$>>
  1131. >>
  1132. % else <<q:=b$ l1:=nil>>
  1133. >>
  1134. >>$
  1135. if tr_gensep then
  1136. <<terpri()$write "new expression (should not depend on ",f,") : "$
  1137. eqprint q$>>$
  1138. if l then l2:=cons(list(v,l),l2)$
  1139. if tr_gensep and l2 then
  1140. <<write "The list of multiplications and integrations ",
  1141. "to go backwards after direct separation:"$
  1142. for each ss in l2 do <<write "integr. wrt. ",car ss$ terpri()$
  1143. write "multiply with "$
  1144. for each aa in cadr ss do
  1145. eqprint aa>>
  1146. >>$
  1147. l1:=list(q,l2)
  1148. >>$
  1149. return l1$
  1150. end$
  1151. symbolic procedure backint(s,l2,ftem,vl)$
  1152. begin scalar fl,ft,q,l,v,v1,v2,vf,s2,p,f2,fnew1$
  1153. fnew1:=fnew_$
  1154. fl:=q:=t$
  1155. p:=s$
  1156. while l2 and fl do
  1157. <<l:=car l2$
  1158. l2:=cdr l2$
  1159. v:=car l$
  1160. if tr_gensep then
  1161. <<terpri()$
  1162. write "backward integration w.r.t. ",v," of the expression : "$
  1163. eqprint p>>$
  1164. l:=cadr l$
  1165. while l and q do
  1166. <<ft:=smemberl(ftem,p)$
  1167. %terpri()$write "vor int: p= "$eqprint p$
  1168. fnew_:=nil$
  1169. q:=integratepde(p,ft,list v,nil)$
  1170. fnew1:=append(fnew_,fnew1)$
  1171. if q then
  1172. <<fl:=t$
  1173. p:=reval list('TIMES,car l,car q)$
  1174. % Substituting the new functions of integration by derivatives
  1175. % of them such that back-integration can be made
  1176. % hat fnew_ nur ein element, d.h. wird nur eine Integration gemacht
  1177. % oder mehrere?
  1178. for each f1 in fnew_ do
  1179. <<f2:=f1;
  1180. vf:=setdiff(vl,fctargs f1);
  1181. for each s1 in reverse l2 do
  1182. <<v1:=car s1;
  1183. if not freeof(f1,v1) then
  1184. % only then integration makes difficulties
  1185. <<s2:=reverse cadr s1;
  1186. while s2 do
  1187. <<if not smemberl(vf,car s2) then
  1188. f2:=reval list('DF,list('QUOTIENT,f2,car s2),v1);
  1189. % actually only dividing through those factors of (car s2)
  1190. % which depend on v1 and which do not contain variables
  1191. % which f2 does not depent on.
  1192. s2:=cdr s2
  1193. >>
  1194. >>
  1195. >>;
  1196. if f1 neq f2 then
  1197. <<if tr_gensep then <<write f1," is replaced by ";
  1198. eqprint f2>>;
  1199. p:=subst(f2,f1,p)$
  1200. >>
  1201. >>;
  1202. ftem:=union(fnew_,ftem)
  1203. >> else fl:=nil$
  1204. l:=cdr l
  1205. >>
  1206. >>$
  1207. if tr_gensep then if fl then <<terpri()$write "yields : "$
  1208. eqprint p$>>
  1209. else <<terpri()$
  1210. write "was not successful.">>$
  1211. fnew_:=union(fnew1,fnew_)$
  1212. return if fl then p
  1213. else s
  1214. end$
  1215. endmodule$
  1216. %*********************************************************************
  1217. module integration$
  1218. %*********************************************************************
  1219. % Routines for integration of pde's containing unnown functions
  1220. % Author: Andreas Brand
  1221. % June 1990
  1222. symbolic procedure intminderiv(p,ftem,vl)$
  1223. % yields a list l of variables from vl, such that in p for each v in l
  1224. % there exists a derivative of a function f from ftem wrt. v
  1225. begin scalar l,ft,a$
  1226. for each v in vl do
  1227. <<ft:=ftem$
  1228. a:=t$
  1229. while ft and a do
  1230. if member(v,fctargs car ft) and highdiff(p,car ft,v)=0
  1231. then a:=nil
  1232. else ft:=cdr ft$
  1233. if a then l:=cons(v,l)>>$
  1234. return l
  1235. end$
  1236. symbolic procedure integratepde(p,ftem,varl,genflag)$
  1237. % Generalized integration of the expression p
  1238. % if not genflag then "normal integration"
  1239. begin scalar l,l1,vl,n,l2,q,f,flag$
  1240. varl:=if genflag then varl
  1241. else intminderiv(p,ftem,varl)$
  1242. q:=p$
  1243. if tr_genint then
  1244. <<terpri()$write "integration of the expression : "$
  1245. eqprint q$
  1246. >>$
  1247. %ftem:=smemberl(ftem,p)$
  1248. vl:=argset ftem$
  1249. if zerop q then flag:='success$
  1250. for each v in varl do
  1251. if member(v,vl) then
  1252. <<n:=0$
  1253. if flag neq 'genint then
  1254. <<p:=q$
  1255. while (p and not zerop p) do
  1256. <<p:=intpde(q,ftem,vl,v)$
  1257. if p then
  1258. if zerop cadr p then
  1259. <<q:=car p$n:=add1 n$flag:='success>>
  1260. else if not genflag then p:=nil
  1261. else
  1262. <<if print_ and not tr_genint then
  1263. <<terpri()$write "generalized Integration: ">>$
  1264. if (l2:=partint(cadr p,smemberl(ftem,cadr p),vl,v))
  1265. then
  1266. <<q:=reval list('PLUS,car p,car l2)$
  1267. n:=add1 n$
  1268. ftem:=union(fnew_,ftem)$
  1269. l1:=append(cdr l2,l1)$ % additional de's
  1270. flag:='genint>>$
  1271. p:=nil$
  1272. >>$
  1273. >> >>$
  1274. l:=cons(n,l)>>
  1275. else
  1276. <<flag:='success$
  1277. l:=cons(1,l)$
  1278. q:=reval list('INT,q,v)$
  1279. l2:=1$
  1280. >>$
  1281. l:=reverse l$
  1282. if not zerop q then
  1283. <<ftem:=reverse fctsort ftem$
  1284. while ftem do
  1285. if fctlength car ftem<length vl then ftem:=nil
  1286. else if fctlinear(q,f) then
  1287. <<f:=car ftem$
  1288. ftem:=nil>>
  1289. else ftem:=cdr ftem$
  1290. if f then
  1291. <<l2:=lderiv2(q,f,fctargs f)$
  1292. l2:=reval coeffn(q,reval car l2,cdr l2)>>
  1293. else l2:=1>>$
  1294. return if flag then
  1295. <<if varl then
  1296. for each v in varl do
  1297. <<q:=list('PLUS,q,intconst(l2,vl,v,car l))$
  1298. l:=cdr l>>
  1299. else
  1300. <<q:=newfct(fname_,vl,nfct_)$
  1301. nfct_:=add1 nfct_$
  1302. fnew_:=cons(q,fnew_)>>$
  1303. cons(reval q,l1)>>
  1304. else nil$
  1305. end$
  1306. symbolic procedure intpde(p,ftem,vl,x)$
  1307. % integration of an polynomial expr. p w.r.t. x
  1308. begin scalar f,ft,l,l1,vl,k,s,a,iflag,flag$
  1309. ft:=ftem$
  1310. vl:=cons(x,delete(x,vl))$
  1311. while ftem and not flag do
  1312. <<f:=car ftem$
  1313. if member(x,fctargs f) then
  1314. <<l1:=l:=lderiv2(p,f,vl)$
  1315. while not (flag or (iflag:=intlintest(p,f,l,x))) do
  1316. <<k:=reval coeffn(p,car l,cdr l)$
  1317. if intcoefftest(lderiv1(k,f,vl),car l,vl) then
  1318. <<a:=decderiv(car l,x)$
  1319. k:=reval list('INT,subst('v_a_r_,a,k),'v_a_r_)$
  1320. k:=reval subst(a,'v_a_r_,k)$
  1321. s:=cons(k,s)$
  1322. p:=reval aeval list('DIFFERENCE,p,list('DF,k,x))$
  1323. if (l:=lderiv2(p,f,vl))=l1 then flag:='neverending
  1324. else l1:=l>>
  1325. else flag:='coeffld>>$
  1326. if iflag='nofct then ftem:=smemberl(ftem,p)
  1327. else if fctlength f<length vl then
  1328. <<ftem:=cdr ftem$flag:=nil>>
  1329. else flag:=(iflag or flag)>>
  1330. else ftem:=cdr ftem>>$
  1331. return if not flag then
  1332. <<l:=explicitpart(p,ft,x)$
  1333. l:=list('INT,l,x)$
  1334. s:=reval aeval cons('PLUS,cons(l,s))$
  1335. p:=list('DIFFERENCE,p,list('DF,l,x))$
  1336. if poly_only then
  1337. if ratexp(s,ft) then list(s,reval aeval p)
  1338. else nil
  1339. else list(s,reval aeval p)>>
  1340. else nil$
  1341. end$
  1342. symbolic procedure explicitpart(p,ft,x)$
  1343. % part of a sum p which only explicitly depends on a variable x
  1344. begin scalar l$
  1345. if not member(x,argset smemberl(ft,p)) then l:=p
  1346. else if pairp p then
  1347. <<if car p='MINUS then
  1348. l:=reval list('MINUS,explicitpart(cadr p,ft,x))$
  1349. if (car p='QUOTIENT) and not member(x,argset smemberl(ft,caddr p))
  1350. then
  1351. l:=reval list('QUOTIENT,explicitpart(cadr p,ft,x),caddr p)$
  1352. if car p='PLUS then
  1353. <<for each a in cdr p do
  1354. if not member(x,argset smemberl(ft,a)) then l:=cons(a,l)$
  1355. if pairp l then l:=reval cons('PLUS,l)>> >>$
  1356. if not l then l:=0$
  1357. return l$
  1358. end$
  1359. symbolic procedure intconst(co,vl,x,n)$
  1360. begin scalar l,l2,f$
  1361. while n>0 do
  1362. <<f:=newfct(fname_,delete(x,vl),nfct_)$
  1363. nfct_:=add1 nfct_$
  1364. fnew_:=cons(f,fnew_)$
  1365. l:=cons(list('TIMES,f,list('EXPT,x,sub1 n)),l)$
  1366. n:=sub1 n>>$
  1367. if length l>1 then l:=cons('PLUS,l)
  1368. else if pairp l then l:=car l
  1369. else l:=0$
  1370. if length co>1 then
  1371. <<if car co='TIMES then co:=cdr co
  1372. else co:=list co$
  1373. while co do
  1374. <<if freeof(car co,x) then l2:=cons(car co,l2)$
  1375. co:=cdr co>> >>
  1376. else if not (co=x) then l2:=list co$
  1377. return reval if l2 then cons('TIMES,cons(l,l2))
  1378. else l
  1379. end$
  1380. symbolic procedure intcoefftest(l,l1,vl)$
  1381. begin scalar s$
  1382. return if not pairp l then t
  1383. else if car l='DF then
  1384. <<s:=decderiv(l1,car vl)$
  1385. if pairp s and pairp cdr s then s:=cddr s
  1386. else s:=nil$
  1387. if diffrelp(cons(cddr l,1),cons(s,1),vl) then t
  1388. else nil>>
  1389. else t$
  1390. end$
  1391. symbolic procedure fctlinear(p,f)$
  1392. <<p:=ldiffp(p,f)$
  1393. (null car p) and (cdr p=1)>>$
  1394. symbolic procedure intlintest(p,f,l,x)$
  1395. % Test,ob in einem Paar (fuehrende Ableitung.Potenz)
  1396. % eine x-Ableitung linear auftritt
  1397. if freeof(l,f) then 'nofct
  1398. else % Fkt. tritt auf
  1399. if (car l) and (cdr l=1) then % fuehr. Abl. tritt linear auf
  1400. if pairp car l then % Abl. der Fkt. tritt auf
  1401. if caar l='DF then
  1402. if member(x,cddar l) then nil
  1403. % x-Abl. tritt auf
  1404. else if member(x,fctargs cadar l) then 'noxdrv
  1405. else 'noxdep
  1406. else 'nodrv
  1407. else 'nodrv
  1408. else 'nonlin$
  1409. symbolic procedure decderiv(l,x)$
  1410. % in Diff.ausdr. l wird Ordn. d. Abl. nach x um 1 gesenkt
  1411. begin scalar l1$
  1412. return if l then if car l='DF then
  1413. <<l1:=decderiv1(cddr l,x)$
  1414. if l1 then cons('DF,cons(cadr l,l1))
  1415. else cadr l>>
  1416. else l
  1417. else nil$
  1418. end$
  1419. symbolic procedure decderiv1(l,x)$
  1420. if null l then nil
  1421. else
  1422. if car l=x then
  1423. if cdr l then
  1424. if numberp cadr l then
  1425. if cadr l>2 then cons(car l,cons(sub1 cadr l,cddr l))
  1426. else cons(car l,cddr l)
  1427. else cdr l
  1428. else nil
  1429. else cons(car l,decderiv1(cdr l,x))$
  1430. symbolic procedure integratede(q,ftem,genflag)$
  1431. % Integration of a de
  1432. % result: newde if successfull, nil otherwise
  1433. begin scalar l,l1,fl$
  1434. ftem:=smemberl(ftem,q)$
  1435. if l1:=integrableode(q,ftem) then % looking for an integrable ode
  1436. if l1:=integrateode(q,car l1,cadr l1,caddr l1,ftem) then
  1437. % trying to integrate it
  1438. <<q:=l1$
  1439. fl:=t$
  1440. ftem:=smemberl(union(fnew_,ftem),q)>>$
  1441. if l1:=integratepde(q,ftem,argset ftem,genflag) then
  1442. % trying to integrate a pde
  1443. <<q:=car l1$
  1444. l:=for each a in cdr l1 conc
  1445. <<ftem:=union(fnew_,ftem)$
  1446. if (l1:=integratede(a,ftem,nil)) then l1
  1447. else list a>>$
  1448. fl:=t$
  1449. ftem:=union(fnew_,ftem)>>$
  1450. if fl then
  1451. <<l:=cons(q,l)$
  1452. l:=for each a in l collect reval aeval a$
  1453. l:=for each a in l collect
  1454. if pairp a and (car a='QUOTIENT) then cadr a
  1455. else a>>$
  1456. return l$
  1457. end$
  1458. endmodule$
  1459. %********************************************************************
  1460. module generalized_integration$
  1461. %********************************************************************
  1462. % Routines for generalized integration of pde's containing unnown
  1463. % functions
  1464. % Author: Andreas Brand
  1465. % December 1991
  1466. symbolic procedure gintorder(p,vl,x)$
  1467. % reorder equation p
  1468. begin scalar l,l1,q,n,m,b,c$
  1469. if pairp(p) and (car p='QUOTIENT) then <<q:=caddr p$p:=cadr p>>$
  1470. if pairp(p) and (car p='PLUS) then p:=cdr p % list of summands
  1471. else p:=list p$
  1472. while p do
  1473. <<l1:=gintorder1(car p,x)$
  1474. if DepOnAllVars(car l1,x,vl) then l:=p:=nil
  1475. else <<l:=termsort(l,l1)$p:=cdr p>> >>$
  1476. if l then
  1477. <<l:=for each a in l collect if cddr a then
  1478. <<b:=car a$
  1479. c:=cdr reval coeff1(cons('PLUS,cdr a),x,nil)$
  1480. m:=0;
  1481. while c and (car c=0) do <<c:=cdr c$m:=add1 m>>$
  1482. if m>0 then b:=list('TIMES,list('EXPT,x,m),b)$
  1483. cons(reval b,c)>>
  1484. else
  1485. cons(reval car a,cdr reval coeff1(cadr a,x,nil))$
  1486. if q then
  1487. if freeof(q,x) then
  1488. l:=for each a in l collect
  1489. cons(car a,for each s in cdr a collect
  1490. reval list('QUOTIENT,s,q))
  1491. else
  1492. l:=for each a in l collect
  1493. cons(reval list('QUOTIENT,car a,q),cdr a)>>$
  1494. return l$
  1495. end$
  1496. symbolic procedure DepOnAllVars(c,x,vl)$
  1497. % tests for occurence off vars from vl in factors of c depending on x
  1498. begin scalar l$
  1499. if pairp c and (car c='TIMES) then c:=cdr c
  1500. else c:=list c$
  1501. while c and vl do
  1502. <<if not freeof(car c,x) then
  1503. for each v in vl do if not freeof(car c,v) then l:=cons(v,l)$
  1504. vl:=setdiff(vl,l)$
  1505. c:=cdr c
  1506. >>$
  1507. return (null vl)$
  1508. end$
  1509. symbolic procedure gintorder1(p,x)$
  1510. % reorder a term p
  1511. begin scalar l1,l2,sig$ % l2:list of factors of p not depending
  1512. % on x or beeing a power of x
  1513. % l1:all other factors
  1514. if pairp p and (car p='MINUS) then <<sig:=t$p:=cadr p>>$
  1515. if pairp p and (car p='TIMES) then p:=cdr p
  1516. else p:=list p$
  1517. for each a in p do
  1518. <<if freeof(a,x) then l2:=cons(a,l2)
  1519. else if a=x then l2:=cons(a,l2)
  1520. else if pairp a and (car a='EXPT) and (cadr a=x) and fixp caddr a
  1521. then l2:=cons(a,l2)
  1522. else l1:=cons(a,l1)>>$
  1523. if pairp l1 then
  1524. if cdr l1 then l1:=cons('TIMES,l1)
  1525. else l1:=car l1$
  1526. if pairp l2 then
  1527. <<if cdr l2 then l2:=cons('TIMES,l2)
  1528. else l2:=car l2$
  1529. if sig then l2:=list('MINUS,l2)>>$
  1530. return list(if l1 then l1 else 1,if l2 then l2 else 1)$
  1531. end$
  1532. symbolic procedure partint(p,ftem,vl,x)$
  1533. begin scalar f,neg,l1,n,k,l$
  1534. if tr_genint then
  1535. <<terpri()$write "generalized integration of the unintegrated rest : "$
  1536. eqprint p
  1537. >>$
  1538. l:=gintorder(p,vl,x)$
  1539. l:=for each s in l collect
  1540. <<f:=newfct(fname_,varslist(car s,ftem,vl),nfct_)$
  1541. nfct_:=add1 nfct_$
  1542. fnew_:=cons(f,fnew_)$
  1543. neg:=t$
  1544. n:=sub1 length cdr s$
  1545. k:=-1$
  1546. l1:=cons(reval list('DIFFERENCE,car s,list('DF,f,x,add1 n)),l1)$
  1547. reval cons('PLUS, for each sk on cdr s collect
  1548. <<neg:=not neg$
  1549. k:=add1 k$
  1550. reval
  1551. list('TIMES,if neg then -1 else 1,
  1552. list('DF,f,x,n-k),tailsum(sk,k,x))>>
  1553. )>>$
  1554. if l then l:=cons(reval cons('PLUS,l),l1)$
  1555. if tr_gensep then
  1556. <<terpri()$
  1557. write "result (without constant or function of integration): "$
  1558. eqprint car l$
  1559. write "additional equations : "$
  1560. deprint cdr l$
  1561. >>$
  1562. return l$
  1563. end$
  1564. symbolic procedure tailsum(sk,k,x)$
  1565. begin scalar j$
  1566. j:=-1$
  1567. return reval cons('PLUS,
  1568. for each a in sk collect
  1569. <<j:=j+1$
  1570. list('TIMES,a,prod(j+1,j+k),list('EXPT,x,j)) >> )
  1571. end$
  1572. symbolic procedure prod(m,n)$
  1573. if m>n then 1
  1574. else for i:=m:n product i$
  1575. endmodule$
  1576. %********************************************************************
  1577. module odeintegration$
  1578. %********************************************************************
  1579. % Routines for integration of ode's containing unnown functions
  1580. % Author: Thomas Wolf
  1581. % August 1991
  1582. symbolic procedure integrateode(de,fold,xnew,ordr,ftem)$
  1583. begin scalar newde,newnewde,l$ % Integral einer Gleichung
  1584. return
  1585. if not xnew then begin % Integr. einer alg. Gl. fuer eine Abl.
  1586. newde:=cadr solveeval list(de,fold)$
  1587. newde:=reval list('PLUS,cadr newde,list('MINUS,caddr newde))$
  1588. return
  1589. if newde=de then nil
  1590. else if (l:=integratede(newde,ftem,nil)) then car l
  1591. else nil$
  1592. end else % eine ode fuer ein f?
  1593. if not pairp fold then % i.e. not df(...,...), i.e. fold=f
  1594. odeconvert(de,fold,xnew,ordr)
  1595. % --> ode fuer eine Abl. von f
  1596. else begin
  1597. newde:=odeconvert(de,fold,xnew,ordr)$
  1598. % if print_ then
  1599. % if newde then <<terpri()$write "One ode has been integrated.">>$
  1600. return
  1601. if not newde then nil
  1602. else <<
  1603. newnewde:=cadr solveeval list(newde,fold)$
  1604. newnewde:=reval list('PLUS,cadr newnewde,list('MINUS,
  1605. caddr newnewde))$
  1606. ftem:=union(fnew_,ftem)$
  1607. newnewde:=integratede(newnewde,ftem,nil)$
  1608. if newnewde then car newnewde
  1609. else newde >>
  1610. end
  1611. end$ % of integrateode
  1612. symbolic operator polyans$
  1613. symbolic procedure polyans(ordr,dgr,x,y,d_y,fn)$
  1614. % generates a polynom
  1615. % for i:=0:dgr sum fn"i"(x,y,d_y(1),..,d_y(ordr-1))*d_y(ordr)**i
  1616. % with fn as the function names and d_y as names or derivatives of y
  1617. % w.r.t. x
  1618. begin scalar ll,fl,a,i,f$
  1619. i:=sub1 ordr$
  1620. while i>0 do
  1621. <<ll:=cons(list(d_y,i),ll)$
  1622. i:=sub1 i>>$
  1623. ll:=cons(y,ll)$
  1624. ll:=reverse cons(x,ll)$
  1625. fl:=nil$
  1626. i:=0$
  1627. while i<=dgr do
  1628. <<f:=newfct(fn,ll,i)$
  1629. fl:=(f . fl)$
  1630. a:=list('PLUS,list('TIMES,f,list('EXPT,list(d_y,ordr),i)),a)$
  1631. i:=add1 i>>$
  1632. return list('list,reval a,cons('list,fl))
  1633. end$ % of polyans
  1634. symbolic operator sepans$
  1635. symbolic procedure sepans(kind,v1,v2,fn)$
  1636. % Generates a separation ansatz
  1637. % v1,v2 = lists of variables, fn = new function name + index added
  1638. % The first variable of v1 occurs only in one sort of the two sorts of
  1639. % functions and the remaining variables of v1 in the other sort of
  1640. % functios.
  1641. % The variables of v2 occur in all functions.
  1642. % Returned is a sum of products of each one function of both sorts.
  1643. % form: fn1(v11;v21,v22,v23,..)*fn2(v12,..,v1n;v21,v22,v23,..)+...
  1644. % the higher "kind", the more general and difficult the ansatz is
  1645. % kind = 0 is the full case
  1646. begin scalar n,vl1,vl2,h1,h2,h3,h4,fl$
  1647. if cdr v1 = nil then <<vl1:=cdr v2;vl2:=cdr v2>>
  1648. else <<vl1:=cons(cadr v1,cdr v2)$
  1649. vl2:=append(cddr v1,cdr v2)>>$
  1650. return
  1651. if kind = 0 then <<vl1:=append(cdr v1,cdr v2)$
  1652. h1:=newfct(fn,vl1,'_)$
  1653. list('LIST,h1,list('LIST,h1))>>
  1654. else
  1655. if kind = 1 then <<h1:=newfct(fn,vl1,1)$
  1656. list('LIST,h1,list('LIST,h1))>>
  1657. else
  1658. if kind = 2 then <<h1:=newfct(fn,vl2,1)$
  1659. list('LIST,h1,list('LIST,h1))>>
  1660. else
  1661. if kind = 3 then <<h1:=newfct(fn,vl1,1)$
  1662. h2:=newfct(fn,vl2,2)$
  1663. list('LIST,reval list('PLUS,h1,h2),
  1664. list('LIST,h1,h2))>>
  1665. else
  1666. if kind = 4 then <<h1:=newfct(fn,vl1,1)$
  1667. h2:=newfct(fn,vl2,2)$
  1668. list('LIST,reval list('TIMES,h1,h2),
  1669. list('LIST,h1,h2))>>
  1670. else
  1671. if kind = 5 then <<h1:=newfct(fn,vl1,1)$
  1672. h2:=newfct(fn,vl2,2)$
  1673. h3:=newfct(fn,vl1,3)$
  1674. list('LIST,reval list('PLUS,list('TIMES,h1,h2),h3),
  1675. list('LIST,h1,h2,h3))>>
  1676. else
  1677. if kind = 6 then <<h1:=newfct(fn,vl1,1)$
  1678. h2:=newfct(fn,vl2,2)$
  1679. h3:=newfct(fn,vl2,3)$
  1680. list('LIST,reval list('PLUS,list('TIMES,h1,h2),h3),
  1681. list('LIST,h1,h2,h3))>>
  1682. else
  1683. if kind = 7 then <<h1:=newfct(fn,vl1,1)$
  1684. h2:=newfct(fn,vl2,2)$
  1685. h3:=newfct(fn,vl1,3)$
  1686. h4:=newfct(fn,vl2,4)$
  1687. list('LIST,reval list('PLUS,
  1688. list('TIMES,h1,h2),h3,h4),
  1689. list('LIST,h1,h2,h3,h4))>>
  1690. else
  1691. % ansatz of the form FN = FN1(v11,v2) + FN2(v12,v2) + ... + FNi(v1i,v2)
  1692. if kind = 8 then <<n:=1$ vl1:=cdr v1$ vl2:=cdr v2$
  1693. fl:=();
  1694. while vl1 neq () do <<
  1695. h1:=newfct(fn,cons(car vl1,vl2),n)$
  1696. vl1:=cdr vl1;
  1697. fl:=cons(h1, fl);
  1698. n:=n+1
  1699. >>;
  1700. list('LIST, cons('PLUS,fl), cons('LIST,fl))>>
  1701. else
  1702. <<h1:=newfct(fn,vl1,1)$
  1703. h2:=newfct(fn,vl2,2)$
  1704. h3:=newfct(fn,vl1,3)$
  1705. h4:=newfct(fn,vl2,4)$
  1706. list('LIST,reval list('PLUS,list('TIMES,h1,h2),
  1707. list('TIMES,h3,h4)),
  1708. list('LIST,h1,h2,h3,h4))>>
  1709. end$ % of sepans
  1710. symbolic procedure odecheck(ex,fint,ftem)$
  1711. % assumes an revaled expression ex
  1712. % Does wrong if car ex is a list!
  1713. begin scalar a,b,op,ex1$
  1714. %***** ex is a ftem-function *****
  1715. if ex=fint then % list(ex,0,0,..)
  1716. <<a:=list ex$
  1717. ex:=fctargs ex$
  1718. while ex do
  1719. <<a:=append(list(0,0),a)$
  1720. ex:=cdr ex>>$
  1721. % not checked if it is a function of an expression of x
  1722. op:=reverse a>>
  1723. else if pairp ex then
  1724. %***** car ex is 'df *****
  1725. if (car ex)='df then
  1726. <<a:=odecheck(cadr ex,fint,ftem)$
  1727. if not pairp a then op:=a
  1728. else % a is list(fctname,0,0,..,0,0)
  1729. <<op:=list(car a)$
  1730. a:=fctargs car a$ % a is list(variables), not checked
  1731. ex:=cddr ex$ % ex is list(derivatives)
  1732. while a do
  1733. <<ex1:=ex$
  1734. while ex1 and ((car a) neq (car ex1)) do ex1:=cdr ex1$
  1735. if null ex1 then op:=cons(0,cons(0,op))
  1736. else
  1737. <<if not cdr ex1 then b:=1 % b is number of deriv. of that var.
  1738. else
  1739. <<b:=cadr ex1$
  1740. if not numberp b then b:=1>>$
  1741. op:=cons(b,cons(b,op))>>$
  1742. a:=cdr a>>$
  1743. op:=reverse op>> >>
  1744. else
  1745. %***** car ex is a standard or other function *****
  1746. <<a:=car ex$ % for linearity check
  1747. ex:=cdr ex$
  1748. if a='INT then ex:=reval car ex$
  1749. while (op neq '!_abb) and ex do
  1750. <<b:=odecheck(car ex,fint,ftem)$
  1751. if b then % function found
  1752. if b eq '!_abb then op:='!_abb else % occures properly
  1753. if not poly_only then op:=odetest(op,b) else % linearity check
  1754. if (a = 'PLUS) or (a = 'MINUS) then op:=odetest(op,b) else
  1755. if a = 'TIMES then
  1756. if smemberl(ftem,cdr ex) then op:='!_abb
  1757. %car b is f.-name->freeof works
  1758. else op:=odetest(op,b)
  1759. else op:='!_abb$
  1760. ex:=cdr ex>> >>$
  1761. return op
  1762. end$
  1763. symbolic procedure integrableode(p,ftem)$
  1764. if delength p>(if odesolve_ then odesolve_ else 0) then
  1765. (if cont_ then
  1766. if yesp("expression to be integrated ? ") then
  1767. integrableode1(p,ftem))
  1768. else integrableode1(p,ftem)$
  1769. symbolic procedure integrableode1(p,ftem)$
  1770. begin scalar a,b,u,vl,le,uvar,
  1771. fint,fivar,% the function to be integrated and its variables
  1772. fold, % the new function of the ode
  1773. xnew, % the independ. variable of the ode
  1774. ordr1, % order of the ode
  1775. ordr2, % order of the derivative for which it is an ode
  1776. intlist$ % list of ode's
  1777. ftem:=smemberl(ftem,p)$
  1778. vl:=argset ftem$
  1779. % p muss genau eine Funktion aus ftem von allen Variablen enthalten.
  1780. % Die Integrationsvariable darf nicht Argument anderer in p enthaltener
  1781. % ftem-Funktionen sein.
  1782. a:=ftem$
  1783. b:=nil$
  1784. le:=length vl$
  1785. while a and vl do
  1786. <<u:=car a$
  1787. uvar:=fctargs u$
  1788. if (length uvar) = le then
  1789. if b then
  1790. <<vl:=nil$a:=list(nil)>>
  1791. else
  1792. <<b:=t$
  1793. fint:=u$
  1794. fivar:=uvar>>
  1795. else vl:=setdiff(vl,uvar)$
  1796. a:=cdr a>>$
  1797. if not b then vl:=nil$
  1798. le:=length p$
  1799. if ((1<le) and vl) then
  1800. <<a:=odecheck(p,fint,ftem)$
  1801. if not atom a then % The equation is an ode
  1802. <<ordr1:=0$
  1803. ordr2:=0$
  1804. xnew:=nil$
  1805. a:=cdr a$
  1806. b:=fivar$
  1807. while b do
  1808. <<if (car a) neq 0 then
  1809. <<fold:=cons(car b,fold)$
  1810. if (car a) > 1 then fold:=cons(car a,fold)>>$
  1811. ordr2:=ordr2+car a$
  1812. if (car a) neq (cadr a) then
  1813. <<xnew:=car b$
  1814. if not member(xnew,vl) then
  1815. <<b:=list(nil)$vl:=nil>>$
  1816. ordr1:=(cadr a) - (car a)>>$
  1817. b:=cdr b$
  1818. a:=cddr a>>$
  1819. fold:=reverse fold$
  1820. %fold is the list of diff.variables + number of diff.
  1821. if fold then fold:=cons('df,cons(fint,fold))
  1822. else fold:=fint$
  1823. if vl and ((ordr1 neq 0) or (ordr2 neq 0)) then
  1824. intlist:=list(fold,xnew,ordr1,ordr2)
  1825. >> % of variable found
  1826. >>$ % of if
  1827. return intlist
  1828. end$ % of integrableode1
  1829. symbolic procedure odetest(op,b)$
  1830. if not op then b
  1831. else % op=nil --> first function found
  1832. if (car op) neq (car b) then '!_abb else % f occurs in differ. fct.s
  1833. begin scalar dif,a$
  1834. dif:=nil$ % dif=t --> different derivatives
  1835. a:=list(car op)$ % in one variable already found
  1836. op:=cdr op$
  1837. b:=cdr b$
  1838. while op do
  1839. <<a:=cons(max(cadr op,cadr b),cons(min(car op,car b),a))$
  1840. if (car a) neq ( cadr a) then
  1841. if dif then
  1842. <<a:='!_abb$
  1843. op:=list(1,1)>>
  1844. else dif:=t$
  1845. op:=cddr op$
  1846. b:=cddr b>>$
  1847. if not atom a then a:=reverse a$
  1848. return a % i.e. '!_abb or (fctname,min x1-der.,max x1-der.,...)
  1849. end$
  1850. symbolic procedure odeconvert(de,ford,xnew,ordr)$
  1851. begin scalar j,ford_,newco,oldde,newde,newvl,null_$
  1852. ford_:='y_$%gensym$
  1853. depl!*:=delete(assoc(ford_,depl!*),depl!*)$
  1854. depend1(ford_,xnew,t)$
  1855. oldde:=reval subst(ford_,ford,de)$
  1856. if pairp ford then % i.e. (car ford) eq 'DF then
  1857. << for j:=1:ordr do
  1858. oldde:= subst( reval list('DF,ford_,xnew,j),
  1859. reval list('DF,ford,xnew,j), oldde)>>$
  1860. algebraic !!arbconst:=0$
  1861. algebraic ( explog:= {
  1862. cot(~x) => 1/tan(x),
  1863. e**(~x+~y) => e**x*e**y,
  1864. sqrt(e)**(~x+~y) => sqrt(e)**x*sqrt(e)**y,
  1865. e**((~x+~y)/~z) => e**(x/z)*e**(y/z),
  1866. sqrt(e)**((~x+~y)/~z) => sqrt(e)**(x/z)*sqrt(e)**(y/z),
  1867. sqrt(e)**(log(~y)/~x) => y**(1/x/2),
  1868. sqrt(e)**(-log(~y)/~x) => y**(-1/x/2),
  1869. sqrt(e)**(~x*log(~y)/~z) => y**(x/z/2),
  1870. sqrt(e)**(-~x*log(~y)/~z) => y**(-x/z/2),
  1871. sqrt(e)**((~x*log(~y))/~z) => y**(x/z/2),
  1872. e**(log(~y)/~x) => y**(1/x),
  1873. e**(~x*log(~y)/~z) => y**(x/z),
  1874. e**((~x*log(~y))/~z) => y**(x/z),
  1875. int(df(~y,~x)/~y,~x) => log(y) })$
  1876. algebraic( let explog )$
  1877. newde:=algebraic first
  1878. odesolve(symbolic oldde,symbolic ford_,symbolic xnew)$
  1879. if (cadr newde neq oldde) then begin % solution found
  1880. % Test der Loesung klappt nur, wenn Loesung explizit gegeben
  1881. if cadr newde neq ford_ then
  1882. (if print_ then
  1883. <<write "Solution of the ode is not explicitly given."$
  1884. algebraic write "Equation is: ",algebraic symbolic oldde$
  1885. algebraic write "Solution is: ",algebraic symbolic newde>>)
  1886. else begin
  1887. null_:=reval reval aeval subst(caddr newde, ford_, oldde)$
  1888. % reval reval because of a REDUCE bug for special data,
  1889. % to be droped as soon as possible
  1890. if (null_ neq 0) then begin
  1891. % newde:=nil;
  1892. if print_ then begin
  1893. write "odesolve solves : "$
  1894. deprint list oldde$
  1895. write "to"$
  1896. deprint list newde$
  1897. Write "which inserted in the equation yields"$
  1898. deprint list null_$
  1899. end
  1900. end
  1901. end
  1902. end$
  1903. algebraic ( clear explog )$
  1904. depl!*:=delete(assoc(ford_,depl!*),depl!*)$
  1905. if newde then
  1906. <<newde:=list('PLUS,cadr newde,list('MINUS,caddr newde))$
  1907. if 0 = reval list('PLUS,newde,list('MINUS,oldde)) then newde:=nil>>$
  1908. return
  1909. if not newde then nil
  1910. else
  1911. <<newde:=subst(ford,ford_,newde)$
  1912. newvl:=delete(xnew,if (pairp ford and (car ford='DF))
  1913. then fctargs cadr ford
  1914. else fctargs ford)$
  1915. % if pairp ford then newvl:=delete(xnew,cdr assoc(cadr ford,depl!*))
  1916. % else newvl:=delete(xnew,cdr assoc(ford,depl!*))$
  1917. for j:=1:ordr do begin
  1918. newco:=newfct(fname_,newvl,nfct_)$
  1919. nfct_:=add1 nfct_$
  1920. fnew_:=cons(newco,fnew_)$
  1921. newde:=subst(newco,list('arbconst,j),newde)
  1922. % newde:=subst(newco, prepf !*kk2f list('arbconst,j),newde)
  1923. % newde:=reval subst(newco,list('arbconst,j),newde)
  1924. % newde:=reval subst(newco, prepf !*kk2f list('arbconst,j),newde)
  1925. end$
  1926. newde>>
  1927. end$
  1928. endmodule$
  1929. %********************************************************************
  1930. module simplifications$
  1931. %********************************************************************
  1932. % Routines for simplifications and substitution of functions
  1933. % Author: Andreas Brand
  1934. % August 1991
  1935. symbolic procedure clearfactors(sorg,ftem,vl)$
  1936. % liefert Liste der Gl. die entstehen, wenn in allen Gl. aus sorg
  1937. % gemeinsame Faktoren, die keine der Funktionen aus ftem sowie deren
  1938. % Ableitungen enthalten, gekuerzt werden
  1939. if sorg and ftem then
  1940. begin scalar l,ft$
  1941. while sorg do
  1942. <<if not zerop car sorg then
  1943. if not(ft:=smemberl(ftem,car sorg)) then l:=cons(car sorg,l)
  1944. else l:=cons(reval algsimple(reval car sorg,car ft,ft,vl),l)$
  1945. sorg:=cdr sorg>>$
  1946. return l
  1947. end
  1948. else sorg$
  1949. symbolic procedure algsimple(g,f,ftem,vl)$
  1950. % Gl. die entsteht, wenn in g gemeinsame Faktoren, die keine der Fkt.
  1951. % aus ftem sowie deren Ableitungen enthalten, gekuerzt werden
  1952. if pairp g then
  1953. begin scalar h,l$
  1954. if car g='MINUS then g:=algsimple(cadr g,f,ftem,vl)
  1955. else if car g='QUOTIENT then
  1956. g:=reval aeval list('QUOTIENT,algsimple(cadr g,f,ftem,vl),
  1957. algsimple(caddr g,f,ftem,vl))
  1958. else
  1959. <<h:=ftem$
  1960. if pairp g and (car g='PLUS) and (pairp cadr g) and (caadr g='MINUS)
  1961. then g:=reval list('MINUS,g)$
  1962. if freeof(g,f) then
  1963. <<f:=nil$
  1964. while h do
  1965. if not freeof(g,car h) then <<f:=car h$h:=nil>>
  1966. else h:=cdr h>>$
  1967. if f then
  1968. <<l:=lderiv2(g,f,fctargs f)$
  1969. h:=car reverse cdr reval list('COEFF,g,reval car l)$
  1970. %highest coefficient
  1971. if lowpow!*>1 then
  1972. g:=reval list('QUOTIENT,g,list('EXPT,car l,lowpow!*-1))$
  1973. if not zerop h then
  1974. if pairp h then
  1975. <<h:=independpart(reval list('GCD,g,h),ftem,vl)$
  1976. if not zerop h then g:=reval list('QUOTIENT,g,h)>>
  1977. else g:=reval list('QUOTIENT,g,list('GCD,g,h))>>
  1978. >>$
  1979. return g
  1980. end
  1981. else if zerop g then 0
  1982. else if freeof(ftem,g) then 1
  1983. else g$
  1984. symbolic procedure lcasepossible(l,vl)$
  1985. begin scalar l1$
  1986. for each a in l do l1:=union(list casepossible(a,vl),l1)$
  1987. return delete('NIL,l1)
  1988. end$
  1989. symbolic procedure casepossible(a,vl)$
  1990. if pairp a then
  1991. if (car a='QUOTIENT) or (car a='EXPT) or (car a='MINUS) then
  1992. casepossible(cadr a,vl)
  1993. else
  1994. if car a='TIMES then begin scalar l$
  1995. return if (l:=lcasepossible(cdr a,vl)) then reval cons('TIMES,l)
  1996. end
  1997. else if setdiff(idlist a,append(idlist vl,REDUCEFUNCTIONS_)) then a
  1998. else if setdiff(idlist a,append(idlist vl,REDUCEFUNCTIONS_)) then a$
  1999. symbolic procedure casecheck(p,vl)$
  2000. begin scalar a$
  2001. if (a:=casepossible(p,vl)) and not member(a,special_cases) then
  2002. <<special_cases:=cons(a,special_cases)$
  2003. ineq_:=union(list a,ineq_)$
  2004. if print_ then
  2005. <<terpri()$write "Special case to be considered : "$
  2006. deprint list a>> >>$
  2007. return a
  2008. end$
  2009. symbolic procedure independpart(g,ftem,vl)$
  2010. % determines factors not depending on functions in ftem
  2011. begin scalar l,l1$
  2012. g:=cdr reval list('FACTORIZE,g)$
  2013. while g do
  2014. <<if member(car g,cdr g) or member(car g,ineq_)
  2015. then l:=cons(car g,l)
  2016. else l1:=cons(car g,l1)$
  2017. g:=cdr g>>$
  2018. for each x in l1 do
  2019. if not smemberl(ftem,x) then
  2020. if not casecheck(x,vl) or not sp_cases then l:=cons(x,l)$
  2021. return if l then if cdr l then cons('TIMES,l)
  2022. else car l
  2023. else 1
  2024. end$
  2025. symbolic procedure splitde(p,ftem)$
  2026. begin scalar l$
  2027. if pairp p and (car p='QUOTIENT) then p:=cadr p$
  2028. for each x in cdr reval list('FACTORIZE,p) do
  2029. if smemberl(ftem,x) then l:=cons(reval x,l)$
  2030. return if length l>1 then union(l,nil)
  2031. else nil
  2032. end$
  2033. symbolic procedure simplifyde(a,ftem,vl,genflag)$
  2034. begin scalar l,f,p$
  2035. ftem:=smemberl(ftem,a)$
  2036. if f:=fctchoose(list a,ftem) then
  2037. <<p:=reval algsimple(reval a,f,ftem,vl)$
  2038. if not p or zerop p then
  2039. <<write "***** Error in ALGSIMPLE : "$
  2040. mathprint a>>
  2041. else a:=p$
  2042. if not stardep(a,ftem,vl) then
  2043. if (l:=integratede(a,ftem,genflag)) and print_ then
  2044. if null cdr l then
  2045. <<terpri()$write "integrated equation : "$deprint(l)>>
  2046. else
  2047. <<terpri()$write "generalized integration yields ",
  2048. length l," equations : "$deprint(l)>> >>$
  2049. return if l then l
  2050. else list a
  2051. end$
  2052. symbolic procedure fctsubst(ex,fo,forg)$
  2053. % substitution of a function fo in the list forg by an expression ex
  2054. <<%if not member(fo,forg) then depl!*:=delete(assoc(fo,depl!*),depl!*)$
  2055. for each f in forg collect
  2056. if f=fo then list('EQUAL,fo,ex)
  2057. else if freeof(f,fo) then f
  2058. else reval subst(ex,fo,f)>>$
  2059. symbolic procedure substandsep(g,sorg,ftem,vlist)$
  2060. % in allen Gl. aus sorg wird die Fkt. car g durch cdr g ersetzt
  2061. begin scalar l,p,q,a$
  2062. while sorg do
  2063. <<p:=car sorg$
  2064. sorg:=cdr sorg$
  2065. if freeof(p,car g) then l:=union(list p,l)
  2066. else
  2067. <<q:=reval subst(cdr g,car g,p)$
  2068. if (ineq_:=ineqsubst(g,ftem)) then
  2069. if pairp q then
  2070. <<a:=gensep(q,smemberl(union(fnew_,ftem),q),vlist)$
  2071. if contradiction_ then l:=sorg:=nil
  2072. else l:=union(car a,l)>>
  2073. else
  2074. if q neq 0 then l:=union(list q,l)>>
  2075. >>$
  2076. return l
  2077. end$
  2078. symbolic procedure fcteval(p,ftem,vl)$
  2079. begin
  2080. if pairp p and (car p='QUOTIENT) then
  2081. <<casecheck(caddr p,vl)$
  2082. p:=cadr p>>$
  2083. return
  2084. if delength p>(if fcteval_ then fcteval_ else 0) then
  2085. (if cont_ then
  2086. if yesp("function to be evaluated ? ") then
  2087. fcteval1(p,ftem,vl))
  2088. else fcteval1(p,ftem,vl)
  2089. end$
  2090. symbolic procedure fcteval1(p,ftem,vl)$
  2091. begin scalar l,f,n,ft,a$
  2092. ft:=smemberl(ftem,p)$
  2093. n:=length varslist(p,ft,vl)$
  2094. for each x in ft do
  2095. if fctlength x>=n then
  2096. <<l:=ldiffp(p,x)$
  2097. if (null car l) and (cdr l=1) then
  2098. if freeofzero(coeffn(p,x,1),delete(x,ft)) then f:=x>>$
  2099. if f then
  2100. p:=reval list('DIFFERENCE,f,list('QUOTIENT,p,coeffn(p,f,1)))$
  2101. return if f then cons(p,f)
  2102. else nil$
  2103. end$
  2104. symbolic procedure freeofzero(p,ft)$
  2105. % liefert t, falls p nicht 0 wird
  2106. if null ft then t
  2107. else if freeof(p,car ft) then freeofzero(p,cdr ft)
  2108. else
  2109. begin scalar a$
  2110. p:=cdr reval list('FACTORIZE,p)$
  2111. while p do
  2112. if null smemberl(ft,car p) or member(car p,ineq_) then p:=cdr p
  2113. else <<p:=nil$
  2114. a:=t>>$
  2115. return (null a)
  2116. end$
  2117. symbolic procedure fctevalstrict(a,ftem,vl)$
  2118. % fcteval with additional condition
  2119. % substituted expr. contains only functions of less arguments
  2120. % than the function
  2121. begin scalar l,n,ft$
  2122. l:=fcteval(a,ftem,vl)$
  2123. if l then
  2124. <<ft:=smemberl(ftem,car l)$
  2125. n:=for each f in ft collect length fctargs f$
  2126. if not (reval cons('MAX,n)<length fctargs cdr l) then l:=nil>>$
  2127. return l$
  2128. end$
  2129. endmodule$
  2130. %********************************************************************
  2131. module utilities$
  2132. %********************************************************************
  2133. % Routines for finding leading derivatives and others
  2134. % Author: Andreas Brand
  2135. % June 1990
  2136. symbolic procedure diffrel(p,q,v)$
  2137. % liefert komplizierteren Differentialausdruck$
  2138. if diffrelp(p,q,v) then q
  2139. else p$
  2140. symbolic procedure diffrelp(p,q,v)$
  2141. % liefert q, falls p einfacherer Differentialausdruck, sonst nil
  2142. % p, q Paare (liste.power), v Liste der Variablen
  2143. % liste Liste aus Var. und Ordn. der Ableit. in Diff.ausdr.,
  2144. % power Potenz des Differentialausdrucks
  2145. if null v then % alle Variable untersucht ?
  2146. if cdr p>cdr q then nil
  2147. else t
  2148. else begin
  2149. scalar a,b$
  2150. a:=diffdeg(car p, car v)$ % Ordnung der Ableitung nach
  2151. b:=diffdeg(car q,car v)$ % der ersten Variablen
  2152. return if a<b then t
  2153. else if b<a then nil
  2154. else diffrelp(p,q,cdr v) % falls Ableitungen
  2155. % erste Variable gleich, dann
  2156. % restliche Variablen
  2157. end$
  2158. symbolic procedure diffdeg(p,v)$
  2159. % liefert Ordnung der Ableitung von p nach v$
  2160. % p Liste Varible+Ordnung der Ableitung, v Variable (Atom)
  2161. if null p then 0 % alle Variable bearbeitet ?
  2162. else if car p=v then % v naechste Variable ?
  2163. if cdr p then
  2164. if numberp(cadr p) then cadr p % folgt eine Zahl ?
  2165. else 1
  2166. else 1
  2167. else diffdeg(cdr p,v)$ % weitersuchen
  2168. symbolic procedure ldiff(p,f)$
  2169. % Suchen der fuehrenden Ableitung der Fkt. f(arg1.,...,argn) in p
  2170. % p Ausdruck in Listenform,f Funktion in listenform
  2171. % Ergebnis: (p,(liste.power))$ liste: Liste der Ordn. der Ableitungen
  2172. begin scalar l$
  2173. l:=ldiffp(p,f)$ % fuerende Liste mit Potenz
  2174. return cons(ldiff1(car l,fctargs f),cdr l)$
  2175. % aus Liste Variablen + Ordnung
  2176. % wird Liste der Ordnungen
  2177. end$
  2178. symbolic operator fargs$
  2179. symbolic procedure fargs f$
  2180. cons('LIST,fctargs f)$
  2181. symbolic procedure fctargs f$
  2182. % arguments of a function
  2183. %if pairp f then cdr f$
  2184. if (f:=assoc(f,depl!*)) then cdr f$
  2185. symbolic procedure fctlength f$
  2186. % number of arguments
  2187. length fctargs f$
  2188. symbolic procedure argset(ftem)$
  2189. % List of arguments of all functions in ftem
  2190. if ftem then union(reverse fctargs car ftem,argset(cdr ftem))
  2191. else nil$
  2192. symbolic procedure ldiff1(l,v)$
  2193. % liefert Liste der Ordnungen der Ableitungen nach den Variablen aus v
  2194. % l Liste (Variable + Ordnung)$ v Liste der Variablen
  2195. if null v then nil % alle Variable abgearbeitet ?
  2196. else cons(diffdeg(l,car v),ldiff1(l,cdr v))$
  2197. % Ordnung der Ableitung nach
  2198. % erster Variable anhaengen
  2199. symbolic procedure ldiffp(p,f)$
  2200. % liefert Liste der Variablen + Ordnungen mit Potenz
  2201. % p Ausdruck in LISP - Notation, f Funktion
  2202. ldiffp1(p,f,fctargs f)$
  2203. symbolic procedure ldiffp1(p,f,vl)$
  2204. % liefert Liste der Variablen + Ordnungen mit Potenz
  2205. % p Ausdruck in LISP - Notation, f Funktion, lv Variablenliste
  2206. begin scalar a$
  2207. a:=cons(nil,0)$
  2208. if not atom p then
  2209. if member(car p,list('EXPT,'PLUS,'MINUS,'TIMES,'QUOTIENT,'DF,'EQUAL))
  2210. then
  2211. % erlaubte Funktionen
  2212. <<if (car p='PLUS) or (car p='TIMES) or (car p='QUOTIENT)
  2213. or (car p='EQUAL) then
  2214. <<p:=cdr p$
  2215. while p do
  2216. <<a:=diffrel(ldiffp1(car p,f,vl),a,vl)$
  2217. p:=cdr p>> >>
  2218. else if car p='MINUS then
  2219. a:=ldiffp1(cadr p,f,vl)
  2220. else if car p='EXPT then % Exponent
  2221. if numberp caddr p then
  2222. <<a:=ldiffp1(cadr p,f,vl)$
  2223. % fuehrende Abl. aus der Basis
  2224. a:=cons(car a,times(caddr p,cdr a))>>
  2225. else a:=cons(nil,0)
  2226. % Poetenz aus Basis wird mit
  2227. % Potenz multipliziert
  2228. else if car p='DF then % Ableitung
  2229. if cadr p=f then a:=cons(cddr p,1)
  2230. % f wird differenziert?
  2231. else a:=cons(nil,0)>> % sonst Konstante bzgl. f
  2232. else if p=f then a:=cons(nil,1)
  2233. % Funktion selbst
  2234. else a:=cons(nil,0) % alle uebrigen Fkt. werden wie
  2235. else if p=f then a:=cons(nil,1)$ % Konstante behandelt
  2236. return a
  2237. end$
  2238. symbolic procedure lderiv(p,f)$
  2239. % fuehrende Ableitung in LISP-Notation ohne Potenz
  2240. lderiv1(p,f,fctargs f)$
  2241. symbolic procedure lderiv1(p,f,vl)$
  2242. % fuerende Ableitung in LISP-Notation ohne Potenz
  2243. % mit Angabe der Rangfolge der Variablen
  2244. begin scalar l$
  2245. l:=ldiffp1(p,f,vl)$
  2246. return if car l then cons('DF,cons(f,car l))
  2247. else if zerop cdr l then nil
  2248. else f
  2249. end$
  2250. symbolic procedure lderiv2(p,f,vl)$
  2251. % fuehrende Ableitung in LISP-Notation mit Potenz (als dotted pair)
  2252. begin scalar l$
  2253. l:=ldiffp1(p,f,vl)$
  2254. return cons(if car l then cons('DF,cons(f,car l))
  2255. else if zerop cdr l then nil
  2256. else f
  2257. ,cdr l)
  2258. end$
  2259. symbolic procedure highdiff(p,f,x)$
  2260. % hoechste Ableitung einer Funktion f nach der Variable x
  2261. % in einem Ausdruck p
  2262. % p,f in LISP-Notation, x Atom
  2263. diffdeg(car ldiffp1(p,f,list x),x)$
  2264. symbolic procedure minausd(p,q)$
  2265. % minimalen Differentialausdruck suchen$
  2266. % p,q, Ausdr. in Listenform mit fuehrender Ableitung + Potenz
  2267. % zur Berechnung wird nur fuehrender Ableitung + Potenz benutzt
  2268. if minausdp1(cadr p,cddr p,cadr q,cddr q) then p
  2269. else q$
  2270. symbolic procedure minausdsp(p,q)$
  2271. % falls p minimaler Diff.ausdr. und p nicht laenger als q, p sonst nil
  2272. % p,q, Ausdr. in Listenform mit fuerender Ableitung und Potenz
  2273. % benutzt wird nur fuerende Ableitung und Potenz
  2274. begin scalar s$
  2275. s:=minausdp1(cadr p,cddr p,cadr q,cddr q)$
  2276. return if s then if s='EQUAL!= then % falls die Ausdruecke gleich
  2277. % schwierig sind,
  2278. if shorter(car p,car q) then p
  2279. else nil
  2280. % geht auch die Laenge ein
  2281. else p
  2282. else nil
  2283. end$
  2284. symbolic procedure minausdp(p,q)$
  2285. % falls p minimaler Differentialausdruck, p sonst nil
  2286. % p,q, Ausdr. in Listenform mit fuehrender Ableitung und Potenz
  2287. % benutzt wird nur fuerende Ableitung und Potenz
  2288. begin scalar j,k$
  2289. return if minausdp1(cadr p,cddr p,cadr q,cddr q) then p
  2290. else nil$
  2291. end$
  2292. symbolic procedure minausdp1(l1,p1,l2,p2)$
  2293. % liefert t, wenn der erste von zwei Differentialausdr. echt einfacher,
  2294. % 'EQUAL!=, wenn sie gleich schwierig sind, sonst nil
  2295. % l1,l2 Listen der Ordnungen der Ableit., p1,p2 Potenzen
  2296. if null l1 then % Ordnungen gleich ?
  2297. if p1=p2 then 'EQUAL!=
  2298. % Potenzen gleich ?
  2299. else p1<p2
  2300. else if null l2 then nil % darf eigentlich nicht sein
  2301. else if car l1<car l2 then t % Ordn. der 1. Var. kleiner ?
  2302. else if car l1>car l2 then nil
  2303. % Ordn. der 1. Var. groeaer ?
  2304. else minausdp1(cdr l1,p1,cdr l2,p2)$
  2305. % restliche Variable testen
  2306. symbolic procedure difdiff(r,s)$
  2307. % liefert Liste der Differenzen der Elemente zweier Listen
  2308. if null r then nil
  2309. else cons (car r-car s,difdiff(cdr r,cdr s))$
  2310. symbolic procedure mkldiff(f,l)$
  2311. % erzeugt die Ableitung der Funktion f nach
  2312. % den Variablen (einschliesslich Ordnungen) aus der Liste l
  2313. cons('DF,cons(f,difflist(fctargs f,l)))$
  2314. symbolic procedure difflist(v,l)$
  2315. % erzeugt aus der Liste der Variablen und der Liste der Ordnungen der
  2316. % Ableitungen eine Liste von Variablen + Ordnungen
  2317. if null v then nil
  2318. else if car l=0 then difflist(cdr v,cdr l)
  2319. % Ordnung 0
  2320. else if car l=1 then cons(car v,difflist(cdr v,cdr l))
  2321. % bei Ordnung 1 wird Variable
  2322. % ohne Ordnung angehaengt
  2323. else cons(car v,cons(car l,difflist(cdr v,cdr l)))$
  2324. symbolic procedure delength(d)$
  2325. % Laenge eines Polynoms in LISP - Notation
  2326. if not pairp d then if d then 1
  2327. else 0
  2328. else
  2329. if car d='PLUS then length(d)-1 % Laenge in LISP ohne PLUS
  2330. else if car d='EQUAL then delength(cadr d)+delength(caddr d)
  2331. else if car d='QUOTIENT then delength(cadr d)
  2332. else 1$
  2333. symbolic procedure shorter(a,b)$
  2334. delength a<=delength b$
  2335. symbolic procedure desort(l)$
  2336. % list sorting
  2337. begin scalar l1,l2,l3,m,n$
  2338. return
  2339. if null l then nil
  2340. else
  2341. <<n:=delength car l$
  2342. l2:=list car l$
  2343. l:=cdr l$
  2344. while l do
  2345. <<m:=delength car l$
  2346. if m<n then l1:=cons(car l,l1)
  2347. else if m>n then l3:=cons(car l,l3)
  2348. else l2:=cons(car l,l2)$
  2349. l:=cdr l>>$
  2350. append(desort(l1),append(l2,desort(l3)))>>
  2351. end$
  2352. symbolic procedure smemberl(fl,ex)$
  2353. if fl and ex then
  2354. if smember(car fl,ex) then cons(car fl,smemberl(cdr fl,ex))
  2355. else smemberl(cdr fl,ex)$
  2356. symbolic procedure fctsort(l)$
  2357. % list sorting
  2358. begin scalar l1,l2,l3,m,n$
  2359. return
  2360. if null l then nil
  2361. else
  2362. <<n:=fctlength car l$
  2363. l2:=list car l$
  2364. l:=cdr l$
  2365. while l do
  2366. <<m:=fctlength car l$
  2367. if m<n then l1:=cons(car l,l1)
  2368. else if m>n then l3:=cons(car l,l3)
  2369. else l2:=cons(car l,l2)$
  2370. l:=cdr l>>$
  2371. append(fctsort(l1),append(l2,fctsort(l3)))>>
  2372. end$
  2373. symbolic procedure fctprint(fl)$
  2374. % Ausdrucken der Funktionen aus fl
  2375. begin scalar n,l$
  2376. n:=0$
  2377. for each f in fl do
  2378. if pairp f then
  2379. if car f='EQUAL then
  2380. <<n:=delength reval f$
  2381. if n>print_ then
  2382. <<terpri()$write cadr f,"= expr. with ",n," terms"$terpri()>>
  2383. else mathprint f$
  2384. n:=0>>
  2385. else
  2386. <<if n eq 5 then
  2387. <<terpri()$n:=0>>$
  2388. write car f$
  2389. if pairp cdr f then
  2390. <<write "("$write cadr f$
  2391. for each v in cddr f do
  2392. <<write ","$write v>>$
  2393. write ") ">>
  2394. else
  2395. <<write car f$
  2396. write " ">>$
  2397. n:=add1 n>>
  2398. else
  2399. <<if n eq 5 then
  2400. <<terpri()$n:=0>>$
  2401. write f$
  2402. if (l:=fctargs f) then
  2403. <<write "("$write car l$
  2404. for each v in cdr l do write ",",v$
  2405. write ")">>$
  2406. write " "$
  2407. n:=add1 n>>$
  2408. %if n neq 0 then terpri()
  2409. end$
  2410. symbolic procedure eqprint(e)$
  2411. % Ausdrucken der Gl. e
  2412. if print_ then
  2413. begin scalar n$
  2414. n:=delength reval e$
  2415. if n>print_ then
  2416. <<write "expr. with "$write n$write " terms"$terpri()>>
  2417. else
  2418. mathprint e$
  2419. end$
  2420. symbolic procedure substprint(a,b)$
  2421. if print_ then
  2422. begin scalar n$
  2423. n:=delength reval b$
  2424. if n>print_ then <<fctprint list a$write "= expr. with ",n," terms"$
  2425. terpri()>>
  2426. else mathprint list('EQUAL,a,b)
  2427. end$
  2428. symbolic procedure deprint(l)$
  2429. % Ausdrucken der Gl. aus der Liste l
  2430. if l and print_ then for each x in l do eqprint(list('EQUAL,0,x))$
  2431. symbolic procedure powappend(l,f)$
  2432. % Anhaengen der fuehrenden Ableitung
  2433. if null l then nil
  2434. else cons(cons(car l,ldiff(car l,f)),powappend(cdr l,f))$
  2435. symbolic procedure powdelete(l)$
  2436. % Loeschen der fuehrenden Ableitung
  2437. if null l then nil
  2438. else cons(caar l,powdelete(cdr l))$
  2439. symbolic procedure fctdepend(e,v,fctset)$
  2440. % Test,ob variable v im Ausdruck e nicht in Abhaeng. von
  2441. % Fkt. aus fctset vorkommt
  2442. if member(v,argset smemberl(fctset,e)) then t
  2443. else freeof(e,v) $
  2444. symbolic procedure subset(a,b)$
  2445. % test,ob a Teilmenge von b ist
  2446. if null a then t
  2447. else if member(car a,b) then subset(cdr a,b)
  2448. else nil$
  2449. symbolic procedure idlist(l)$
  2450. if pairp l then union(idlist car l,idlist cdr l)
  2451. else if l and idp l then list l
  2452. else nil$
  2453. symbolic procedure varapp(l,a,v1,v2)$
  2454. % an jede Gl. aus l werden v1 und v2 angehaengt
  2455. if null l then nil
  2456. else
  2457. cons(list(cons(cons(caar l,a),cdar l),v1,v2),varapp(cdr l,a,v1,v2))$
  2458. symbolic procedure varslist(p,ftem,vl)$
  2459. begin scalar l$
  2460. ftem:=argset smemberl(ftem,p)$
  2461. for each v in vl do
  2462. if not freeof(p,v) or member(v,ftem) then l:=cons(v,l)$
  2463. return reverse l$
  2464. end$
  2465. symbolic procedure newfct(id,l,nfct)$
  2466. begin scalar f$
  2467. f:=mkid(id,nfct)$
  2468. depl!*:=delete(assoc(f,depl!*),depl!*)$
  2469. %put(f,'simpfn,'simpiden)$
  2470. %if pairp l then f:=cons(f,l)$
  2471. if pairp l then depl!*:=cons(cons(f,l),depl!*)$
  2472. if print_ then
  2473. <<terpri()$
  2474. if pairp l then
  2475. <<write "new function: "$
  2476. fctprint list f>>
  2477. else
  2478. write "new constant: ",f>>$
  2479. return f$
  2480. end$
  2481. symbolic procedure equallist(forg)$
  2482. % List of all members of forg which are pairs
  2483. if forg then
  2484. if pairp car forg then cons(car forg,equallist cdr forg)
  2485. else equallist cdr forg$
  2486. symbolic procedure spmin(a,b)$
  2487. if null a then b
  2488. else if null b then a
  2489. else if cadr a<cadr b then a
  2490. else b$
  2491. symbolic procedure specons(a,l)$
  2492. if freeof(l,car a) then cons(car a,cons(cadr a,l))
  2493. else specons1(a,l)$
  2494. symbolic procedure specons1(a,l)$
  2495. if null l then nil
  2496. else if car l=car a then
  2497. if cadr l<cadr a then cons(car a,cons(cadr a,cddr l))
  2498. else l
  2499. else cons(car l,cons(cadr l,specons1(a,cddr l)))$
  2500. symbolic procedure polyp(p,ftem)$
  2501. begin scalar a$
  2502. a:=t$
  2503. while ftem do
  2504. if polyp1(p,car ftem) then ftem:=cdr ftem
  2505. else
  2506. <<terpri()$
  2507. write "***** This equation is not a polynomial w.r.t. "$
  2508. write car ftem$write " and its derivatives : "$
  2509. deprint(list p)$
  2510. ftem:=nil$
  2511. a:=nil>>$
  2512. return a
  2513. end$
  2514. symbolic procedure polyp1(p,f)$
  2515. % prueft, ob p f nur in polynomialer Form enthaelt
  2516. if freeof(p,f) then t
  2517. else
  2518. begin scalar a$
  2519. if atom p then a:=t
  2520. else
  2521. if member(car p,list('EXPT,'PLUS,'MINUS,'TIMES,'QUOTIENT,'DF)) then
  2522. % erlaubte Funktionen
  2523. <<if (car p='PLUS) or (car p='TIMES) then
  2524. <<p:=cdr p$
  2525. while p do
  2526. if a:=polyp1(car p,f) then p:=cdr p
  2527. else p:=nil>>
  2528. else if (car p='MINUS) then
  2529. a:=polyp1(cadr p,f)
  2530. else if (car p='QUOTIENT) then
  2531. <<if freeof(caddr p,f) then a:=polyp1(cadr p,f)>>
  2532. else if car p='EXPT then % Exponent
  2533. <<if (fixp caddr p) then
  2534. if caddr p>0 then a:=polyp1(cadr p,f)>>
  2535. else if car p='DF then % Ableitung
  2536. if (cadr p=f) or freeof(cadr p,f) then a:=t>>
  2537. else a:=(p=f)$
  2538. return a
  2539. end$
  2540. symbolic operator rationalexp$
  2541. symbolic procedure rationalexp(p,ftem)$
  2542. ratexp(p,cdr ftem)$
  2543. lisp flag('(rationalexp),'BOOLEAN)$
  2544. symbolic procedure ratexp(p,ftem)$
  2545. if null ftem then t
  2546. else if ratexp1(p,car ftem) then ratexp(p,cdr ftem)
  2547. else nil$
  2548. symbolic procedure ratexp1(p,f)$
  2549. % prueft, ob p f nur in rationaler Form enthaelt
  2550. if not pairp p or freeof(p,f) then t
  2551. else if car p='QUOTIENT then polyp1(cadr p,f) and polyp1(caddr p,f)
  2552. else polyp1(p,f)$
  2553. %symbolic procedure freeof(u,v)$
  2554. %not(smember(v,u)) and freeofdepl(depl!*,u,v)$
  2555. symbolic procedure freeofdepl(de,u,v)$
  2556. if null de then t
  2557. else if smember(v,cdar de) and smember(caar de,u) then nil
  2558. else freeofdepl(cdr de,u,v)$
  2559. symbolic procedure freeoflist(l,m)$
  2560. % liefert t, falls kein Element aus m in l auftritt
  2561. if null m then t
  2562. else if freeof(l,car m) then freeoflist(l,cdr m)
  2563. else nil$
  2564. endmodule$
  2565. %********************************************************************
  2566. module dfint; % Patch to improve symbolic differentiation,
  2567. % mainly of integrals.
  2568. % Author: Francis J. Wright <F.J.Wright@QMW.ac.uk>
  2569. % QMW, London and CBPF, Rio.
  2570. % Date: Thu Nov 19 21:11:12 1992
  2571. % REDUCE version: 3.4.1 (ONLY); PSL
  2572. % Beta test version
  2573. % 19 June 1992: Preliminary alpha test version (for CRACK)
  2574. % 28 Oct 1992: !*k2q -> !*kk2q to avoid non-unique kernels
  2575. % But maybe it should be done as in diffp instead?
  2576. % 7 Nov 1992: Allowdfint mode added; completely revised REDUCE 3.4.1
  2577. % version
  2578. % DOCUMENTATION
  2579. % =============
  2580. % This patch has several functions: for examples see the test and
  2581. % demonstration file DFINT.TST.
  2582. % Let A, B, C, D be arbitrary SEQUENCES of kernels.
  2583. % 1. REDUCE commutes the order of differentiations so as to collect
  2584. % differentiation variables, but it misses the commutation that would
  2585. % simplify any expression equivalent to df(y, A, y, B) to zero (unless
  2586. % A is absent). A one-line patch to procedure diffp (below) fixes
  2587. % this. This simplification must surely ALWAYS be correct and
  2588. % desirable (since REDUCE commutes differentiations), and is very
  2589. % cheap to include, so it is ALWAYS performed.
  2590. % 2. However, the main purpose of this patch is to differentiate
  2591. % integrals (hence the name DFINT) in a controlled manner. This is
  2592. % implemented for single derivatives and differentiation wrt the first
  2593. % variable in multiple derivatives via the new main procedure
  2594. % dfform_int, together with a patch to the existing procedure diffp
  2595. % (below) to deal with differentiation wrt later variables in multiple
  2596. % derivatives.
  2597. % It is not possible in general in REDUCE to perform any of these
  2598. % simplifications by pattern matching because of the arbitrary number
  2599. % of arguments. In particular, this patch makes redundant the
  2600. % following specific rule defined in INT.RED:
  2601. % put('df,'opmtch,'(((int !=y !=x) !=x) (nil . t) (evl!* !=y) nil) .
  2602. % get('df,'opmtch));
  2603. % This is equivalent (but NOT identical) to the algebraic command
  2604. % for all y,x let df(int(y,x), x) = y;
  2605. % which could therefore be cleared - see DFINT.TST. However, leaving
  2606. % it effective should not matter. The code here to replace this rule
  2607. % is not NECESSARY, but seems desirable since the code has to check
  2608. % for differentiation of an integral anyway.
  2609. % The precise operation of the new facility to differentiate integrals
  2610. % is as follows:
  2611. % (a). Differentiation wrt the integration variable:
  2612. % df(int(F(A,x,B),x),C,x,D), or any equivalent composition of
  2613. % derivatives applied to one integral, is ALWAYS simplified to
  2614. % df(F(A,x,B),C,D).
  2615. % (b). Differentiation wrt a parameter of the integrand:
  2616. % If the switch ALLOWDFINT is turned on (it is ON by default) then "df
  2617. % int" will be commuted into "int df" IF THIS SIMPLIFIES THE
  2618. % INTEGRAND, meaning currently that the new integrand is not a
  2619. % symbolic derivative. Thus differentiation under the integral sign
  2620. % will be performed so that df(int(F(A,x,B),x),C,y,D) simplifies to
  2621. % df(int(F_y(A,x,B),x),C,D) if F_y = dF/dy simplifies. It think this
  2622. % is normally desirable.
  2623. % If the switch DFINT is turned on (it is OFF by default) then the
  2624. % commutation is ALWAYS performed. Thus df(int(F(A,x,B),x),C,y,D)
  2625. % ALWAYS evaluates to int(df(F(A,x,B),C,y,D),x). I think this will
  2626. % not normally be desirable, although for special purposes it is.
  2627. % If used together with either Herbert Melenk's patch or mine (called
  2628. % intpatch) that allow integrands to be implicitly dependent on the
  2629. % integration variable, this code is intended to also work with such
  2630. % dependent integrands, rather than only with explicit operators as
  2631. % illustrated above. For examples see the end of the test and
  2632. % demonstration file DFINT.TST.
  2633. % This file is intended to be compiled using faslout and then loaded
  2634. % using load_package, but alternatively the source code can be input
  2635. % when required and either compiled or interpreted. It could also be
  2636. % edited into the standard source file POLY.RED and built permanently
  2637. % into REDUCE.
  2638. % ** WARNING ** To use this patch with REDUCE 3.4 the new procedures
  2639. % called by diffp in 3.4.1 need to be supplied, or the end of diffp
  2640. % changed back to its 3.4 form.
  2641. switch allowdfint, dfint; % dfint OFF by default
  2642. deflist('((allowdfint ((t (rmsubs)))) (dfint ((t (rmsubs))))), 'simpfg);
  2643. % There is no code to reverse the df-int commutation,
  2644. % so no reason to call rmsubs when the switch is turned off.
  2645. % on allowdfint; % But would be done when INput rather than LOADed!
  2646. !*allowdfint := t; rmsubs(); % allowdfint ON by default
  2647. !*dfint:=t;
  2648. put('int, 'dfform, 'dfform_int);
  2649. % dfform is a new hook, otherwise used only by taylor (I think).
  2650. % This code does not necessarily need to use this hook,
  2651. % but it needs to be called as an alternative to diffp so
  2652. % that the linearity of differentiation has already been applied.
  2653. symbolic procedure dfform_int(u, v, n);
  2654. % Simplify a SINGLE derivative of an integral.
  2655. % u = '(int y x) [as main variable of SQ form]
  2656. % v = kernel
  2657. % n = integer power
  2658. % Return SQ form of df(u**n, v) = n*u**(n-1)*df(u, v)
  2659. % This routine is called by diffp via the hook
  2660. % if x := get(car u,'dfform) then return apply3(x,u,v,n)
  2661. begin scalar result, x, y;
  2662. y := simp!* cadr u; % SQ form integrand
  2663. x := caddr u; % kernel
  2664. result :=
  2665. if v eq x then y
  2666. % df(int(y,x), x) -> y replacing the let rule in INT.RED
  2667. else if (!*allowdfint or !*dfint) and << y := diffsq(y, v);
  2668. !*dfint or not_df_p y % it has simplified
  2669. >> then simp{'int, mk!*sq y, x} % MUST re-simplify it!!!
  2670. % i.e. differentiate under the integral sign
  2671. % df(int(y, x), v) -> int(df(y, v), x).
  2672. % (Perhaps I should use prepsq - kernels are normally
  2673. % true prefix?)
  2674. else !*kk2q{'df, u, v}; % remain unchanged
  2675. if not(n eq 1) then
  2676. result := multsq( (((u .** (n-1)) .* n) .+ nil) ./ 1, result);
  2677. return result
  2678. end;
  2679. symbolic procedure not_df_p y;
  2680. % True if the SQ form y is not a df kernel.
  2681. not(denr y eq 1 and
  2682. not domainp (y := numr y) and eqcar(mvar y, 'df));
  2683. % Author: Anthony C. Hearn.
  2684. % Copyright (c) 1991 RAND. All rights reserved.
  2685. % Modifications by Francis J. Wright, QMW, London and CBPF, Rio
  2686. % (clearly flagged -- search for FJW).
  2687. % This procedure is from the REDUCE 3.4.1 module poly in file POLY.RED
  2688. % and is a little different from the 3.4 version! It needs a minor
  2689. % addition to improve the simplification of MULTIPLE derivatives.
  2690. % Note that in PSL-REDUCE POLY is compiled into the base system, so
  2691. % this procedure is always defined and can safely be re-defined.
  2692. % Under other Lisps this may not be true, so BEWARE!!!
  2693. symbolic procedure diffp(u,v);
  2694. % U is a standard power, V a kernel.
  2695. % Value is the standard quotient derivative of U wrt V.
  2696. begin scalar n,w,x,y,z; integer m;
  2697. n := cdr u; % integer power.
  2698. u := car u; % main variable.
  2699. if u eq v and (w := 1 ./ 1) then go to e
  2700. else if atom u then go to f
  2701. %else if (x := assoc(u,dsubl!*)) and (x := atsoc(v,cdr x))
  2702. % and (w := cdr x) then go to e % deriv known.
  2703. % DSUBL!* not used for now.
  2704. else if (not atom car u and (w:= difff(u,v)))
  2705. or (car u eq '!*sq and (w:= diffsq(cadr u,v)))
  2706. then go to c % extended kernel found.
  2707. else if x := get(car u,'dfform) then return apply3(x,u,v,n)
  2708. else if x:= get(car u,'dfn) then nil
  2709. else if car u eq 'plus and (w := diffsq(simp u,v))
  2710. then go to c
  2711. else go to h; % unknown derivative.
  2712. y := x;
  2713. z := cdr u;
  2714. a: w := diffsq(simp car z,v) . w;
  2715. if caar w and null car y then go to h; % unknown deriv.
  2716. y := cdr y;
  2717. z := cdr z;
  2718. if z and y then go to a
  2719. else if z or y then go to h; % arguments do not match.
  2720. y := reverse w;
  2721. z := cdr u;
  2722. w := nil ./ 1;
  2723. b: % computation of kernel derivative.
  2724. if caar y
  2725. then w := addsq(multsq(car y,simp subla(pair(caar x,z),
  2726. cdar x)),
  2727. w);
  2728. x := cdr x;
  2729. y := cdr y;
  2730. if y then go to b;
  2731. c: % save calculated deriv in case it is used again.
  2732. % if x := atsoc(u,dsubl!*) then go to d
  2733. % else x := u . nil;
  2734. % dsubl!* := x . dsubl!*;
  2735. % d: rplacd(x,xadd(v . w,cdr x,t));
  2736. e: % allowance for power.
  2737. % first check to see if kernel has weight.
  2738. if (x := atsoc(u,wtl!*))
  2739. then w := multpq('k!* .** (-cdr x),w);
  2740. m := n-1;
  2741. % Evaluation is far more efficient if results are rationalized.
  2742. return rationalizesq if n=1 then w
  2743. else if flagp(dmode!*,'convert)
  2744. and null(n := int!-equiv!-chk
  2745. apply1(get(dmode!*,'i2d),n))
  2746. then nil ./ 1
  2747. else multsq(!*t2q((u .** m) .* n),w);
  2748. f: % Check for possible unused substitution rule.
  2749. if not depends(u,v)
  2750. and (not (x:= atsoc(u,powlis!*))
  2751. or not depends(cadddr x,v))
  2752. then return nil ./ 1;
  2753. w := list('df,u,v);
  2754. go to j;
  2755. h: % Final check for possible kernel deriv.
  2756. if car u eq 'df
  2757. then if depends(cadr u,v)
  2758. %% BEGIN addition to 3.4.1 version by FJW
  2759. and not(cadr u eq v) then
  2760. % (df (df v A) v) ==> 0
  2761. << if eqcar(cadr u, 'int) then
  2762. % (df (df (int F x) A) v) ==> (df (df (int F x) v) A) ?
  2763. % Commute the derivatives to differentiate the integral?
  2764. if caddr cadr u eq v then
  2765. % Evaluating (df u v) where u = (df (int F v) A)
  2766. % Just return (df F A) - derivative absorbed
  2767. << w := 'df . cadr cadr u . cddr u; go to j >>
  2768. else if !*allowdfint and
  2769. % Evaluating (df u v) where u = (df (int F x) A)
  2770. % Commute only if the result simplifies:
  2771. not_df_p(w := diffsq(simp!* cadr cadr u, v))
  2772. then <<
  2773. % Generally must re-evaluate the integral (carefully!)
  2774. w := aeval{'int, mk!*sq w, caddr cadr u} . cddr u;
  2775. go to j >>; % derivative absorbed
  2776. %% END addition to 3.4.1 version by FJW
  2777. %% BEGIN difference from 3.4
  2778. if (x := find_sub_df(w:= cadr u . derad(v,cddr u),
  2779. get('df,'kvalue)))
  2780. then <<w := simp car x;
  2781. for each el in cdr x do
  2782. for i := 1:cdr el do
  2783. w := diffsq(w,car el);
  2784. go to e>>
  2785. else w := 'df . w
  2786. %% END difference from 3.4
  2787. >> %FJW
  2788. else return nil ./ 1
  2789. else if depends(u,v) then w := list('df,u,v)
  2790. else return nil ./ 1;
  2791. j: w := if x := opmtch w then simp x else mksq(w,1);
  2792. go to e
  2793. end;
  2794. endmodule;
  2795. module intpatch; % Integrate dependent variables & rational powers
  2796. % Author: Francis J. Wright <F.J.Wright@QMW.ac.uk>
  2797. % Date: 19 June 1992 (Very minor update 16/11/92)
  2798. % REDUCE version: 3.4 or 3.4.1; PSL
  2799. % This version (19 June 1992) fixes a bug that integrals that remained
  2800. % symbolic were not returned as unique kernels - I now use !*kk2q.
  2801. % This bug caused rather obscure symptoms, such as failures with on
  2802. % factor.
  2803. % DOCUMENTATION
  2804. % =============
  2805. % This patch has two separate functions:
  2806. % 1: It allow integrals containing IMPLICITLY dependent variables,
  2807. % created using the DEPEND command, to remain symbolic rather than
  2808. % cause an error, whilst preserving other error handling as normal.
  2809. % ON FAILHARD turns this facility off.
  2810. % This facility was developed from a patch by Herbert Melenk,
  2811. % which this patch is intended to replace.
  2812. % 2: It integrates simple rational powers of the integration
  2813. % variable that the integrator currently fails to integrate.
  2814. % This file is intended to be compiled using faslout and then loaded
  2815. % using load_package, but alternatively the source code can be input
  2816. % when required and either compiled or interpreted. It could also be
  2817. % edited into the standard source file INT.RED and built permanently
  2818. % into REDUCE.
  2819. % Because of the autoload definitions for int (see ENTRY.RED) it is
  2820. % safe to load this module before the integrator has been loaded, and
  2821. % it does not cause the integrator to load. The integrator can safely
  2822. % be AUTOLOADED by calling INT afterwards, either from algebraic mode
  2823. % or from symbolic mode using any of the methods described below, but
  2824. % MUST NOT BE EXPLICITLY LOADED AFTER this patch, otherwise this patch
  2825. % will not work because the simpfn property of int will get
  2826. % overwritten. I cannot see any solution to this, other than avoiding
  2827. % doing it!
  2828. % WARNING: To call the integrator from symbolic mode when this patch
  2829. % is loaded DO NOT CALL SIMPINT DIRECTLY. Instead, there are several
  2830. % possibilities that should work, including any of the following:
  2831. % 1. Use the form ????{'int, integrand, int_var}, where ???? is
  2832. % reval, aeval or simp, etc, depending on the form of result you want,
  2833. % and the arguments are in prefix (or pseudo-prefix) form. This is
  2834. % equivalent to calling the integrator from algebraic mode, and I
  2835. % currently think this is probably the best approach.
  2836. % 2. Call simpintpatch directly, but this is not general and so not
  2837. % recommended.
  2838. % 3. Replace calls of "simpint" by (say) "integrator", and do
  2839. % essentially the following:
  2840. % global'(integration_function);
  2841. % symbolic(integration_function := get('int, 'simpfn));
  2842. %
  2843. % symbolic procedure integrator u;
  2844. % apply1(integration_function, u);
  2845. % Note: apply1 is defined in RLISP.RED.
  2846. fluid '(!*failhard);
  2847. %% fluid '(soft!-rerror!-number);
  2848. % Hope not necessary - it seems not to be.
  2849. symbolic procedure SimpIntPatch u;
  2850. % Driver for various patches:
  2851. % 1: Catch errors from SimpInt, trap error number 7 only,
  2852. % and pass on all other errors as normal hard REDUCE errors.
  2853. % 2: Post-process unintegrated rational powers.
  2854. begin scalar r, !*usermode,!*redefmsg, !*uncached; !*uncached := t;
  2855. % !*redefmsg rebound to avoid PSL messages
  2856. % about redefinition of rerror.
  2857. %% integer soft!-rerror!-number; % defaults to 0, not nil
  2858. put('int, 'simpfn, 'SimpInt); % assumed & reset by SimpInt
  2859. copyd('rerror, 'intpatch!-rerror); % redefine rerror
  2860. r := errorset!*({'SimpInt, mkquote u}, nil);
  2861. copyd('rerror, 'rerror!%); % restore rerror
  2862. put('int, 'simpfn, 'SimpIntPatch); % reset INT interface
  2863. if pairp r then <<
  2864. % First call of SimpInt succeeded -
  2865. % try to reprocess any integrals left:
  2866. put('int, 'simpfn, 'SimpIntRatPow);
  2867. u := resimp car r; % this works ONLY with !*uncached := t;
  2868. put('int, 'simpfn, 'SimpIntPatch);
  2869. return u
  2870. >>
  2871. else if !*failhard or not(r eq 7) then
  2872. rederr EMSG!* % Error failure
  2873. else return !*kk2q('int . u) % Remain symbolic
  2874. end;
  2875. % Integrator error trap patch to allow controlled error handling
  2876. % ==============================================================
  2877. % The error numbers generated by SIMPINT and the corresponding
  2878. % error message that would be output by INT are the following,
  2879. % collected from the INT source code:
  2880. % 1 = "Improper number of arguments to INT"
  2881. % 2 = "Improper number of arguments to INT"
  2882. % 3 = "Too many arguments to INT"
  2883. % 4 = "FAILHARD switch set"
  2884. % 5 = "Invalid polynomial in int-quadterm"
  2885. % 6 = "Empty list to mapply"
  2886. % 7 = "Can't integrate in the presence of side-relations" (TRAPPED)
  2887. % 8 = "Invalid exponent"
  2888. % 9 = "FAILHARD switch set"
  2889. % If any other error number, such as 0, should occur then it
  2890. % corresponds to some other non-specific error.
  2891. symbolic procedure rerror!%(packagename,number,message);
  2892. % This is precisely the definition of rerror in RLISP.RED,
  2893. % but redefining it here makes sure it is loaded,
  2894. % and also avoids the need to save it.
  2895. % Precisely this procedure is also defined in SOFTSOLV.
  2896. rederr message;
  2897. symbolic procedure intpatch!-rerror(packagename,number,message);
  2898. %% << soft!-rerror!-number := number; error1() >>;
  2899. % The following will suffice provided errorsets
  2900. % are not nested in the integrator.
  2901. % It makes error message text available in EMSG!*.
  2902. error(number, message);
  2903. % Integrator postprocessor patch to integrate simple rational
  2904. % powers that the integrator currently fails to integrate.
  2905. % =======================================================
  2906. symbolic procedure SimpIntRatPow u; % u = (integ var)
  2907. % Integrate integrands of the form var**(m/n),
  2908. % which the integrator leaves in a rather bizarre form -
  2909. % hence the precise form of the following code.
  2910. % Returns original integral if it has the wrong form.
  2911. begin scalar integ, var, power;
  2912. integ := car u; var := cadr u;
  2913. % assumes true prefix forms, already evaluated by SimpInt.
  2914. % power := errorset!*(
  2915. % {'FindRatPow, mkquote integ, mkquote var}, nil);
  2916. % errorset!*(u,v) == errorset(u,v,!*backtrace)
  2917. % Backtrace from this is unlikely to be interesting, so ...
  2918. power := errorset(
  2919. {'FindRatPow, mkquote integ, mkquote var}, nil, nil);
  2920. if errorp power then return !*kk2q('int . u);
  2921. power := car power; % correct form of integrand found.
  2922. % integrand = var**power, so return integral:
  2923. power := reval {'plus, power, 1};
  2924. return simp!* {'quotient, {'expt, var, power}, power}
  2925. end;
  2926. symbolic procedure FindRatPow(monom, var);
  2927. % Return power of a monomial in var, as a
  2928. % rational number in UNSIMPLIFIED prefix form
  2929. % or cause error return to enclosing errorset.
  2930. if eqcar(monom, 'quotient) then
  2931. {'plus, FindRatPow(cadr monom, var),
  2932. {'minus, FindRatPow(caddr monom, var)}}
  2933. else if eqcar(monom, 'times) then
  2934. 'plus . for each el in cdr monom collect FindRatPow1(el, var)
  2935. else FindRatPow1(monom, var);
  2936. symbolic procedure FindRatPow1(monom, var);
  2937. if monom eq 1 then 0 % only possible constant by linearity
  2938. else if monom = var then 1
  2939. else if eqcar(monom, 'expt) and
  2940. cadr monom = var then caddr monom
  2941. else error1(); % wrong form
  2942. endmodule;
  2943. load_package int$
  2944. % die folgende Aenderung verhindert das Erzeugen von int* ...
  2945. remd('simpint!*)$
  2946. symbolic procedure simpint!* u$
  2947. begin scalar x;
  2948. return if (x := opmtch('int . u)) then simp x
  2949. else simpiden('int . u)
  2950. % statt else simpiden('int!* . u)
  2951. end$
  2952. setcrackflags()$
  2953. !*fullroots:=t;
  2954. % Zum Integrieren
  2955. put('int, 'simpfn, 'SimpIntPatch);
  2956. share !*intflag!*; % True inside integrator.
  2957. algebraic let {
  2958. int(1/~x^(~n),~x) => -x/(x^n*(n-1)) when numberp n,
  2959. ~x^(~m/~n)*~x => x**((m+n)/n) when (numberp n and numberp m),
  2960. int(~z/~y,~x) => log(y) when z = df(y,x)};
  2961. load_package crack2;
  2962. end$