matr.red 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. module matr;
  2. % Author: Anthony C. Hearn;
  3. % This module is rife with essential references to RPLAC-based
  4. % functions.
  5. fluid '(!*sub2);
  6. global '(nxtsym!* subfg!*);
  7. symbolic procedure matrix u;
  8. %declares list U as matrices;
  9. begin scalar v,w,x;
  10. for each j in u do
  11. if atom j then if null (x := gettype j)
  12. then put(j,'rtype,'matrix)
  13. else if x eq 'matrix
  14. then <<lprim list(x,j,"redefined");
  15. put(j,'rtype,'matrix)>>
  16. else typerr(list(x,j),"matrix")
  17. else if not idp car j
  18. or length (v := revlis cdr j) neq 2
  19. or not natnumlis v
  20. then errpri2(j,'hold)
  21. else if not (x := gettype car j) or x eq 'matrix
  22. then <<w := nil;
  23. for n := 1:car v do w := nzero cadr v . w;
  24. put(car j,'rtype,'matrix);
  25. put(car j,'rvalue,'mat . w)>>
  26. else typerr(list(x,car j),"matrix")
  27. end;
  28. symbolic procedure natnumlis u;
  29. % True if U is a list of natural numbers.
  30. null u
  31. or numberp car u and fixp car u and car u>0 and natnumlis cdr u;
  32. rlistat '(matrix);
  33. symbolic procedure nzero n;
  34. % Returns a list of N zeros.
  35. if n=0 then nil else 0 . nzero(n-1);
  36. % Parsing interface.
  37. symbolic procedure matstat;
  38. % Read a matrix.
  39. begin scalar x,y;
  40. a: scan();
  41. scan();
  42. y := xread 'paren;
  43. if not eqcar(y,'!*comma!*) then y := list y else y := remcomma y;
  44. x := y . x;
  45. if nxtsym!* eq '!)
  46. then return <<scan(); scan(); 'mat . reversip x>>
  47. else if not(nxtsym!* eq '!,) then symerr("Syntax error",nil);
  48. go to a
  49. end;
  50. put('mat,'stat,'matstat);
  51. symbolic procedure formmat(u,vars,mode);
  52. 'list . mkquote 'mat
  53. . for each x in cdr u collect('list . formlis(x,vars,mode));
  54. put('mat,'formfn,'formmat);
  55. put('mat,'i2d,'mkscalmat);
  56. put('mat,'inversefn,'matinverse);
  57. put('mat,'lnrsolvefn,'lnrsolve);
  58. put('mat,'rtypefn,'(lambda (x) 'matrix));
  59. flag('(mat tp),'matflg);
  60. flag('(mat),'noncommuting);
  61. put('mat,'prifn,'matpri);
  62. flag('(mat),'struct); % for parsing
  63. put('matrix,'fn,'matflg);
  64. put('matrix,'evfn,'matsm!*);
  65. flag('(matrix),'sprifn);
  66. put('matrix,'tag,'mat);
  67. put('matrix,'lengthfn,'matlength);
  68. put('matrix,'getelemfn,'getmatelem);
  69. put('matrix,'setelemfn,'setmatelem);
  70. symbolic procedure mkscalmat u;
  71. % Converts id u to 1 by 1 matrix.
  72. list('mat,list u);
  73. symbolic procedure getmatelem u;
  74. begin scalar x;
  75. x := get(car u,'rvalue);
  76. if not eqcar(x,'mat) then rederr list("Matrix",car u,"not set")
  77. else if not numlis (u := revlis cdr u) or length u neq 2
  78. then errpri2(x . u,t);
  79. return nth(nth(cdr x,car u),cadr u)
  80. end;
  81. symbolic procedure setmatelem(u,v); letmtr(u,v,get(car u,'rvalue));
  82. symbolic procedure matlength u;
  83. if not eqcar(u,'mat) then rederr list("Matrix",u,"not set")
  84. else list('list,length cdr u,length cadr u);
  85. symbolic procedure matsm!*(u,v);
  86. % Matrix expression simplification function.
  87. begin
  88. u := 'mat . for each j in matsm u collect
  89. for each k in j collect mk!*sq2 k;
  90. !*sub2 := nil; %since all substitutions done;
  91. return u
  92. end;
  93. symbolic procedure mk!*sq2 u;
  94. begin scalar x;
  95. x := !*sub2; %since we need value for each element;
  96. u := subs2 u;
  97. !*sub2 := x;
  98. return mk!*sq u
  99. end;
  100. symbolic procedure matsm u;
  101. begin scalar x,y;
  102. for each j in nssimp(u,'matrix) do
  103. <<y := multsm(car j,matsm1 cdr j);
  104. x := if null x then y else addm(x,y)>>;
  105. return x
  106. end;
  107. symbolic procedure matsm1 u;
  108. %returns matrix canonical form for matrix symbol product U;
  109. begin scalar x,y,z; integer n;
  110. a: if null u then return z
  111. else if eqcar(car u,'!*div) then go to d
  112. else if atom car u then go to er
  113. else if caar u eq 'mat then go to c1
  114. else x := apply(caar u,cdar u);
  115. b: z := if null z then x
  116. else if null cdr z and null cdar z then multsm(caar z,x)
  117. else multm(x,z);
  118. c: u := cdr u;
  119. go to a;
  120. c1: if not lchk cdar u then rederr "Matrix mismatch";
  121. x := for each j in cdar u collect
  122. for each k in j collect xsimp k;
  123. go to b;
  124. d: y := matsm cadar u;
  125. if (n := length car y) neq length y
  126. then rederr "Non square matrix"
  127. else if (z and n neq length z) then rederr "Matrix mismatch"
  128. else if cddar u then go to h
  129. else if null cdr y and null cdar y then go to e;
  130. x := subfg!*;
  131. subfg!* := nil;
  132. if null z then z := apply1(get('mat,'inversefn),y)
  133. else if null(x := get('mat,'lnrsolvefn))
  134. then z := multm(apply1(get('mat,'inversefn),y),z)
  135. else z := apply2(get('mat,'lnrsolvefn),y,z);
  136. subfg!* := x;
  137. % Make sure there are no power substitutions.
  138. z := for each j in z collect for each k in j collect
  139. <<!*sub2 := t; subs2 k>>;
  140. go to c;
  141. e: if null caaar y then rederr "Zero denominator";
  142. y := revpr caar y;
  143. z := if null z then list list y else multsm(y,z);
  144. go to c;
  145. h: if null z then z := generateident n;
  146. go to c;
  147. er: rederr list("Matrix",car u,"not set")
  148. end;
  149. symbolic procedure lchk u;
  150. begin integer n;
  151. if null u or atom car u then return nil;
  152. n := length car u;
  153. repeat u := cdr u
  154. until null u or atom car u or length car u neq n;
  155. return null u
  156. end;
  157. symbolic procedure addm(u,v);
  158. %returns sum of two matrix canonical forms U and V;
  159. for each j in addm1(u,v,function cons)
  160. collect addm1(car j,cdr j,function addsq);
  161. symbolic procedure addm1(u,v,w);
  162. if null u and null v then nil
  163. else if null u or null v then rederr "Matrix mismatch"
  164. else apply(w,list(car u,car v)) . addm1(cdr u,cdr v,w);
  165. symbolic procedure tp u; tp1 matsm u;
  166. put('tp,'rtypefn,'getrtypecar);
  167. symbolic procedure tp1 u;
  168. %returns transpose of the matrix canonical form U;
  169. %U is destroyed in the process;
  170. begin scalar v,w,x,y,z;
  171. v := w := list nil;
  172. while car u do
  173. <<x := u;
  174. y := z := list nil;
  175. while x do
  176. <<z := cdr rplacd(z,list caar x);
  177. x := cdr rplaca(x,cdar x)>>;
  178. w := cdr rplacd(w,list cdr y)>>;
  179. return cdr v
  180. end;
  181. symbolic procedure scalprod(u,v);
  182. %returns scalar product of two lists (vectors) U and V;
  183. if null u and null v then nil ./ 1
  184. else if null u or null v then rederr "Matrix mismatch"
  185. else addsq(multsq(car u,car v),scalprod(cdr u,cdr v));
  186. symbolic procedure multm(u,v);
  187. %returns matrix product of two matrix canonical forms U and V;
  188. (lambda x;
  189. for each y in u collect for each k in x collect scalprod(y,k))
  190. tp1 v;
  191. symbolic procedure multsm(u,v);
  192. %returns product of standard quotient U and matrix standard form V;
  193. if u = (1 ./ 1) then v
  194. else for each j in v collect for each k in j collect multsq(u,k);
  195. symbolic procedure letmtr(u,v,y);
  196. %substitution for matrix elements;
  197. begin scalar z;
  198. if not eqcar(y,'mat) then rederr list("Matrix",car u,"not set")
  199. else if not numlis (z := revlis cdr u) or length z neq 2
  200. then return errpri2(u,'hold);
  201. rplaca(pnth(nth(cdr y,car z),cadr z),v);
  202. end;
  203. endmodule;
  204. module matpri; % Matrix printing routines.
  205. % Author: Anthony C. Hearn;
  206. global '(!*nat);
  207. symbolic procedure setmatpri(u,v);
  208. matpri1(cdr v,u);
  209. put('mat,'setprifn,'setmatpri);
  210. symbolic procedure matpri u;
  211. matpri1(cdr u,"MAT");
  212. symbolic procedure matpri1(u,x);
  213. %prints a matrix canonical form U with name X;
  214. begin scalar m,n;
  215. m := 1;
  216. for each y in u do
  217. <<n := 1;
  218. for each z in y do
  219. <<varpri(z,list('setq,list(x,m,n),z),'only); n := n+1>>;
  220. m := m+1>>
  221. end;
  222. endmodule;
  223. module bareiss; % Inversion routines using the Bareiss 2-step method.
  224. % Author: Anthony C. Hearn;
  225. % This module is rife with essential references to RPLAC-based
  226. % functions.
  227. fluid '(!*exp asymplis!*);
  228. global '(wtl!*);
  229. symbolic procedure matinverse u;
  230. lnrsolve(u,generateident length u);
  231. symbolic procedure lnrsolve(u,v);
  232. %U is a matrix standard form, V a compatible matrix form.
  233. %Value is U**(-1)*V.
  234. begin integer n; scalar !*exp,temp;
  235. !*exp := t; n := length u;
  236. if asymplis!* or wtl!*
  237. then <<temp := asymplis!* . wtl!*;
  238. asymplis!* := wtl!* := nil>>;
  239. v := backsub(bareiss car normmat augment(u,v),n);
  240. if temp then <<asymplis!* := car temp; wtl!* := cdr temp>>;
  241. u := rhside(car v,n);
  242. v := cdr v;
  243. return if temp
  244. then for each j in u collect
  245. for each k in j collect resimp(k ./ v)
  246. else for each j in u collect
  247. for each k in j collect cancel(k ./ v)
  248. end;
  249. symbolic procedure augment(u,v);
  250. if null u then nil else append(car u,car v) . augment(cdr u,cdr v);
  251. symbolic procedure generateident n;
  252. %returns matrix canonical form of identity matrix of order N.
  253. begin scalar u,v;
  254. for i := 1:n do
  255. <<u := nil;
  256. for j := 1:n do u := ((if i=j then 1 else nil) . 1) . u;
  257. v := u . v>>;
  258. return v
  259. end;
  260. symbolic procedure rhside(u,m);
  261. if null u then nil else pnth(car u,m+1) . rhside(cdr u,m);
  262. symbolic procedure bareiss u;
  263. %The 2-step integer preserving elimination method of Bareiss
  264. %based on the implementation of Lipson.
  265. %If the value of procedure is NIL then U is singular, otherwise the
  266. %value is the triangularized form of U (in matrix polynomial form).
  267. begin scalar aa,c0,ci1,ci2,ik1,ij,kk1,kj,k1j,k1k1,ui,u1,x;
  268. integer k,k1;
  269. %U1 points to K-1th row of U
  270. %UI points to Ith row of U
  271. %IJ points to U(I,J)
  272. %K1J points to U(K-1,J)
  273. %KJ points to U(K,J)
  274. %IK1 points to U(I,K-1)
  275. %KK1 points to U(K,K-1)
  276. %K1K1 points to U(K-1,K-1)
  277. %M in comments is number of rows in U
  278. %N in comments is number of columns in U.
  279. aa:= 1;
  280. k:= 2;
  281. k1:=1;
  282. u1:=u;
  283. go to pivot;
  284. agn: u1 := cdr u1;
  285. if null cdr u1 or null cddr u1 then return u;
  286. aa:=nth(car u1,k); %aa := u(k,k).
  287. k:=k+2;
  288. k1:=k-1;
  289. u1:=cdr u1;
  290. pivot: %pivot algorithm.
  291. k1j:= k1k1 := pnth(car u1,k1);
  292. if car k1k1 then go to l2;
  293. ui:= cdr u1; %i := k.
  294. l: if null ui then return nil
  295. else if null car(ij := pnth(car ui,k1))
  296. then go to l1;
  297. l0: if null ij then go to l2;
  298. x:= car ij;
  299. rplaca(ij,negf car k1j);
  300. rplaca(k1j,x);
  301. ij:= cdr ij;
  302. k1j:= cdr k1j;
  303. go to l0;
  304. l1: ui:= cdr ui;
  305. go to l;
  306. l2: ui:= cdr u1; %i:= k;
  307. l21: if null ui then return; %if i>m then return;
  308. ij:= pnth(car ui,k1);
  309. c0:= addf(multf(car k1k1,cadr ij),
  310. multf(cadr k1k1,negf car ij));
  311. if c0 then go to l3;
  312. ui:= cdr ui; %i:= i+1;
  313. go to l21;
  314. l3: c0:= quotf!*(c0,aa);
  315. kk1 := kj := pnth(cadr u1,k1); %kk1 := u(k,k-1);
  316. if cdr u1 and null cddr u1 then go to ev0
  317. else if ui eq cdr u1 then go to comp;
  318. l31: if null ij then go to comp; %if i>n then go to comp;
  319. x:= car ij;
  320. rplaca(ij,negf car kj);
  321. rplaca(kj,x);
  322. ij:= cdr ij;
  323. kj:= cdr kj;
  324. go to l31;
  325. %pivoting complete.
  326. comp:
  327. if null cdr u1 then go to ev;
  328. ui:= cddr u1; %i:= k+1;
  329. comp1:
  330. if null ui then go to ev; %if i>m then go to ev;
  331. ik1:= pnth(car ui,k1);
  332. ci1:= quotf!*(addf(multf(cadr k1k1,car ik1),
  333. multf(car k1k1,negf cadr ik1)),
  334. aa);
  335. ci2:= quotf!*(addf(multf(car kk1,cadr ik1),
  336. multf(cadr kk1,negf car ik1)),
  337. aa);
  338. if null cddr k1k1 then go to comp3;%if j>n then go to comp3;
  339. ij:= cddr ik1; %j:= k+1;
  340. kj:= cddr kk1;
  341. k1j:= cddr k1k1;
  342. comp2:
  343. if null ij then go to comp3;
  344. rplaca(ij,quotf!*(addf(multf(car ij,c0),
  345. addf(multf(car kj,ci1),
  346. multf(car k1j,ci2))),
  347. aa));
  348. ij:= cdr ij;
  349. kj:= cdr kj;
  350. k1j:= cdr k1j;
  351. go to comp2;
  352. comp3:
  353. ui:= cdr ui;
  354. go to comp1;
  355. ev0:if null c0 then return;
  356. ev: kj := cdr kk1;
  357. x := cddr k1k1; %x := u(k-1,k+1);
  358. rplaca(kj,c0);
  359. ev1:kj:= cdr kj;
  360. if null kj then go to agn;
  361. rplaca(kj,quotf!*(addf(multf(car k1k1,car kj),
  362. multf(car kk1,negf car x)),
  363. aa));
  364. x := cdr x;
  365. go to ev1
  366. end;
  367. symbolic procedure backsub(u,m);
  368. begin scalar detm,det1,ij,ijj,ri,summ,uj,ur; integer i,jj;
  369. %N in comments is number of columns in U.
  370. if null u then rederr "Singular matrix";
  371. ur := reverse u;
  372. detm := car pnth(car ur,m); %detm := u(i,j).
  373. if null detm then rederr "Singular matrix";
  374. i := m;
  375. rows:
  376. i := i-1;
  377. ur := cdr ur;
  378. if null ur then return u . detm;
  379. %if i=0 then return u . detm.
  380. ri := car ur;
  381. jj := m+1;
  382. ijj:=pnth(ri,jj);
  383. r2: if null ijj then go to rows; %if jj>n then go to rows;
  384. ij := pnth(ri,i); %j := i;
  385. det1 := car ij; %det1 := u(i,i);
  386. uj := pnth(u,i);
  387. summ := nil; %summ := 0;
  388. r3: uj := cdr uj; %j := j+1;
  389. if null uj then go to r4; %if j>m then go to r4;
  390. ij := cdr ij;
  391. summ := addf(summ,multf(car ij,nth(car uj,jj)));
  392. %summ:=summ+u(i,j)*u(j,jj);
  393. go to r3;
  394. r4: rplaca(ijj,quotf!*(addf(multf(detm,car ijj),negf summ),det1));
  395. %u(i,j):=(detm*u(i,j)-summ)/det1;
  396. jj := jj+1;
  397. ijj := cdr ijj;
  398. go to r2
  399. end;
  400. symbolic procedure normmat u;
  401. %U is a matrix standard form.
  402. %Value is dotted pair of matrix polynomial form and factor.
  403. begin scalar x,y,z;
  404. x := 1;
  405. for each v in u do
  406. <<y := 1;
  407. for each w in v do y := lcm(y,denr w);
  408. z := (for each w in v
  409. collect multf(numr w,quotf(y,denr w)))
  410. . z;
  411. x := multf(y,x)>>;
  412. return reverse z . x
  413. end;
  414. endmodule;
  415. module det; % Determinant and trace routines.
  416. % Author: Anthony C. Hearn;
  417. symbolic procedure simpdet u; detq matsm carx(u,'det);
  418. % The hashing and determinant routines below are due to M. L. Griss.
  419. comment Some general purpose hashing functions;
  420. flag('(array),'eval); %declared again for bootstrapping purposes;
  421. array !$hash 64; %general array for hashing;
  422. symbolic procedure gethash key;
  423. %access previously saved element;
  424. assoc(key,!$hash(remainder(key,64)));
  425. symbolic procedure puthash(key,valu);
  426. begin integer k; scalar buk;
  427. k := remainder(key,64);
  428. buk := (key . valu) . !$hash k;
  429. !$hash k := buk;
  430. return car buk
  431. end;
  432. symbolic procedure clrhash;
  433. for i := 0:64 do !$hash i := nil;
  434. comment Determinant Routines;
  435. symbolic procedure detq u;
  436. %top level determinant function;
  437. begin integer len;
  438. len := length u; %number of rows;
  439. for each x in u do
  440. if length x neq len then rederr "NON SQUARE MATRIX";
  441. if len=1 then return caar u;
  442. clrhash();
  443. u := detq1(u,len,0);
  444. clrhash();
  445. return u
  446. end;
  447. symbolic procedure detq1(u,len,ignnum);
  448. %U is a square matrix of order LEN. Value is the determinant of U;
  449. %Algorithm is expansion by minors of first row;
  450. %IGNNUM is packed set of column indices to avoid;
  451. begin integer n2; scalar row,sign,z;
  452. row := car u; %current row;
  453. n2 := 1;
  454. if len=1
  455. then return <<while twomem(n2,ignnum)
  456. do <<n2 := 2*n2; row := cdr row>>;
  457. car row>>; %last row, single element;
  458. if z := gethash ignnum then return cdr z;
  459. len := len-1;
  460. u := cdr u;
  461. z := nil ./ 1;
  462. for each x in row do
  463. <<if not twomem(n2,ignnum)
  464. then <<if numr x
  465. then <<if sign then x := negsq x;
  466. z:= addsq(multsq(x,detq1(u,len,n2+ignnum)),
  467. z)>>;
  468. sign := not sign>>;
  469. n2 := 2*n2>>;
  470. puthash(ignnum,z);
  471. return z
  472. end;
  473. symbolic procedure twomem(n1,n2);
  474. %for efficiency reasons, this procedure should be coded in assembly
  475. %language;
  476. not evenp(n2/n1);
  477. put('det,'simpfn,'simpdet);
  478. symbolic procedure simptrace u;
  479. begin integer n; scalar z;
  480. u := matsm carx(u,'trace);
  481. if length u neq length car u then rederr "NON SQUARE MATRIX";
  482. n := 1;
  483. z := nil ./ 1;
  484. for each x in u do <<z := addsq(nth(x,n),z); n := n+1>>;
  485. return z
  486. end;
  487. put('trace,'simpfn,'simptrace);
  488. endmodule;
  489. module glmat; % Routines for inverting matrices and finding eigen-values
  490. % and vectors. Methods are the same as in glsolve module.
  491. % Author: Eberhard Schruefer.
  492. fluid '(!*cramer !*gcd kord!*);
  493. global '(!!arbint);
  494. if null !!arbint then !!arbint := 0;
  495. switch cramer;
  496. put('cramer,'simpfg,
  497. '((t (put 'mat 'lnrsolvefn 'clnrsolve)
  498. (put 'mat 'inversefn 'matinv))
  499. (nil (put 'mat 'lnrsolvefn 'lnrsolve)
  500. (put 'mat 'inversefn 'matinverse))));
  501. % algebraic operator arbcomplex;
  502. % Done this way since it's also defined in the solve1 module.
  503. deflist('((arbcomplex simpiden)),'simpfn);
  504. symbolic procedure clnrsolve(u,v);
  505. %interface to matrix package.
  506. multm(matinv u,v);
  507. symbolic procedure minv u;
  508. matinv matsm u;
  509. put('minv,'rtypefn,'(lambda (x) 'matrix));
  510. flag('(minv),'matflg);
  511. %put('mateigen,'rtypefn,'(lambda (x) 'matrix));
  512. remprop('mateigen,'rtypefn);
  513. %flag('(mateigen),'matflg);
  514. remflag('(mateigen),'matflg);
  515. put('detex,'simpfn,'detex);
  516. symbolic procedure matinv u;
  517. %u is a matrix form. Result is the inverse of matrix u.
  518. begin scalar sgn,x,y,z;
  519. integer l,m,lm;
  520. z := 1;
  521. lm := length car u;
  522. for each v in u do
  523. <<y := 1;
  524. for each w in v do y := lcm(y,denr w);
  525. m := lm;
  526. x := list(nil . (l := l + 1)) .* negf y .+ nil;
  527. for each j in reverse v do
  528. <<if numr j then
  529. x := list m .* multf(numr j,quotf(y,denr j)) .+ x;
  530. m := m - 1>>;
  531. z := c!:extmult(x,z)>>;
  532. if singularchk lpow z then rederr "singular matrix";
  533. sgn := evenp length lpow z;
  534. return for each k in lpow z collect
  535. <<sgn := not sgn;
  536. for each j in lpow z collect mkglimat(k,z,sgn,j)>>
  537. end;
  538. symbolic procedure singularchk u;
  539. pairp car reverse u;
  540. flag('(mateigen),'opfn);
  541. flag('(mateigen),'noval);
  542. symbolic procedure mateigen(u,eival);
  543. %u is a matrix form, eival an indeterminate naming the eigenvalues.
  544. %Result is a list of lists:
  545. % {{eival-eq1,multiplicity1,eigenvector1},....},
  546. %where eival-eq is a polynomial and eigenvector is a matrix.
  547. % How much should we attempt to solve the eigenvalue eq.? sqfr?
  548. % Sqfr is necessary if we want to have the full eigenspace. If there
  549. % are multiple roots another pass through eigenvector calculation
  550. % is needed(done).
  551. % We should actually perform the calculations in the extension
  552. % field generated by the eigenvalue equation(done inside).
  553. %*** needs still checking; seems to do fairly well.
  554. begin scalar arbvars,exu,sgn,q,r,s,x,y,z,eivec;
  555. integer l,m,lm;
  556. z := 1;
  557. if not(getrtype u eq 'matrix) then typerr(u,"matrix");
  558. u := matsm u;
  559. lm := length car u;
  560. exu := for each v in u collect
  561. <<y := 1;
  562. for each w in v do y := lcm(y,denr w);
  563. m := lm;
  564. l := l + 1;
  565. x := nil;
  566. for each j in reverse v do
  567. <<if l=m then j := addsq(j,negsq !*k2q !*a2k eival);
  568. if numr j then
  569. x := list m .* multf(numr j,quotf(y,denr j)) .+ x;
  570. m := m - 1>>;
  571. y := z;
  572. z := c!:extmult(if null red x then <<
  573. q := (if p then (car p . (cdr p + 1)) . delete(p,q)
  574. else (lc x . 1) . q) where p = assoc(lc x,q);
  575. !*p2f lpow x>> else x,z);
  576. x>>;
  577. r := if minusf lc z then negf lc z else lc z;
  578. r := numr subs2(r ./ 1);
  579. kord!* := eival . kord!*;
  580. if domainp r then s := 1 else
  581. s := comfac!-to!-poly comfac(r := reorder r);
  582. r := quotf1(r,s);
  583. r := if domainp r then nil else sqfrf r;
  584. if null domainp s and (mvar s eq eival) then
  585. if red s then r := (s . 1) . r
  586. else r := (!*k2f eival . ldeg s) . r;
  587. for each j in q do r := (absf reorder car j . cdr j) . r;
  588. kord!* := cdr kord!*;
  589. r := for each j in r collect reorder car j . cdr j;
  590. l := length r;
  591. return 'list .
  592. for each j in r collect
  593. <<if null((cdr j = 1) and (l = 1)) then
  594. <<y := 1;
  595. for each k in exu do
  596. if x := reduce!-mod!-eig(car j,c!:extmult(k,y))
  597. then y := x>>;
  598. arbvars := nil;
  599. for each k in lpow z do
  600. if (y=1) or null(k member lpow y) then
  601. arbvars := (k . makearbcomplex()) . arbvars;
  602. sgn := (y=1) or evenp length lpow y;
  603. eivec := 'mat . for each k in lpow z collect list
  604. if x := assoc(k,arbvars)
  605. then mvar cdr x
  606. else prepsq!* mkgleig(k,y,
  607. sgn := not sgn,arbvars);
  608. list('list,prepsq!*(car j ./ 1),cdr j,eivec)>>
  609. end;
  610. symbolic procedure reduce!-mod!-eig(u,v);
  611. %reduces exterior product v wrt eigenvalue equation u.
  612. begin scalar x,y;
  613. for each j on v do
  614. if numr(y := reduce!-mod!-eigf(u,lc j)) then
  615. x := lpow j .* y .+ x;
  616. y := 1;
  617. for each j on x do y := lcm(y,denr lc j);
  618. return for each j on reverse x collect
  619. lpow j .* multf(numr lc j,quotf(y,denr lc j))
  620. end;
  621. symbolic procedure reduce!-mod!-eigf(u,v);
  622. subs2 reduce!-eival!-powers(lpow u . negsq cancel(red u ./ lc u),v);
  623. symbolic procedure reduce!-eival!-powers(v,u);
  624. if domainp u then u ./ 1
  625. else if mvar u eq caar v then reduce!-eival!-powers1(v,u ./ 1)
  626. else if ordop(caar v,mvar u) then u ./ 1
  627. else addsq(multpq(lpow u,reduce!-eival!-powers(v,lc u)),
  628. reduce!-eival!-powers(v,red u));
  629. symbolic procedure reduce!-eival!-powers1(v,u);
  630. %reduces powers with the help of the eigenvalue polynomial;
  631. if domainp numr u or (ldeg numr u<pdeg car v) then u
  632. else if ldeg numr u=pdeg car v then
  633. addsq(multsq(cdr v,lc numr u ./ denr u),
  634. red numr u ./ denr u)
  635. else reduce!-eival!-powers1(v,
  636. addsq(multsq(multpf(mvar numr u .** (ldeg numr u-pdeg car v),
  637. lc numr u) ./ denr u,
  638. cdr v),red numr u ./ denr u));
  639. symbolic procedure detex u;
  640. %u is a matrix form, result is determinant of u.
  641. begin scalar f,x,y,z;
  642. integer m,lm;
  643. z := 1;
  644. u := matsm car u;
  645. lm := length car u;
  646. f := 1;
  647. for each v in u do
  648. <<y := 1;
  649. for each w in v do y := lcm(y,denr w);
  650. f := multf(y,f);
  651. m := lm;
  652. x := nil;
  653. for each j in v do
  654. <<if numr j then
  655. x := list m .* multf(numr j,quotf(y,denr j)) .+ x;
  656. m := m - 1>>;
  657. z := c!:extmult(x,z)>>;
  658. return cancel(lc z ./ f)
  659. end;
  660. symbolic procedure mkglimat(u,v,sgn,k);
  661. begin scalar s,x,y;
  662. x := nil ./ 1;
  663. y := lpow v;
  664. for each j on red v do
  665. if s := glmatterm(u,y,j,k)
  666. then x := addsq(cancel(s ./ lc v),x);
  667. return if sgn then negsq x else x
  668. end;
  669. symbolic procedure glmatterm(u,v,w,k);
  670. begin scalar x,y,sgn;
  671. x := lpow w;
  672. a: if null x then return
  673. if pairp car y and (cdar y = k) then lc w else nil;
  674. if car x = u then return nil
  675. else if car x member v then <<x := cdr x;
  676. if y then sgn := not sgn>>
  677. else if y then return nil
  678. else <<y := list car x; x := cdr x>>;
  679. go to a
  680. end;
  681. symbolic procedure mkgleig(u,v,sgn,arbvars);
  682. begin scalar s,x,y,!*gcd;
  683. x := nil ./ 1;
  684. y := lpow v;
  685. !*gcd := t;
  686. for each j on red v do
  687. if s := glsoleig(u,y,j,arbvars)
  688. then x := addsq(cancel(s ./ lc v),x);
  689. return if sgn then negsq x else x
  690. end;
  691. symbolic procedure glsoleig(u,v,w,arbvars);
  692. begin scalar x,y,sgn;
  693. x := lpow w;
  694. a: if null x then return
  695. if null car y then lc w
  696. else multf(cdr assoc(car y,arbvars),
  697. if sgn then negf lc w else lc w);
  698. if car x = u then return nil
  699. else if car x member v then <<x := cdr x;
  700. if y then sgn := not sgn>>
  701. else if y then return nil
  702. else <<y := list car x; x := cdr x>>;
  703. go to a
  704. end;
  705. %**** Support for exterior multiplication ****
  706. % Data structure is lpow ::= list of col.-ind. in exterior product
  707. % | nil . number of eq. for inhomog. terms.
  708. % lc ::= standard form
  709. symbolic procedure c!:extmult(u,v);
  710. %Special exterior multiplication routine. Degree of form v is
  711. %arbitrary, u is a one-form.
  712. if null u or null v then nil
  713. else if v = 1 then u %unity
  714. else (if x then cdr x .* (if car x then negf multf(lc u,lc v)
  715. else multf(lc u,lc v))
  716. .+ c!:extadd(c!:extmult(!*t2f lt u,red v),
  717. c!:extmult(red u,v))
  718. else c!:extadd(c!:extmult(!*t2f lt u,red v),
  719. c!:extmult(red u,v)))
  720. where x = c!:ordexn(car lpow u,lpow v);
  721. symbolic procedure c!:extadd(u,v);
  722. if null u then v
  723. else if null v then u
  724. else if lpow u = lpow v then
  725. (lambda x,y; if null x then y else lpow u .* x .+ y)
  726. (addf(lc u,lc v),c!:extadd(red u,red v))
  727. else if c!:ordexp(lpow u,lpow v) then lt u .+ c!:extadd(red u,v)
  728. else lt v .+ c!:extadd(u,red v);
  729. symbolic procedure c!:ordexp(u,v);
  730. if null u then t
  731. else if car u = car v then c!:ordexp(cdr u,cdr v)
  732. else c!:ordxp(car u,car v);
  733. symbolic procedure c!:ordexn(u,v);
  734. %u is a single index, v a list. Returns nil if u is a member
  735. %of v or a dotted pair of a permutation indicator and the ordered
  736. %list of u merged into v.
  737. begin scalar s,x;
  738. a: if null v then return(s . reverse(u . x))
  739. else if (u = car v) or (pairp u and pairp car v)
  740. then return nil
  741. else if c!:ordxp(u,car v) then
  742. return(s . append(reverse(u . x),v))
  743. else <<x := car v . x;
  744. v := cdr v;
  745. s := not s>>;
  746. go to a
  747. end;
  748. symbolic procedure c!:ordxp(u,v);
  749. if pairp u then if pairp v then cdr u < cdr v
  750. else nil
  751. else if pairp v then t
  752. else u < v;
  753. endmodule;
  754. end;