camal.red 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. %%off comp;
  2. lisp;
  3. %%module foursupport;
  4. %% This section is to define macros and simple functions to handle the
  5. %% data structures for harmonic forms.
  6. %% The structure is a vector:
  7. %% Coeff | FN | Angle | Next
  8. %
  9. %% This version only allows 8 angles. Consider extending this later.
  10. switch fourier;
  11. %% A vector and counter to record link between angle names and index
  12. global '(next!-angle!* fourier!-name!*);
  13. next!-angle!* := 0;
  14. if vectorp fourier!-name!* then <<
  15. for i :=0:7 do remprop(getv(fourier!-name!*, i), 'fourier!-angle)
  16. >>;
  17. fourier!-name!* := mkvect 7;
  18. %% For non Cambridge LISP add
  19. smacro procedure putv!.unsafe(x,y,z); putv(x,y,z);
  20. smacro procedure getv!.unsafe(x,y); getv(x,y);
  21. %% Data abtraction says that we should define macros for access to
  22. %% the parts of the Fourier structure
  23. smacro procedure fs!:set!-next(f,p); putv!.unsafe(f, 3, p);
  24. smacro procedure fs!:next(f); getv!.unsafe(f,3);
  25. smacro procedure fs!:set!-coeff(f,p); putv!.unsafe(f, 0, p);
  26. smacro procedure fs!:coeff(f); getv!.unsafe(f, 0);
  27. smacro procedure fs!:set!-fn(f,p); putv!.unsafe(f, 1, p);
  28. smacro procedure fs!:fn(f); getv!.unsafe(f, 1);
  29. smacro procedure fs!:set!-angle(f,p); putv!.unsafe(f, 2, p);
  30. smacro procedure fs!:angle(f); getv!.unsafe(f, 2);
  31. %% Some support functions for angle expressions
  32. symbolic procedure fs!:make!-nullangle();
  33. begin scalar ans;
  34. ans := mkvect 7;
  35. for i:=0:7 do putv!.unsafe(ans,i,0);
  36. return ans;
  37. end;
  38. symbolic procedure fs!:null!-angle!: u;
  39. fs!:null!-angle cdr u;
  40. symbolic procedure fs!:null!-angle u;
  41. begin scalar ans, i, x;
  42. x := fs!:angle u;
  43. ans := t;
  44. i := 0;
  45. top:
  46. if not(getv!.unsafe(x,i)=0) then return nil;
  47. i := i+1;
  48. if (i<8) then go to top;
  49. return ans;
  50. end;
  51. %%module fourdom; % Domain definitions for angles and fourier series
  52. % Authors: John Fitch 1991
  53. global '(domainlist!*);
  54. domainlist!*:=union('(!:fs!:),domainlist!*);
  55. put('fourier,'tag,'!:fs!:);
  56. put('!:fs!:,'dname,'fourier);
  57. flag('(!:fs!:),'field); %% Should be ring really
  58. put('!:fs!:,'i2d,'i2fourier);
  59. put('!:fs!:,'minusp,'fs!:minusp!:);
  60. put('!:fs!:,'plus,'fs!:plus!:);
  61. put('!:fs!:,'times,'fs!:times!:);
  62. put('!:fs!:, 'expt,'fs!:expt!:);
  63. put('!:fs!:,'difference,'fs!:difference!:);
  64. put('!:fs!:,'quotient,'fs!:quotient!:);
  65. put('!:fs!:, 'divide, 'fs!:divide!:);
  66. put('!:fs!:, 'gcd, 'fs!:gcd!:);
  67. put('!:fs!:,'zerop,'fs!:zerop!:);
  68. put('!:fs!:,'onep,'fs!:onep!:);
  69. put('!:fs!:,'prepfn,'fs!:prepfn!:);
  70. put('!:fs!:,'specprn,'fs!:prin!:);
  71. put('!:fs!:,'prifn,'fs!:prin!:);
  72. put('!:fs!:,'intequivfn,'fs!:intequiv!:);
  73. flag('(!:fs!:),'ratmode);
  74. % conversion functions
  75. put('!:fs!:,'!:mod!:,mkdmoderr('!:fs!:,'!:mod!:));
  76. % put('!:fs!:,'!:gi!:,mkdmoderr('!:fs!:,'!:gi!:));
  77. % put('!:fs!:,'!:rn!:,mkdmoderr('!:fs!:,'!:rn!:));
  78. put('!:rn!:,'!:fs!:,'!*d2fourier);
  79. put('!:ft!:,'!:fs!:,'cdr);
  80. put('!:gi!:,'!:fs!:,'!*d2fourier);
  81. put('!:gf!:,'!:fs!:,'!*d2fourier);
  82. put('expt, '!:fs!:, 'fs!:expt!:);
  83. % Conversion functions
  84. symbolic procedure i2fourier u;
  85. if dmode!*='!:fs!: then !*d2fourier u else u;
  86. symbolic procedure !*d2fourier u;
  87. if null u then nil else
  88. begin scalar fourier;
  89. fourier:=mkvect 3;
  90. fs!:set!-coeff(fourier,(u . 1));
  91. fs!:set!-fn(fourier,'cos);
  92. fs!:set!-angle(fourier,fs!:make!-nullangle());
  93. fs!:set!-next(fourier,nil);
  94. return get('fourier,'tag) . fourier
  95. end;
  96. symbolic procedure !*sq2fourier u;
  97. if null car u then nil else
  98. begin scalar fourier;
  99. fourier:=mkvect 3;
  100. fs!:set!-coeff(fourier,u);
  101. fs!:set!-fn(fourier,'cos);
  102. fs!:set!-angle(fourier,fs!:make!-nullangle());
  103. fs!:set!-next(fourier,nil);
  104. return get('fourier,'tag) . fourier
  105. end;
  106. symbolic procedure fs!:minusp!:(x); fs!:minusp cdr x;
  107. symbolic procedure fs!:minusp x;
  108. if null x then nil else
  109. if null fs!:next x then minusf car fs!:coeff x
  110. else fs!:minusp fs!:next x;
  111. %% Basic algebraic operations
  112. symbolic procedure fs!:times!:(x,y);
  113. % This function seems to be called with numeric values as well
  114. if null x then nil else if null y then nil
  115. else if numberp y then get('fourier,'tag) . fs!:timescoeff(y ./ 1, cdr x)
  116. else if numberp x then get('fourier,'tag) . fs!:timescoeff(x ./ 1, cdr y)
  117. else if not eqcar(x, get('fourier,'tag)) then
  118. get('fourier,'tag) . fs!:timescoeff(x,cdr y)
  119. else if not eqcar(y, get('fourier,'tag)) then
  120. get('fourier,'tag) . fs!:timescoeff(y,cdr x)
  121. else get('fourier,'tag) . fs!:times(cdr x, cdr y);
  122. symbolic procedure fs!:timescoeff(x, y);
  123. if null y then nil
  124. else begin scalar ans, coeff;
  125. coeff := multsq(x,fs!:coeff y);
  126. if coeff = '(nil . 1) then <<
  127. print "zero in times";
  128. return fs!:timescoeff(x, fs!:next y) >>;
  129. ans := mkvect 3;
  130. fs!:set!-coeff(ans,coeff);
  131. fs!:set!-fn(ans,fs!:fn y);
  132. fs!:set!-angle(ans,fs!:angle y);
  133. fs!:set!-next(ans, fs!:timescoeff(x, fs!:next y));
  134. return ans
  135. end;
  136. symbolic procedure fs!:times(x,y);
  137. if null x then nil else if null y then nil else
  138. begin scalar ans;
  139. ans := fs!:timesterm(x, y);
  140. return fs!:plus(ans, fs!:times(fs!:next x, y));
  141. end;
  142. symbolic procedure fs!:timesterm(x,y);
  143. % Treat x as a term and y as a tree
  144. if null y then nil else if null x then nil else
  145. begin scalar ans;
  146. ans := fs!:timestermterm(x,y);
  147. return fs!:plus(ans, fs!:timesterm(x, fs!:next y));
  148. end;
  149. symbolic procedure fs!:timestermterm(x,y);
  150. % x and y are terms. Generate the two answer terms.
  151. begin scalar sum, diff, ans, xv, yv, coeff;
  152. sum := mkvect 7;
  153. xv := fs!:angle x;
  154. yv := fs!:angle y;
  155. for i:=0:7 do putv!.unsafe(sum,i,
  156. getv!.unsafe(xv,i)+getv!.unsafe(yv,i));
  157. diff := mkvect 7;
  158. for i:=0:7 do putv!.unsafe(diff,i,
  159. getv!.unsafe(xv,i)-getv!.unsafe(yv,i));
  160. coeff := multsq(fs!:coeff x, fs!:coeff y);
  161. coeff := multsq(coeff, '(1 . 2));
  162. if null car coeff then return nil;
  163. if fs!:fn x = 'sin then
  164. if fs!:fn y = 'sin then
  165. % sin x*sin y => [-cos(x+y)+cos(x-y)]/2
  166. return fs!:plus(make!-term('cos, sum, negsq coeff),
  167. make!-term('cos,diff, coeff))
  168. else % fs!:fn y = 'cos
  169. % sin x * cos y => [sin(x+y)+sin(x-y)]/2
  170. return fs!:plus(make!-term('sin, sum, coeff),
  171. make!-term('sin, diff,coeff))
  172. else % fs!:fn x='cos
  173. if fs!:fn y = 'sin then
  174. % cos x*sin y => [sin(x+y)-sin(x-y)]/2
  175. return fs!:plus(make!-term('sin, sum, coeff),
  176. make!-term('sin,diff, negsq coeff))
  177. else % fs!:fn y = 'cos
  178. % cos x * cos y => [cos(x+y)+cos(x-y)]/2
  179. return fs!:plus(make!-term('cos, sum, coeff),
  180. make!-term('cos, diff,coeff))
  181. end;
  182. symbolic procedure fs!:expt!:(x,n);
  183. begin scalar ans, xx;
  184. ans := cdr !*d2fourier 1;
  185. x := cdr x;
  186. for i:=1:n do ans := fs!:times(ans,x);
  187. return get('fourier,'tag) . ans;
  188. end;
  189. symbolic procedure make!-term(fn, ang, coeff);
  190. begin scalar fourier, sign, i;
  191. sign := 0;
  192. i:=0;
  193. top: if getv!.unsafe(ang,i)<0 then sign := -1
  194. else if getv!.unsafe(ang,i)>0 then sign := 1
  195. else if i=7 then <<
  196. if fn ='sin then return nil >>
  197. else << i := i #+ 1; goto top >>;
  198. fourier:=mkvect 3;
  199. if sign = 1 or fn = 'cos then fs!:set!-coeff(fourier,coeff)
  200. else fs!:set!-coeff(fourier, multsq('(-1 . 1), coeff));
  201. fs!:set!-fn(fourier,fn);
  202. if sign = -1 then << sign := mkvect 7;
  203. for i:=0:7 do putv!.unsafe(sign,i,-getv!.unsafe(ang,i));
  204. ang := sign
  205. >>;
  206. fs!:set!-angle(fourier,ang);
  207. fs!:set!-next(fourier,nil);
  208. return fourier
  209. end;
  210. symbolic procedure fs!:quotient!:(x,y);
  211. if numberp y then fs!:times!:(x, !*sq2fourier (1 ./ y))
  212. else rerror(fourier, 98, "Unimplemented");
  213. symbolic procedure fs!:divide!:(x,y);
  214. rerror(fourier, 98, "Unimplemented");
  215. symbolic procedure fs!:gcd!:(x,y);
  216. rerror(fourier, 98, "Unimplemented");
  217. symbolic procedure fs!:difference!:(x,y);
  218. fs!:plus!:(x, fs!:negate!: y);
  219. symbolic procedure fs!:negate!: x;
  220. get('fourier,'tag) . fs!:negate cdr x;
  221. symbolic procedure fs!:negate x;
  222. if null x then nil
  223. else begin scalar ans;
  224. ans := mkvect 3;
  225. fs!:set!-coeff(ans,negsq fs!:coeff x);
  226. fs!:set!-fn(ans,fs!:fn x);
  227. fs!:set!-angle(ans,fs!:angle x);
  228. fs!:set!-next(ans, fs!:negate fs!:next x);
  229. return ans
  230. end;
  231. symbolic procedure fs!:zerop!:(u);
  232. null u or
  233. (not numberp u and
  234. null cdr u or
  235. (null fs!:next cdr u and
  236. ((numberp v and zerop v) where v=fs!:coeff cdr u)));
  237. symbolic procedure fs!:onep!:(u); fs!:onep cdr u;
  238. symbolic procedure fs!:onep u;
  239. null fs!:next u and
  240. onep fs!:coeff u and fs!:null!-angle u and fs!:fn(u) = 'cos;
  241. symbolic procedure fs!:prepfn!:(x); x;
  242. symbolic procedure simpfs u; u;
  243. put('!:fs!:,'simpfn,'simpfs);
  244. %% PRINTING FUNCTIONS
  245. %% We have all the usual problems of unit coefficients, and zero angles
  246. smacro procedure zeroterm x; fs!:coeff x = '(nil . 1);
  247. symbolic procedure fs!:prin!:(x);
  248. << prin2!* "["; fs!:prin cdr x; prin2!* "]" >>;
  249. symbolic procedure fs!:prin x;
  250. if null x then prin2!* " 0 " else <<
  251. while x do <<
  252. fs!:prin1 x;
  253. x := fs!:next x;
  254. if x then prin2!* " + "
  255. >>
  256. >>;
  257. symbolic procedure fs!:prin1 x;
  258. begin scalar first, u, v;
  259. first := t;
  260. if not(fs!:coeff x = '(1 . 1)) then <<
  261. prin2!* "("; sqprint fs!:coeff x;
  262. prin2!* ")" >>;
  263. if not(fs!:null!-angle x) then <<
  264. prin2!* fs!:fn x;
  265. prin2!* "[";
  266. u := fs!:angle x;
  267. for i:=0:7 do
  268. if not((v := getv!.unsafe(u,i)) = 0) then <<
  269. if v<0 then << first := t; prin2!* "-"; v := -v >>;
  270. if not first then prin2!* "+";
  271. if not(v=1) then prin2!* v;
  272. first := nil;
  273. prin2!* getv!.unsafe(fourier!-name!*, i)
  274. >>;
  275. prin2!* "]"
  276. >>
  277. else if fs!:coeff x = '(1 . 1) then prin2!* "1"
  278. end;
  279. symbolic procedure fs!:intequiv!:(u);
  280. null fs!:next x and
  281. fs!:null!-angle x and
  282. fs!:fn(x) = 'cos and
  283. fixp car fs!:coeff x and
  284. cdr fs!:coeff x = 1
  285. where x = cdr u;
  286. %%module fourplus;
  287. %% ARITHMETIC
  288. %% Addition of Fourier expressionsis really a merge operation
  289. symbolic procedure fs!:plus!:(x,y);
  290. %% Top level addition of two fourier series
  291. if fs!:zerop!: y then x
  292. else if fs!:zerop!: x then y
  293. else get('fourier,'tag) . fs!:plus(copy!-tree cdr x, copy!-tree cdr y);
  294. % I cannot rely on the CAMAL selective copy, so I take the coward's way out
  295. symbolic procedure copy!-tree x;
  296. if null x then nil
  297. else begin scalar ans;
  298. ans := mkvect 3;
  299. fs!:set!-coeff(ans,fs!:coeff x);
  300. fs!:set!-fn(ans,fs!:fn x);
  301. fs!:set!-angle(ans,fs!:angle x);
  302. fs!:set!-next(ans, copy!-tree fs!:next x);
  303. return ans
  304. end;
  305. symbolic procedure fs!:plus(x, y);
  306. %% The real addition. x is a new tree to which y must be merged.
  307. if null y then x
  308. else if null x then y
  309. else if fs!:fn x = fs!:fn y and angles!-equal(fs!:angle x, fs!:angle y) then
  310. begin scalar coef;
  311. coef := addsq(fs!:coeff x, fs!:coeff y);
  312. % Really I should deal with the zero case here
  313. if null car coef then return fs!:plus(fs!:next x, fs!:next y);
  314. fs!:set!-coeff(x, coef);
  315. fs!:set!-next(x, fs!:plus(fs!:next x, fs!:next y));
  316. return x
  317. end
  318. else if fs!:angle!-order(x, y) then <<
  319. fs!:set!-next(x, fs!:plus(fs!:next x, y));
  320. x >>
  321. else <<
  322. fs!:set!-next(y, fs!:plus(fs!:next y,x));
  323. y >>;
  324. symbolic procedure angles!-equal(x, y);
  325. % Are all angles the same?
  326. begin scalar i;
  327. i := 0;
  328. top:
  329. if not(getv!.unsafe(x,i)=getv!.unsafe(y,i)) then return nil;
  330. i := i+1;
  331. if (i<8) then go to top;
  332. return t;
  333. end;
  334. symbolic procedure fs!:angle!-order(x, y);
  335. % Ordering function for angle expressions, also taking account of angle.
  336. begin scalar ans, i, xx, yy;
  337. i := 0;
  338. xx := fs!:angle x;
  339. yy := fs!:angle y;
  340. top:
  341. ans := (getv!.unsafe(xx,i)-getv!.unsafe(yy,i));
  342. if not(ans = 0) then return ans>0;
  343. i := i+1;
  344. if (i<8) then go to top;
  345. return
  346. if fs!:fn x = fs!:fn y then nil else if fs!:fn x = 'sin then nil else t;
  347. end;
  348. %%module makefour;
  349. %% User interface; all rather iffy at present
  350. symbolic procedure harmonicp u; get(u, 'fourier!-angle);
  351. symbolic procedure harmonic u;
  352. <<
  353. for each x in u do if not(get(x, 'fourier!-angle)) then <<
  354. if (next!-angle!* > 7) then rerror(fourier, 3, "Too many angles");
  355. put(x, 'fourier!-angle, next!-angle!*);
  356. putv!.unsafe(fourier!-name!*, next!-angle!*, x);
  357. next!-angle!* := next!-angle!* #+ 1;
  358. >>
  359. >>;
  360. put('harmonic, 'stat, 'rlis);
  361. symbolic procedure simpfourier u;
  362. %% Handle the form fourier(...) with treating sin and cos as special
  363. begin
  364. if not(length u = 1) then
  365. rerror(fourier,1,"Argument should be single expression");
  366. return simpfourier1 prepsq simp!* car u;;
  367. end;
  368. symbolic procedure simpfourier1 u;
  369. begin scalar ff;
  370. if atom u then <<
  371. if harmonicp u then rerror(fourier,2,"Secular angle not allowed");
  372. return (!*sq2fourier simp u) . 1;
  373. >>
  374. else if eqcar(u, '!:fs!:) then return u
  375. else if (ff := get(car u, 'simpfour)) then return apply1(ff, cdr u)
  376. else <<
  377. rerror(fourier,4,"Unknown function" . car u);
  378. return (!*sq2fourier u) . 1;
  379. >>
  380. end;
  381. put('fourier, 'simpfn, 'simpfourier);
  382. symbolic procedure simpfouriersin u;
  383. % Creation of a simple angle expression and function
  384. begin scalar ans, vv;
  385. u := car u;
  386. if atom u then
  387. if harmonicp u then <<
  388. ans:=mkvect 3;
  389. fs!:set!-coeff(ans,(1 . 1));
  390. fs!:set!-fn(ans,'sin);
  391. vv := mkvect 7;
  392. for i:=0:7 do putv!.unsafe(vv,i,0);
  393. putv!.unsafe(vv, get(u, 'fourier!-angle), 1);
  394. fs!:set!-angle(ans,vv);
  395. fs!:set!-next(ans,nil);
  396. return (get('fourier,'tag) . ans) . 1 >>
  397. else return !*sq2fourier(simp list('sin, u)) . 1;
  398. if angle!-expression!-p u then <<
  399. ans:=mkvect 3;
  400. fs!:set!-coeff(ans,(1 . 1));
  401. fs!:set!-fn(ans,'sin);
  402. vv := mkvect 7;
  403. for i:=0:7 do putv!.unsafe(vv,i,0);
  404. compile!-angle!-expression(u,vv);
  405. fs!:set!-angle(ans,vv);
  406. fs!:set!-next(ans,nil);
  407. return (get('fourier,'tag) . ans) . 1 >>;
  408. rerror(fourier,99,"Not finished yet");
  409. end;
  410. put('sin, 'simpfour, 'simpfouriersin);
  411. symbolic procedure simpfouriercos u;
  412. % Creation of a simple angle expression and function
  413. begin scalar ans, vv;
  414. u := car u;
  415. if atom u then
  416. if harmonicp u then <<
  417. ans:=mkvect 3;
  418. fs!:set!-coeff(ans,(1 . 1));
  419. fs!:set!-fn(ans,'cos);
  420. vv := mkvect 7;
  421. for i:=0:7 do putv!.unsafe(vv,i,0);
  422. putv!.unsafe(vv, get(u, 'fourier!-angle), 1);
  423. fs!:set!-angle(ans,vv);
  424. fs!:set!-next(ans,nil);
  425. return (get('fourier,'tag) . ans) . 1 >>
  426. else return !*sq2fourier(simp list('cos, u)) . 1;
  427. if angle!-expression!-p u then <<
  428. ans:=mkvect 3;
  429. fs!:set!-coeff(ans,(1 . 1));
  430. fs!:set!-fn(ans,'cos);
  431. vv := mkvect 7;
  432. for i:=0:7 do putv!.unsafe(vv,i,0);
  433. compile!-angle!-expression(u,vv);
  434. fs!:set!-angle(ans,vv);
  435. fs!:set!-next(ans,nil);
  436. return (get('fourier,'tag) . ans) . 1 >>;
  437. rerror(fourier,99,"Not finished yet");
  438. end;
  439. put('cos, 'simpfour, 'simpfouriercos);
  440. %% Is the prefix expression u a sum of angles??
  441. symbolic procedure angle!-expression!-p u;
  442. if atom u and harmonicp u then t
  443. else if eqcar(u,'plus) or eqcar(u,'difference) then
  444. angle!-expression!-p cadr u and angle!-expression!-p caddr u
  445. else if eqcar(u,'minus) then angle!-expression!-p cadr u
  446. else if eqcar(u,'times) then
  447. if numberp cadr u then angle!-expression!-p caddr u
  448. else angle!-expression!-p cadr u and numberp caddr u
  449. else nil;
  450. %% We know that u is a sum of angles, so create the vector of coefficients;
  451. symbolic procedure compile!-angle!-expression(u,v);
  452. if atom u and harmonicp u then
  453. putv!.unsafe(v, get(u, 'fourier!-angle),
  454. 1+getv!.unsafe(v, get(u, 'fourier!-angle)))
  455. else if eqcar(u,'plus) then <<
  456. u := cdr u;
  457. while u do <<
  458. compile!-angle!-expression(car u,v);
  459. u := cdr u
  460. >>;
  461. v >>
  462. else if eqcar(u,'difference) then begin scalar vv;
  463. compile!-angle!-expression(cadr u,v);
  464. vv := mkvect 7;
  465. for i:=0:7 do putv!.unsafe(vv,i,0);
  466. compile!-angle!-expression(caddr u,vv);
  467. for i:=0:7 do putv!.unsafe(v,i,getv!.unsafe(v,i)-getv!.unsafe(vv,i));
  468. return v
  469. end
  470. else if eqcar(u,'minus) then
  471. begin scalar vv;
  472. vv := mkvect 7;
  473. for i:=0:7 do putv!.unsafe(vv,i,0);
  474. compile!-angle!-expression(cadr u,vv);
  475. for i:=0:7 do putv!.unsafe(v,i,getv!.unsafe(v,i)-getv!.unsafe(vv,i));
  476. return v;
  477. end
  478. else if eqcar(u,'times) then
  479. if numberp cadr u then begin scalar vv;
  480. vv := mkvect 7;
  481. for i:=0:7 do putv!.unsafe(vv,i,0);
  482. compile!-angle!-expression(caddr u,vv);
  483. for i:=0:7 do putv!.unsafe(v, i,
  484. cadr u * getv!.unsafe(vv, i) + getv!.unsafe(v,i))
  485. end
  486. else begin scalar vv;
  487. vv := mkvect 7;
  488. for i:=0:7 do putv!.unsafe(vv,i,0);
  489. compile!-angle!-expression(cadr u,vv);
  490. for i:=0:7 do putv!.unsafe(v, i,
  491. caddr u * getv!.unsafe(vv, i) + getv!.unsafe(v,i))
  492. end
  493. else nil;
  494. symbolic procedure simpfouriertimes(u);
  495. begin scalar z;
  496. z := car simpfourier1 car u;
  497. u := cdr u;
  498. a: if null u then return z ./ 1;
  499. z := fs!:times!:(car simpfourier1 car u,z);
  500. u := cdr u;
  501. go to a
  502. end;
  503. put('times, 'simpfour, 'simpfouriertimes);
  504. symbolic procedure simpfourierexpt(u);
  505. fs!:expt!:(car simpfourier1 car u, cadr u) . 1;
  506. put('expt, 'simpfour, 'simpfourierexpt);
  507. symbolic procedure simpfourierplus(u);
  508. begin scalar z;
  509. z := car simpfourier1 car u;
  510. u := cdr u;
  511. a: if null u then return z ./ 1;
  512. z := fs!:plus!:(car simpfourier1 car u,z);
  513. u := cdr u;
  514. go to a
  515. end;
  516. put('plus, 'simpfour, 'simpfourierplus);
  517. symbolic procedure simpfourierdifference(u);
  518. fs!:difference!:(car simpfourier1 car u, car simpfourier1 cadr u) ./ 1;
  519. put('difference, 'simpfour, 'simpfourierdifference);
  520. symbolic procedure simpfourierminus(u);
  521. fs!:negate!:(car simpfourier1 car u) . 1;
  522. put('minus, 'simpfour, 'simpfourierminus);
  523. symbolic procedure simpfourierquot(u);
  524. begin scalar v;
  525. v := simp!* cadr u;
  526. v := cdr v . car v;
  527. return fs!:times!:(car simpfourier1 car u, !*sq2fourier v) ./ 1
  528. end;
  529. put('quotient, 'simpfour, 'simpfourierquot);
  530. symbolic procedure simphsin u;
  531. begin
  532. if not(length u = 1) then
  533. rerror(fourier,5,"Argument should be single expression");
  534. return simpfouriersin list(u := prepsq simp!* car u)
  535. end;
  536. put('hsin, 'simpfn, 'simphsin);
  537. symbolic procedure simphcos u;
  538. begin
  539. if not(length u = 1) then
  540. rerror(fourier,6,"Argument should be single expression");
  541. return simpfouriercos list(u := prepsq simp!* car u)
  542. end;
  543. put('hcos, 'simpfn, 'simphcos);
  544. %%endmodule;
  545. %%module hsub
  546. %% Harmonic substitution: the CAMAL HSUB operation, as well as other
  547. %% substitutions.
  548. fluid '(!*trharm);
  549. switch trham;
  550. symbolic procedure hsub(x,u,v,A,n);
  551. %% Substitute v+A for u in x to order n
  552. begin scalar ans, c, tmp, fs!:zero!-generated;
  553. %% fs!:zero!-generated := 0;
  554. ans := fs!:subang(x, u, v);
  555. % c := ensure!-fourier A;
  556. c := car A;
  557. if c then c := cdr c;
  558. A := c;
  559. if !*trham then << print "A"; if null A then print 0 else fs!:prin A >>;
  560. for i:=1:n do <<
  561. if !*trham then << print "i="; print i >>;
  562. x := hdiff(x, u);
  563. if !*trham then << prin2!* "df(x,u,i)="; fs!:prin x; terpri!* t;
  564. prin2!* "A^i ="; fs!:prin c; terpri!* t >>;
  565. c := fs!:times(cdr !*sq2fourier (1 ./ i), c);
  566. if !*trham then << prin2!* "A^i/fact(i) ="; fs!:prin c; terpri!* t>>;
  567. tmp := fs!:times(fs!:subang(x, u, v), c);
  568. if !*trham then <<
  569. prin2!* "f'(0)*A^i/fact i = "; fs!:prin tmp; terpri!* t>>;
  570. ans := fs!:plus(ans, tmp);
  571. if !*trham then << prin2!* "partial sum ="; fs!:prin ans; terpri!* t>>;
  572. if not(i=n) then c := fs!:times(c,A);
  573. >>;
  574. return ans
  575. end;
  576. symbolic procedure fs!:subang(x, u, v);
  577. if null x then nil
  578. else begin scalar vv, n;
  579. vv := mkvect 7;
  580. n := getv!.unsafe(fs!:angle x, u);
  581. for i:=0:7 do if i = u then putv!.unsafe(vv, i, n*getv!.unsafe(v,i))
  582. else putv!.unsafe(vv, i,
  583. getv!.unsafe(fs!:angle x,i) + n*getv!.unsafe(v,i));
  584. return fs!:plus(fs!:subang(fs!:next x, u, v),
  585. make!-term(fs!:fn x, vv, fs!:coeff x));
  586. end;
  587. symbolic procedure fs!:sub(x,u);
  588. if null x then nil else
  589. begin scalar ans;
  590. ans := aeval prepsq fs!:coeff x;
  591. if not fixp ans then ans := subsq(cadr ans, u)
  592. else ans := fs!:coeff x;
  593. if eqcar(numr ans, '!:fs!:) then ans := cdar ans
  594. else ans := cdr !*sq2fourier ans;
  595. ans := fs!:times(make!-term(fs!:fn x, fs!:angle x, 1 ./ 1), ans);
  596. return fs!:plus(fs!:sub(fs!:next x, u), ans);
  597. end;
  598. symbolic procedure simphsub uu;
  599. begin scalar x, u, v, vv, A, n, dmode!*;
  600. dmode!* := '!:fs!:;
  601. if (length uu = 5) then <<
  602. x := car uu; uu := cdr uu;
  603. u := car uu; uu := cdr uu;
  604. v := car uu; uu := cdr uu;
  605. A := car uu; uu := cdr uu;
  606. n := car uu
  607. >>
  608. else if (length uu = 3) then <<
  609. x := car uu; uu := cdr uu;
  610. u := car uu; uu := cdr uu;
  611. v := car uu; uu := cdr uu;
  612. if not harmonicp u then <<
  613. A := ( ((get('fourier, 'tag) .
  614. fs!:sub(cdar simp x, list(u . v))) ./ 1)
  615. ) where wtl!*=delasc(u,wtl!*);
  616. return A;
  617. >>;
  618. A := 0;
  619. n := 0
  620. >>;
  621. if not harmonicp u then
  622. rerror(fourier, 7, "Not an angle in HSUB");
  623. x := cdar simp x;
  624. if not angle!-expression!-p v then
  625. rerror(fourier, 8, "Not an angle expression in HSUB");
  626. vv := mkvect 7;
  627. for i:=0:7 do putv!.unsafe(vv,i,0);
  628. compile!-angle!-expression(v, vv);
  629. A := simp!* A;
  630. n := simp!* n;
  631. if null car n then n := 0 ./ 1
  632. else if not(fixp car n and cdr n = 1) then
  633. rerror(fourier, 9, "Non integer expansion in HSUB");
  634. n := car n;
  635. return (get('fourier, 'tag) . hsub(x,get(u,'fourier!-angle),vv,A,n)) ./ 1;
  636. end;
  637. put('hsub, 'simpfn, 'simphsub);
  638. %%endmodule
  639. %%module hdiff
  640. %% Harmonic differentiation and Integration
  641. symbolic procedure hdiff(x, u);
  642. if null x then nil
  643. else fs!:plus(hdiff(fs!:next x,u), hdiffterm(x,u));
  644. symbolic procedure hdiffterm(x, u);
  645. begin scalar n;
  646. n := getv!.unsafe(fs!:angle x, u);
  647. if n = 0 then return nil;
  648. n := multsq( n . 1, fs!:coeff x);
  649. if fs!:fn x = 'cos then return make!-term('sin, fs!:angle x, negsq n)
  650. else return make!-term('cos, fs!:angle x, n)
  651. end;
  652. symbolic procedure hdiff1(x, u);
  653. if null x then nil
  654. else begin scalar ans, aaa;
  655. ans := diffsq(fs!:coeff x, u);
  656. if ans then <<
  657. aaa := mkvect 3;
  658. fs!:set!-coeff(aaa, ans);
  659. fs!:set!-fn(aaa, fs!:fn x);
  660. fs!:set!-angle(aaa,fs!:angle x);
  661. fs!:set!-next(aaa, hdiff1(fs!:next x, u));
  662. return aaa >>
  663. else return hdiff1(fs!:next x, u)
  664. end;
  665. symbolic procedure simphdiff uu;
  666. begin scalar x, u;
  667. if not (length uu = 2) then
  668. rerror(fourier, 10, "Improper number of arguments to HDIFF");
  669. x := car uu; uu := cdr uu;
  670. u := car uu;
  671. x := simp x;
  672. if not eqcar(car x, '!:fs!:) then x := !*sq2fourier x ./ 1;
  673. if not harmonicp u then
  674. return (get('fourier, 'tag) . hdiff1(cdar x, u)) ./ 1;
  675. x := hdiff(cdar x,get(u,'fourier!-angle));
  676. if null x then return nil ./ 1;
  677. return (get('fourier, 'tag) . x) ./ 1
  678. end;
  679. put('hdiff, 'simpfn, 'simphdiff);
  680. symbolic procedure hint(x, u);
  681. if null x then nil
  682. %% Bind fs!:zero!-generated ??
  683. else fs!:plus(hint(fs!:next x,u), hintterm(x,u));
  684. symbolic procedure hintterm(x, u);
  685. begin scalar n;
  686. n := getv!.unsafe(fs!:angle x, u);
  687. if n = 0 then return make!-term(fs!:fn x, fs!:angle x, fs!:coeff x);
  688. n := multsq( 1 ./ n, fs!:coeff x);
  689. if fs!:fn x = 'cos then return make!-term('sin, fs!:angle x, n)
  690. else return make!-term('cos, fs!:angle x, negsq n)
  691. end;
  692. symbolic procedure hint1(x , u);
  693. if null x then nil
  694. else begin scalar aaa;
  695. aaa := mkvect 3;
  696. fs!:set!-coeff(aaa, simpint list(prepsq fs!:coeff x, u));
  697. fs!:set!-fn(aaa, fs!:fn x);
  698. fs!:set!-angle(aaa,fs!:angle x);
  699. fs!:set!-next(aaa, hint1(fs!:next x, u));
  700. return aaa
  701. end;
  702. symbolic procedure simphint uu;
  703. begin scalar x, u;
  704. if not (length uu = 2) then
  705. rerror(fourier, 11, "Improper number of arguments to HINT");
  706. x := car uu; uu := cdr uu;
  707. u := car uu;
  708. x := simp x;
  709. if not eqcar(car x, '!:fs!:) then x := !*sq2fourier x ./ 1;
  710. if not harmonicp u then
  711. return (get('fourier, 'tag) . hint1(cdar x, u)) ./ 1;
  712. x := hint(cdar x,get(u,'fourier!-angle));
  713. if null x then return nil ./ 1;
  714. return (get('fourier, 'tag) . x) ./ 1
  715. end;
  716. put('hint, 'simpfn, 'simphint);
  717. initdmode 'fourier;
  718. algebraic;
  719. end;
  720. ==John