genpurfn.red 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. module genpurfn;
  2. smacro procedure be_last u;
  3. delete(lastcar u, u);
  4. % VARIOUS GENERAL PURPOSE FUNCTIONS
  5. % 1. Generalization of functions already defined in the REDUCE kernel.
  6. symbolic procedure rmkidnew(u);
  7. if null u or null (u:=reval car u) then gensym() else mkid(u,gensym());
  8. put('mkidnew,'psopfn,'rmkidnew); % Usage mkidnew() or mkidnew(<id>).
  9. symbolic procedure list_to_ids l;
  10. if atom l then rederr "argument for list_to_ids must be a list"
  11. else
  12. intern compress for each i in cdr l join explode i;
  13. flag('(list_to_ids),'opfn);
  14. symbolic procedure simpsetf u;
  15. % generalizes the function "set" to kernels.
  16. begin scalar x;
  17. x := simp!* car u;
  18. if not kernp x or fixp (!*q2a x) then
  19. typerr(!*q2a x,"setvalue kernel") else
  20. x:=!*q2a x;
  21. let0 list(list('equal,x,mk!*sq(u := simp!* cadr u)));
  22. return u
  23. end;
  24. put ('setvalue, 'simpfn, 'simpsetf);
  25. newtok '((!= !=) setvalue ! !=!=! );
  26. infix ==;
  27. flag('(prin2 ) ,'opfn); % To make it available in the alg. mode.
  28. % 2. New functions closely related to existing ones.
  29. symbolic procedure oddp u$
  30. % Tests if integer U is odd. Is also defined in EXCALC;
  31. not evenp u;
  32. flag('(oddp),'boolean);
  33. symbolic procedure followline(n)$
  34. %It allows to go to a new line at the position given by the integer N.
  35. << terpri()$ spaces(n)>>$
  36. flag('(followline ) ,'opfn);
  37. % 3. New general purpose functions.
  38. % 3.1 To handle indexed identifiers.
  39. symbolic procedure charnump!: x;
  40. if x member list('!0,'!1,'!2,'!3,'!4,'!5,'!6,'!7,'!8,'!9) then t ;
  41. symbolic procedure charnump u;
  42. if null u then t else charnump!: car u and charnump cdr u;
  43. symbolic procedure detidnum u;
  44. % Allows one to extract the index from the identifier u.
  45. if idp u then
  46. begin scalar uu;
  47. if length(uu:= cdr explode u) =1 then go to l1
  48. else
  49. while not charnump uu do uu:=cdr uu;
  50. l1: uu:= compress uu;
  51. if fixp uu then return uu end;
  52. flag('(detidnum),'opfn);
  53. symbolic procedure dellastdigit u;
  54. % Strips an integer from its last digit.
  55. if fixp u then compress reverse cdr reverse explode u
  56. else typerr(u,"integer");
  57. flag('(dellastdigit),'opfn);
  58. % 3.2 Random number generator.
  59. symbolic procedure randomlist(n,trial);
  60. % This procedure gives a list of trials in number "trial" of
  61. % random numbers between 0 and n. For the algorithm see KNUTH vol. 2.
  62. 'list . lisp for j:=1:trial collect random n;
  63. flag('(randomlist),'opfn);
  64. % 3.3 Combinatorial functions, symmetry and sorting.
  65. symbolic procedure transpose(l,i,j);
  66. % i,j are integers, l is a list.
  67. % DESTROYS the initial list.
  68. begin scalar tmp;
  69. tmp:=nth(l,i);
  70. nth(l,i):=nth(l,j);
  71. nth(l,j):=tmp;
  72. return l
  73. end;
  74. algebraic procedure combnum(n,nu)$
  75. % Number of combinations of n objects nu to nu.
  76. if nu>n then
  77. rederr "second argument cannot be bigger than first argument"
  78. else factorial(n)/factorial(nu)/factorial(n-nu)$
  79. symbolic procedure cyclicpermlist l;
  80. % Gives all cyclic permutations of elements of the list l.
  81. if atom l then nil else
  82. begin scalar x; integer le;
  83. l:=cdr l;
  84. le:=length l;
  85. x:= ('list . l) . x;
  86. for i:=2:le do x:=('list . (l:=append(cdr l,list car l))) . x;
  87. return 'list . reversip x
  88. end;
  89. flag('(cyclicpermlist),'opfn);
  90. symbolic procedure rpermutation u;
  91. if not baglistp(u:=reval car u) then
  92. nil else if null cdr u then 'list . nil else
  93. begin scalar x,prf$ prf:=car u$
  94. u:=cdr u$
  95. x:=for each j in u
  96. conc mapcons(permutations delete(j,u),j)$
  97. x:=for each j in x collect prf . j$
  98. return prf . x end;
  99. put('permutations,'psopfn,'rpermutation);
  100. symbolic procedure perm_to_num(nindl,indl);
  101. % INPUT : 'indl' : a list of indices.
  102. % 'nindl' : a permutation of 'indl'.
  103. % OUTPUT : an INTEGER (between 0 and (indl)!-1 ) in one-to-one
  104. % correspondence with 'nindl' for the given 'indl'.
  105. begin integer ln,fln,r,num,pos;
  106. nindl:=cdr nindl;
  107. if (ln:=length nindl)= 1 then return num;
  108. fln:=rnfactorial!* mkratnum ln;
  109. while ln>=1 do <<
  110. << r:=rposition list(lastcar nindl,indl);
  111. nindl:=for each j in be_last nindl collect
  112. <<pos:=rposition list(j,indl);
  113. if pos>r then nth(cdr indl,pos-1) else j
  114. >>;
  115. fln:=fln/ln; num:=num + (ln-r)*fln;
  116. >>;
  117. ln:=ln-1 >>;
  118. return num
  119. end;
  120. symbolic procedure num_to_perm(num,indl);
  121. % Does the reverse job. num is an INTEGER. indl is a list of numbers.
  122. % Constructs the corresponding permutation list starting from indl.
  123. begin integer rk,j,f,m,lst; scalar nindl;
  124. indl:=cdr indl;
  125. rk:=length indl;
  126. f:=rnfactorial!* mkratnum rk;
  127. while rk>=1 do <<
  128. <<f:=f/rk; m:=rnfloor!* mkratnum(num/f);
  129. num:=num-m*f; j:=rk-m;
  130. lst:=nth(indl,j); indl:=remove(indl,j);
  131. nindl:=lst . nindl>>;
  132. rk:=rk-1
  133. >>;
  134. return 'list . nindl
  135. end;
  136. flag('(perm_to_num num_to_perm),'opfn);
  137. symbolic procedure !:comb(u)$
  138. begin scalar x,prf; integer n;
  139. if length u neq 2 then
  140. rederr "combinations called with wrong number of arguments";
  141. x:=reval car u ; if not baglistp x then return nil ;
  142. prf :=car x; x:=cdr x; n:=reval cadr u;
  143. return prf . (for each j in comb(x,n) collect prf . j)
  144. end;
  145. put('combinations,'psopfn,'!:comb);
  146. put('symmetrize,'simpfn,'simpsumsym);
  147. flag('(symmetrize),'listargp);
  148. symbolic procedure simpsumsym(u);
  149. % The use is SYMMETRIZE(LIST(A,B,...J),operator,perm_function)
  150. % or SYMMETRIZE(LIST(LIST(A,B,C...)),operator,perm_function).
  151. % Works both for OPFN and symbolic procedure functions.
  152. % Does not yet allow odd permutations.
  153. if length u neq 3 then rederr("3 arguments required for symmetrize")
  154. else
  155. begin scalar uu,x,res,oper,fn,bool,boolfn; integer n;
  156. fn:= caddr u;
  157. if not(gettype fn eq 'procedure) then typerr(fn,"procedure");
  158. uu:=(if flagp(fn,'opfn) then <<boolfn:=t; reval x>>
  159. else cdr reval x) where x=car u;
  160. n:=length uu;
  161. oper:=cadr u;
  162. if not idp oper then typerr(oper,"operator") else
  163. if null flagp(oper,'opfn) then
  164. if null get(oper,'simpfn) then put(oper,'simpfn,'simpiden);
  165. flag(list oper, 'listargp);
  166. x:=if listp car uu and not boolfn then
  167. <<bool:=t;apply1(fn, cdar uu)>> else
  168. if boolfn and listp cadr uu then
  169. <<bool:=t;apply1(fn,cadr uu)>> else
  170. apply1(fn,uu);
  171. if flagp(fn,'opfn) then x:=alg_to_symb x;
  172. n:=length x -1;
  173. if not bool then <<
  174. res:=( oper . car x) .** 1 .* 1 .+ nil;
  175. for i:=1:n do << uu:=cadr x; aconc(res,(oper . uu) .** 1 .* 1 );
  176. delqip(uu,x);>>;
  177. >>
  178. else
  179. << res:=(oper . list('list .
  180. for each i in car x collect mk!*sq simp!* i)) .** 1 .* 1 .+ nil;
  181. for i:=1:n do << uu:=cadr x;
  182. aconc(res,(oper . list('list .
  183. for each i in uu collect mk!*sq simp!* i)) .** 1 .* 1 );
  184. delqip(uu,x);>>;
  185. >>;
  186. if get(oper,'opmtch) or flagp(oper,'opfn) then
  187. res:=resimp( res ./ 1) else res:=res ./ 1;
  188. return res
  189. end;
  190. symbolic procedure sortnumlist l;
  191. % Procedure valid only for list of integers.
  192. % Returns the sorted list without destroying l.
  193. 'list . (if length x < 10 then bubblesort1 x else
  194. quicksort_i_to_j(x,1,length x)) where x=cdr l ;
  195. flag('(sortnumlist),'opfn);
  196. symbolic procedure sortlist(l,fn);
  197. if numlis cdr l then
  198. if fn eq 'lessp then sortnumlist l else
  199. if fn eq 'geq then
  200. ( 'list . (reverse(if length x <10 then bubblesort1 x else
  201. quicksort_i_to_j(x,1,length x))) where x=cdr l) else
  202. nil else
  203. 'list . bubsort1(cdr l,fn);
  204. flag('(sortlist),'opfn);
  205. symbolic procedure bubblesort1 l;
  206. % Elements of l are supposed to be numbers.
  207. begin integer ln;
  208. ln:=length l;
  209. for i:=1:ln do
  210. for j:=i+1:ln do
  211. if i neq j and nth(l,i)>nth(l,j) then
  212. transpose(l,i,j) else nil;
  213. return l
  214. end;
  215. symbolic procedure bubsort1(l,fn);
  216. % Elements of l are numbers or identifiers.
  217. % fn is any ordering function.
  218. begin integer ln;
  219. ln:=length l;
  220. for i:=1:ln do
  221. for j:=i+1:ln do
  222. if i neq j and
  223. apply2(fn,nth(l,j),nth(l,i)) then
  224. transpose(l,i,j) else nil;
  225. return l
  226. end;
  227. symbolic procedure find_pivot_index(l,i,j);
  228. % l is the list, i and j are integers.
  229. begin scalar key; integer k;
  230. key:=nth(l,i);
  231. k:=i+1;
  232. a: if k=j+1 then return -1;
  233. if nth(l,k) > key then return k else
  234. if nth(l,k) < key then return i;
  235. k:=k+1; go to a
  236. end;
  237. symbolic procedure partition(l,i,j,pivot);
  238. % Writes l, all elements less than pivot to the left
  239. % and elements greater or equal to the right of pivot.
  240. % returns the new pivot.
  241. begin integer le,ri;
  242. le:=i; ri:=j;
  243. a: if le>ri then return le;
  244. transpose(l,le,ri);
  245. while nth(l,le) < pivot do le:=le+1;
  246. while nth(l,ri) >= pivot do ri:=ri-1;
  247. go to a
  248. end;
  249. symbolic procedure quicksort_i_to_j(l, i,j);
  250. begin integer k,pi;
  251. pi:=find_pivot_index(l,i,j);
  252. return if pi neq -1 then
  253. <<pi:=nth(l,pi); k:=partition(l,i,j,pi);
  254. quicksort_i_to_j(l,i,k-1);quicksort_i_to_j(l,k,j);l>>
  255. else l
  256. end;
  257. symbolic procedure algsort(u,v);
  258. % Based on the PSL sort function.
  259. % May replace all the above functions.
  260. symb_to_alg sort(alg_to_symb u,v);
  261. symbolic operator algsort;
  262. % 4. Functions to check various properties of objects in a list and extract
  263. % them.
  264. symbolic procedure checkproplist1(l,fn);
  265. % Checks if the list l has the property defined by the function fn.
  266. % fn should preferably be 'function <name_function>'.
  267. if null l then t else
  268. if fn eq 'numberp then
  269. if apply1(function evalnumberp, car l) then checkproplist1(cdr l,fn)
  270. else nil else
  271. if fn eq 'floatp then
  272. if atom car l then nil else
  273. if apply1(function floatp, cdar l ) then checkproplist1(cdr l,fn)
  274. else nil else
  275. if get(fn,'number!-of!-args)=1 then
  276. if apply1(fn,car l) then checkproplist1(cdr l,fn)
  277. else nil else
  278. if get(fn,'number!-of!-args)=2 then
  279. if apply(fn,list(car l,cadr l)) then checkproplist1(cdr l,fn)
  280. else nil;
  281. symbolic procedure checkproplist(l,fn);
  282. % fn may be the name of a function or the expression 'function <name
  283. if atom l then rederr("First argument must be a list") else
  284. checkproplist1(cdr l,fn);
  285. flag('(checkproplist),'boolean);
  286. symbolic procedure extractlist1(l,fn);
  287. % fn is a boolean function. Result is a new list which contains the
  288. % elements satisfying the fn selection criteria.
  289. if null l then nil
  290. else
  291. if fn eq 'numberp then
  292. if apply1(function evalnumberp,car l) then
  293. car l . extractlist1(cdr l,fn)
  294. else extractlist1(cdr l,fn)
  295. else
  296. if fn eq 'floatp then
  297. if atom car l then extractlist1(cdr l,fn) else
  298. if apply1(function floatp, cdar l)
  299. then car l . extractlist1(cdr l,fn)
  300. else extractlist1(cdr l,fn)
  301. else
  302. if apply1(fn,car l) then car l . extractlist1(cdr l,fn)
  303. else extractlist1(cdr l,fn);
  304. symbolic procedure extractlist(l,fn);
  305. % The message will be issued only when number!-of!-args is used.
  306. (if x and x > 1 then
  307. rederr("UNARY boolean function required as argument") else
  308. 'list . extractlist1(cdr l,fn)) where x=get(fn,'number!-of!-args);
  309. flag('(extractlist),'opfn);
  310. % 5. Flags and properties in the ALGEBRAIC mode.
  311. symbolic procedure putflag(u,flg,b)$
  312. % Allows one to put or erase any FLAG on the identifier U.
  313. % U is an idf or a list of idfs, FLAG is an idf, B is T or 0.
  314. if not idp u and not null baglistp u then
  315. <<for each x in cdr u do putflag(x,flg,b)$ t>>
  316. else if idp u and b eq t then
  317. <<flag(list u, flg)$
  318. !:flaglis:=union(list list(u, flg),!:flaglis)$ flg>>
  319. else if idp u and b equal 0 then
  320. <<remflag( list u, flg)$ !:delete(u,nil,flg)$>>
  321. else rederr "*** VARIABLES ARE (idp OR list of flags, T or 0).";
  322. symbolic procedure putprop(u,prop,val,b)$
  323. % Allows to put or erase any PROPERTY on the object U
  324. % U is an idf or a list of idfs, B is T or 0$
  325. if not idp u and baglistp u then
  326. <<for each x in cdr u do putprop(x,prop,val,b)$ t>>
  327. else if idp u and b eq t then
  328. <<put(u, prop,val)$
  329. !:proplis:=union(list list(u,prop,val),!:proplis)$ u>>
  330. else if idp u and b equal 0 then
  331. <<remprop( u, prop)$ !:delete(u,prop,val)$ >>
  332. else rederr "*** VARIABLES ARE (idp OR list of idps, T or 0).";
  333. flag('(putflag putprop),'opfn)$
  334. symbolic procedure rdisplayprop(u)$
  335. % U is the idf whose properties one wants to display.Result is a
  336. % list which contains them$
  337. begin scalar x,val,aa$ x:=reval car u; val:=reval cadr u;
  338. for each j in !:proplis do if car j eq x and cadr j eq val
  339. then aa:=('list . cdr j) . aa;
  340. return if length aa =1 then first aa else 'list . aa
  341. end;
  342. put('displayprop,'psopfn,'rdisplayprop)$
  343. put('displayflag,'psopfn,'rdisplayflag)$
  344. symbolic procedure rdisplayflag(u)$
  345. % U is the idf whose properties one wants to display.Result is a
  346. % list which contains them$
  347. begin scalar x,aa$ x:=reval car u;
  348. for each j in !:flaglis do if car j=x then aa:=cons(cadr j,aa)$
  349. return 'list . aa end;
  350. symbolic procedure clrflg!: u;
  351. for each x in !:flaglis do
  352. if u eq car x then putflag(car x,cadr x,0) ;
  353. symbolic procedure clearflag u;
  354. % If u equals "all" all flags are eliminated.
  355. % If u is a1,a2,a3.....an flags of these identifiers are eliminated.
  356. if null cdr u and car u eq 'all then for each x in !:flaglis
  357. do putflag (car x,cadr x,0) else
  358. if null cdr u then clrflg!: car u else
  359. for each y in u do clrflg!: y;
  360. symbolic procedure clrprp!: u;
  361. for each x in !:proplis do
  362. if u eq car x then putprop(car x,cadr x,caddr x,0);
  363. symbolic procedure clearprop u;
  364. % If u equals "all" all properties are eliminated.
  365. % If u is a1,a2,a3...an properties of these identifiers are eliminated.
  366. if null cdr u and car u eq 'all then for each x in !:proplis
  367. do putprop(car x,cadr x,caddr x,0) else
  368. if null cdr u then clrprp!: car u else
  369. for each y in u do clrprp!: y;
  370. put('clearflag,'stat,'rlis);
  371. put('clearprop,'stat,'rlis);
  372. endmodule;
  373. end;