matrix.red 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514
  1. module matrix; % Header for matrix package.
  2. % Author: Anthony C. Hearn.
  3. % This module is rife with essential references to RPLAC-based
  4. % functions.
  5. create!-package('(matrix matpri bareiss det glmat nullsp rank
  6. resultant cofactor),nil);
  7. fluid '(!*sub2);
  8. global '(nxtsym!* subfg!*);
  9. symbolic procedure matrix u;
  10. % Declares list U as matrices.
  11. begin scalar v,w,x;
  12. for each j in u do
  13. if atom j then if null (x := gettype j)
  14. then put(j,'rtype,'matrix)
  15. else if x eq 'matrix
  16. then <<lprim list(x,j,"redefined");
  17. put(j,'rtype,'matrix)>>
  18. else typerr(list(x,j),"matrix")
  19. else if not idp car j
  20. or length (v := revlis cdr j) neq 2
  21. or not natnumlis v
  22. then errpri2(j,'hold)
  23. else if not (x := gettype car j) or x eq 'matrix
  24. then <<w := nil;
  25. for n := 1:car v do w := nzero cadr v . w;
  26. put(car j,'rtype,'matrix);
  27. put(car j,'avalue,list('matrix,'mat . w))>>
  28. else typerr(list(x,car j),"matrix")
  29. end;
  30. symbolic procedure natnumlis u;
  31. % True if U is a list of natural numbers.
  32. null u or fixp car u and car u>0 and natnumlis cdr u;
  33. rlistat '(matrix);
  34. symbolic procedure nzero n;
  35. % Returns a list of N zeros.
  36. if n=0 then nil else 0 . nzero(n-1);
  37. % Parsing interface.
  38. symbolic procedure matstat;
  39. % Read a matrix.
  40. begin scalar x,y;
  41. if not (nxtsym!* eq '!() then symerr("Syntax error",nil);
  42. a: scan();
  43. if not (scan() eq '!*lpar!*) then symerr("Syntax error",nil);
  44. y := xread 'paren;
  45. if not eqcar(y,'!*comma!*) then y := list y else y := remcomma y;
  46. x := y . x;
  47. if nxtsym!* eq '!)
  48. then return <<scan(); scan(); 'mat . reversip x>>
  49. else if not(nxtsym!* eq '!,) then symerr("Syntax error",nil);
  50. go to a
  51. end;
  52. put('mat,'stat,'matstat);
  53. symbolic procedure formmat(u,vars,mode);
  54. 'list . mkquote car u
  55. . for each x in cdr u collect('list . formlis(x,vars,mode));
  56. put('mat,'formfn,'formmat);
  57. put('mat,'i2d,'mkscalmat);
  58. put('mat,'inversefn,'matinverse);
  59. put('mat,'lnrsolvefn,'lnrsolve);
  60. put('mat,'rtypefn,'quotematrix);
  61. symbolic procedure quotematrix u; 'matrix;
  62. flag('(mat tp),'matflg);
  63. flag('(mat),'noncommuting);
  64. put('mat,'prifn,'matpri);
  65. flag('(mat),'struct); % for parsing
  66. put('matrix,'fn,'matflg);
  67. put('matrix,'evfn,'matsm!*);
  68. flag('(matrix),'sprifn);
  69. put('matrix,'tag,'mat);
  70. put('matrix,'lengthfn,'matlength);
  71. put('matrix,'getelemfn,'getmatelem);
  72. put('matrix,'setelemfn,'setmatelem);
  73. symbolic procedure mkscalmat u;
  74. % Converts id u to 1 by 1 matrix.
  75. list('mat,list u);
  76. symbolic procedure getmatelem u;
  77. begin scalar x;
  78. x := get(car u,'avalue);
  79. if null x or not(car x eq 'matrix) then typerr(car u,"matrix")
  80. else if not eqcar(x := cadr x,'mat)
  81. then if idp x
  82. then return getmatelem (x . cdr u)
  83. else rerror(matrix,1,list("Matrix",car u,"not set"))
  84. else if not numlis (u := revlis cdr u) or length u neq 2
  85. then errpri2(x . u,t)
  86. else return nth(nth(cdr x,car u),cadr u);
  87. end;
  88. symbolic procedure setmatelem(u,v); letmtr(u,v,cadr get(car u,'avalue));
  89. symbolic procedure matlength u;
  90. if not eqcar(u,'mat) then rerror(matrix,2,list("Matrix",u,"not set"))
  91. else list('list,length cdr u,length cadr u);
  92. % Aggregate Property. Commented out for now.
  93. % symbolic procedure matrixmap(u,v);
  94. % if flagp(car u,'matmapfn)
  95. % then matsm!*1 for each j in matsm cadr u collect
  96. % for each k in j collect simp!*(car u . mk!*sq k . cddr u)
  97. % else if flagp(car u,'matfn) then reval2(u,v)
  98. % else typerr(car u,"matrix operator");
  99. % put('matrix,'aggregatefn,'matrixmap);
  100. % flag('(int df),'matmapfn);
  101. % flag('(det trace),'matfn);
  102. symbolic procedure matsm!*(u,v);
  103. % Matrix expression simplification function.
  104. matsm!*1 matsm u;
  105. symbolic procedure matsm!*1 u;
  106. begin scalar sub2;
  107. sub2 := !*sub2; % Since we need value for each element.
  108. u := 'mat . for each j in u collect
  109. for each k in j
  110. collect <<!*sub2 := sub2; !*q2a subs2 k>>;
  111. !*sub2 := nil; % Since all substitutions done.
  112. return u
  113. end;
  114. symbolic procedure mk!*sq2 u;
  115. begin scalar x;
  116. x := !*sub2; % Since we need value for each element.
  117. u := subs2 u;
  118. !*sub2 := x;
  119. return mk!*sq u
  120. end;
  121. symbolic procedure matsm u;
  122. begin scalar x,y;
  123. for each j in nssimp(u,'matrix) do
  124. <<y := multsm(car j,matsm1 cdr j);
  125. x := if null x then y else addm(x,y)>>;
  126. return x
  127. end;
  128. symbolic procedure matsm1 u;
  129. %returns matrix canonical form for matrix symbol product U;
  130. begin scalar x,y,z; integer n;
  131. a: if null u then return z
  132. else if eqcar(car u,'!*div) then go to d
  133. else if atom car u then go to er
  134. else if caar u eq 'mat then go to c1
  135. else x := lispapply(caar u,cdar u);
  136. b: z := if null z then x
  137. else if null cdr z and null cdar z then multsm(caar z,x)
  138. else multm(x,z);
  139. c: u := cdr u;
  140. go to a;
  141. c1: if not lchk cdar u then rerror(matrix,3,"Matrix mismatch");
  142. x := for each j in cdar u collect
  143. for each k in j collect xsimp k;
  144. go to b;
  145. d: y := matsm cadar u;
  146. if (n := length car y) neq length y
  147. then rerror(matrix,4,"Non square matrix")
  148. else if (z and n neq length z)
  149. then rerror(matrix,5,"Matrix mismatch")
  150. else if cddar u then go to h
  151. else if null cdr y and null cdar y then go to e;
  152. x := subfg!*;
  153. subfg!* := nil;
  154. if null z then z := apply1(get('mat,'inversefn),y)
  155. else if null(x := get('mat,'lnrsolvefn))
  156. then z := multm(apply1(get('mat,'inversefn),y),z)
  157. else z := apply2(get('mat,'lnrsolvefn),y,z);
  158. subfg!* := x;
  159. % Make sure there are no power substitutions.
  160. z := for each j in z collect for each k in j collect
  161. <<!*sub2 := t; subs2 k>>;
  162. go to c;
  163. e: if null caaar y then rerror(matrix,6,"Zero divisor");
  164. y := revpr caar y;
  165. z := if null z then list list y else multsm(y,z);
  166. go to c;
  167. h: if null z then z := generateident n;
  168. go to c;
  169. er: rerror(matrix,7,list("Matrix",car u,"not set"))
  170. end;
  171. symbolic procedure lchk u;
  172. begin integer n;
  173. if null u or atom car u then return nil;
  174. n := length car u;
  175. repeat u := cdr u
  176. until null u or atom car u or length car u neq n;
  177. return null u
  178. end;
  179. symbolic procedure addm(u,v);
  180. %returns sum of two matrix canonical forms U and V;
  181. for each j in addm1(u,v,function cons)
  182. collect addm1(car j,cdr j,function addsq);
  183. symbolic procedure addm1(u,v,w);
  184. if null u and null v then nil
  185. else if null u or null v then rerror(matrix,8,"Matrix mismatch")
  186. else apply2(w,car u,car v) . addm1(cdr u,cdr v,w);
  187. symbolic procedure tp u; tp1 matsm u;
  188. put('tp,'rtypefn,'getrtypecar);
  189. symbolic procedure tp1 u;
  190. %returns transpose of the matrix canonical form U;
  191. %U is destroyed in the process;
  192. begin scalar v,w,x,y,z;
  193. v := w := list nil;
  194. while car u do
  195. <<x := u;
  196. y := z := list nil;
  197. while x do
  198. <<z := cdr rplacd(z,list caar x);
  199. x := cdr rplaca(x,cdar x)>>;
  200. w := cdr rplacd(w,list cdr y)>>;
  201. return cdr v
  202. end;
  203. symbolic procedure scalprod(u,v);
  204. %returns scalar product of two lists (vectors) U and V;
  205. if null u and null v then nil ./ 1
  206. else if null u or null v then rerror(matrix,9,"Matrix mismatch")
  207. else addsq(multsq(car u,car v),scalprod(cdr u,cdr v));
  208. symbolic procedure multm(u,v);
  209. %returns matrix product of two matrix canonical forms U and V;
  210. (for each y in u
  211. collect for each k in x collect subs2 scalprod(y,k))
  212. where x = tp1 v;
  213. symbolic procedure multsm(u,v);
  214. %returns product of standard quotient U and matrix standard form V;
  215. if u = (1 ./ 1) then v
  216. else for each j in v collect for each k in j collect multsq(u,k);
  217. symbolic procedure letmtr(u,v,y);
  218. %substitution for matrix elements;
  219. begin scalar z;
  220. if not eqcar(y,'mat)
  221. then rerror(matrix,10,list("Matrix",car u,"not set"))
  222. else if not numlis (z := revlis cdr u) or length z neq 2
  223. then return errpri2(u,'hold);
  224. rplaca(pnth(nth(cdr y,car z),cadr z),v);
  225. end;
  226. % Explicit substitution code for matrices.
  227. symbolic procedure matsub(u,v);
  228. 'mat . for each x in cdr v collect
  229. for each y in x collect subeval1(u,y);
  230. put('matrix,'subfn,'matsub);
  231. endmodule;
  232. module matpri; % Matrix printing routines.
  233. % Author: Anthony C. Hearn.
  234. % Modified by Arthur C. Norman.
  235. fluid '(!*nat orig!* pline!* posn!* ycoord!* ymax!* ymin!*);
  236. global '(obrkp!*);
  237. symbolic procedure setmatpri(u,v);
  238. matpri1(cdr v,u);
  239. put('mat,'setprifn,'setmatpri);
  240. symbolic procedure matpri u;
  241. matpri1(cdr u,nil);
  242. symbolic procedure matpri1(u,x);
  243. % Prints a matrix canonical form U with name X.
  244. % Tries to do fancy display if nat flag is on.
  245. begin scalar m,n,r,l,w,e,ll,ok,name,nw,widths,firstflag,toprow,lbar,
  246. rbar,realorig;
  247. if !*fort
  248. then <<m := 1;
  249. if null x then x := "MAT";
  250. for each y in u do
  251. <<n := 1;
  252. for each z in y do
  253. <<varpri(z,list('setq,list(x,m,n),z),'only);
  254. n := n+1>>;
  255. m := m+1>>;
  256. return nil>>;
  257. terpri!* t;
  258. if x and !*nat then <<
  259. name := layout!-formula(x, 0, nil);
  260. if name then <<
  261. nw := cdar name + 4;
  262. ok := !*nat >>>>
  263. else <<nw := 0; ok := !*nat>>;
  264. ll := linelength nil - spare!* - orig!*;
  265. m := length car u;
  266. widths := mkvect(1 + m);
  267. for i := 1:m do putv(widths, i, 1);
  268. % Collect sizes for all elements to see if it will fit in
  269. % displayed matrix form.
  270. % We need to compute things wrt a zero orig for the following
  271. % code to work properly.
  272. realorig := orig!*;
  273. orig!* := 0;
  274. if ok then for each y in u do
  275. <<n := 1;
  276. l := nil;
  277. w := 0;
  278. if ok then for each z in y do if ok then <<
  279. e := layout!-formula(z, 0, nil);
  280. if null e then ok := nil
  281. else begin
  282. scalar col;
  283. col := max(getv(widths, n), cdar e);
  284. % this allows for 2 blanks between cols, and also 2 extra chars, one
  285. % for the left-bar and one for the right-bar.
  286. if (w := w + col + 2) > ll then ok := nil
  287. else <<
  288. l := e . l;
  289. putv(widths, n, col) >> end;
  290. n := n+1>>;
  291. r := (reverse l) . r >>;
  292. if ok then <<
  293. % Matrix will fit in displayed representation.
  294. % Compute format with respect to 0 posn.
  295. firstflag := toprow := t;
  296. r := for each py on reverse r collect begin
  297. scalar y, ymin, ymax, pos, pl, k, w;
  298. ymin := ymax := 0;
  299. pos := 1; % Since "[" is of length 1.
  300. k := 1;
  301. pl := nil;
  302. y := car py;
  303. for each z in y do <<
  304. w := getv(widths, k);
  305. pl := append(update!-pline(pos+(w-cdar z)/2,0,caar z),
  306. pl); % Centre item in its field
  307. pos := pos + w + 2; % 2 blanks between cols
  308. k := k + 1;
  309. ymin := min(ymin, cadr z);
  310. ymax := max(ymax, cddr z) >>;
  311. k := nil;
  312. if firstflag then firstflag := nil
  313. else ymax := ymax + 1; % One blank line between rows
  314. for h := ymax step -1 until ymin do <<
  315. if toprow then <<
  316. lbar := symbol 'mat!-top!-l;
  317. rbar := symbol 'mat!-top!-r;
  318. toprow := nil >>
  319. else if h = ymin and null cdr py then <<
  320. lbar := symbol 'mat!-low!-l;
  321. rbar := symbol 'mat!-low!-r >>
  322. % else lbar := rbar := symbol 'vbar;
  323. else <<lbar := symbol 'mat!-low!-l;
  324. rbar := symbol 'mat!-low!-r>>;
  325. pl := ((((pos - 2) . (pos - 1)) . h) . rbar) . pl;
  326. k := (((0 . 1) . h) . lbar) . k >>;
  327. return (append(pl, k) . pos) . (ymin . ymax) end;
  328. orig!* := realorig;
  329. w := 0;
  330. for each y in r do w := w + (cddr y - cadr y + 1);
  331. % Total height.
  332. n := w/2; % Height of mid-point.
  333. u := nil;
  334. for each y in r do <<
  335. u := append(update!-pline(0, n - cddr y, caar y), u);
  336. n := n - (cddr y - cadr y + 1) >>;
  337. if x then <<maprin x; oprin 'setq >>;
  338. pline!* := append(update!-pline(posn!*,ycoord!*,u),
  339. pline!*);
  340. ymax!* := max(ycoord!* + w/2, ymax!*);
  341. ymin!* := min(ycoord!* + w/2 - w, ymin!*);
  342. terpri!*(not !*nat)>>
  343. else <<if x then <<maprin x; oprin 'setq>>; matpri2 u>>
  344. end;
  345. symbolic procedure matpri2 u;
  346. begin scalar y;
  347. prin2!* 'mat;
  348. prin2!* "(";
  349. obrkp!* := nil;
  350. y := orig!*;
  351. orig!* := if posn!*<18 then posn!* else orig!*+3;
  352. while u do
  353. <<prin2!* "(";
  354. orig!* := orig!*+1;
  355. inprint('!*comma!*,0,car u);
  356. prin2!* ")";
  357. if cdr u
  358. then <<oprin '!*comma!*; orig!* := orig!*-1;
  359. terpri!* !*nat>>;
  360. u := cdr u>>;
  361. obrkp!* := t;
  362. orig!* := y;
  363. prin2!* ")";
  364. if null !*nat then prin2!* "$";
  365. terpri!* t
  366. end;
  367. endmodule;
  368. module bareiss; % Inversion routines using the Bareiss 2-step method.
  369. % Author: Anthony C. Hearn.
  370. % This module is rife with essential references to RPLAC-based
  371. % functions.
  372. fluid '(!*exp asymplis!* wtl!*);
  373. symbolic procedure matinverse u;
  374. lnrsolve(u,generateident length u);
  375. symbolic procedure lnrsolve(u,v);
  376. %U is a matrix standard form, V a compatible matrix form.
  377. %Value is U**(-1)*V.
  378. begin integer n; scalar !*exp,temp;
  379. !*exp := t; n := length u;
  380. if asymplis!* or wtl!*
  381. then <<temp := asymplis!* . wtl!*;
  382. asymplis!* := wtl!* := nil>>;
  383. v := backsub(bareiss car normmat augment(u,v),n);
  384. if temp then <<asymplis!* := car temp; wtl!* := cdr temp>>;
  385. u := rhside(car v,n);
  386. v := cdr v;
  387. return if temp
  388. then for each j in u collect
  389. for each k in j collect resimp(k ./ v)
  390. else for each j in u collect
  391. for each k in j collect cancel(k ./ v)
  392. end;
  393. symbolic procedure augment(u,v);
  394. if null u then nil else append(car u,car v) . augment(cdr u,cdr v);
  395. symbolic procedure generateident n;
  396. %returns matrix canonical form of identity matrix of order N.
  397. begin scalar u,v;
  398. for i := 1:n do
  399. <<u := nil;
  400. for j := 1:n do u := ((if i=j then 1 else nil) . 1) . u;
  401. v := u . v>>;
  402. return v
  403. end;
  404. symbolic procedure rhside(u,m);
  405. if null u then nil else pnth(car u,m+1) . rhside(cdr u,m);
  406. symbolic procedure bareiss u;
  407. (if null x then nil else cdr x) where x= bareiss1(u,nil);
  408. symbolic procedure bareiss1(u,perm);
  409. % The 2-step integer preserving elimination method of Bareiss based on
  410. % the implementation of Lipson. This is based on the original Bareiss
  411. % function in REDUCE, modified to reduce singular matrices. If PERM
  412. % is nil, it behaves like the old BAREISS, except a pair is returned
  413. % for non-singular U, whose cdr is the triangularized U. The car is
  414. % the rank of U, which in this case is always LENGTH(U). Otherwise
  415. % PERM is a list of the integers 1,2...length(U). As columns are
  416. % interchanged, then so are the elements of PERM. In this case a pair
  417. % is returned whose car is the rank of U and whose cdr is the
  418. % triangularized U. Note that, just as in BAREISS, the lower
  419. % triangular portion of the returned matrix standard form is only
  420. % implicitly all nils--the requisite RPLACAs are not performed. Also,
  421. % if PERM is non-nil and the rank,r, of U is less than the order of U,
  422. % only the first r rows of the upper triangular portion are explicitly
  423. % set. The all nil rows are only implicitly all nils. U is a list of
  424. % lists of standard forms (a matrix standard form) corresponding to
  425. % the appropriate augmented matrix. If the value of procedure is NIL
  426. % then U is singular, otherwise the value is the triangularized form
  427. % of U (in the same form).
  428. begin scalar aa,c0,ci1,ci2,ik1,ij,kk1,kj,k1j,k1k1,
  429. ui,u1,x,k1col,kij,flg;
  430. integer k,k1,col,maxcol;
  431. %U1 points to K-1th row of U
  432. %UI points to Ith row of U
  433. %IJ points to U(I,J)
  434. %K1J points to U(K-1,J)
  435. %KJ points to U(K,J)
  436. %IK1 points to U(I,K-1)
  437. %KK1 points to U(K,K-1)
  438. %K1K1 points to U(K-1,K-1)
  439. %M in comments is number of rows in U
  440. %N in comments is number of columns in U.
  441. maxcol := length(u);
  442. aa:= 1;
  443. k:= 2;
  444. k1:=1;
  445. u1:=u;
  446. go to pivot;
  447. agn: u1 := cdr u1;
  448. if null cdr u1 or null cddr u1
  449. then return if perm and cdr u1
  450. and null car(ij := pnth(nth(u,maxcol),maxcol))
  451. then if not allnils cdr ij then nil else (maxcol-1) . u
  452. else maxcol . u;
  453. aa:=nth(car u1,k); % aa := u(k,k).
  454. k:=k+2;
  455. k1:=k-1;
  456. u1:=cdr u1;
  457. pivot: %pivot algorithm;
  458. col := k1;
  459. k1j:= k1k1 := pnth(car u1,k1);
  460. piv1: k1col := pnth(car(u1), col);
  461. if car k1col then go to l2;
  462. ui:= cdr u1; % i := k.
  463. l: if null ui then
  464. if perm then
  465. if col>=maxcol then
  466. return (k1-1).u
  467. else <<
  468. col := col+1;
  469. go to piv1 >>
  470. else
  471. return nil
  472. else if null car(ij := pnth(car ui,col))
  473. then go to l1;
  474. l0: if null ij then go to l2;
  475. x := car ij;
  476. rplaca(ij,negf car k1col);
  477. rplaca(k1col,x);
  478. ij:= cdr ij;
  479. k1col:= cdr k1col;
  480. go to l0;
  481. l1: ui:= cdr ui;
  482. go to l;
  483. l2: swapcolumns(u, k1, col, perm);
  484. col := k;
  485. piv2: ui:= cdr u1; % i:= k.
  486. l21: if null ui then
  487. if perm then
  488. if col>=maxcol then <<
  489. flg := t;
  490. while flg and u1 do <<
  491. ik1 := pnth(car(u1), k1);
  492. ij := pnth(ik1, maxcol-k1+2);
  493. kij := pnth(k1k1, maxcol-k1+2);
  494. while flg and ij do
  495. if addf(multf(car(k1k1), car(ij)),
  496. multf(car(ik1), negf(car(kij))) )
  497. then flg := nil
  498. else ij := cdr(ij);
  499. u1 := cdr(u1) >>;
  500. if flg then
  501. return (k-1).u
  502. else
  503. return nil >>
  504. else <<
  505. col := col+1;
  506. go to piv2 >>
  507. else
  508. return nil;
  509. ij:= pnth(car ui,k1);
  510. c0:= addf(multf(car k1k1,nth(ij, col-k+2)),
  511. multf(nth(k1k1, col-k+2),negf car ij));
  512. if c0 then go to l3;
  513. ui:= cdr ui; % i:= i+1.
  514. go to l21;
  515. l3: swapcolumns(u, k, col, perm);
  516. c0:= quotf!*(c0,aa);
  517. kk1 := kj := pnth(cadr u1,k1); % kk1 := u(k,k-1).
  518. if cdr u1 and null cddr u1 then go to ev0
  519. else if ui eq cdr u1 then go to comp;
  520. l31: if null ij then go to comp; % if i>n then go to comp.
  521. x:= car ij;
  522. rplaca(ij,negf car kj);
  523. rplaca(kj,x);
  524. ij:= cdr ij;
  525. kj:= cdr kj;
  526. go to l31;
  527. %pivoting complete;
  528. comp:
  529. if null cdr u1 then go to ev;
  530. ui:= cddr u1; % i:= k+1.
  531. comp1:
  532. if null ui then go to ev; % if i>m then go to ev.
  533. ik1:= pnth(car ui,k1);
  534. ci1:= quotf!*(addf(multf(cadr k1k1,car ik1),
  535. multf(car k1k1,negf cadr ik1)),
  536. aa);
  537. ci2:= quotf!*(addf(multf(car kk1,cadr ik1),
  538. multf(cadr kk1,negf car ik1)),
  539. aa);
  540. if null cddr k1k1 then go to comp3; % if j>n then go to comp3.
  541. ij:= cddr ik1; % j := k+1.
  542. kj:= cddr kk1;
  543. k1j:= cddr k1k1;
  544. comp2:
  545. if null ij then go to comp3;
  546. rplaca(ij,quotf!*(addf(multf(car ij,c0),
  547. addf(multf(car kj,ci1),
  548. multf(car k1j,ci2))),
  549. aa));
  550. ij:= cdr ij;
  551. kj:= cdr kj;
  552. k1j:= cdr k1j;
  553. go to comp2;
  554. comp3:
  555. ui:= cdr ui;
  556. go to comp1;
  557. ev0:if null c0 then return;
  558. ev: kj := cdr kk1;
  559. x := cddr k1k1; % x := u(k-1,k+1).
  560. rplaca(kj,c0);
  561. ev1:kj:= cdr kj;
  562. if null kj then go to agn;
  563. rplaca(kj,quotf!*(addf(multf(car k1k1,car kj),
  564. multf(car kk1,negf car x)),
  565. aa));
  566. x := cdr x;
  567. go to ev1
  568. end;
  569. symbolic procedure allnils u; null u or null car u and allnils cdr u;
  570. symbolic procedure swapcolumns(matrx,col1,col2,perm);
  571. if col1=col2 then matrx
  572. else <<swapelements(perm,col1,col2);
  573. for each u in matrx do swapelements(u,col1,col2);
  574. matrx>>;
  575. symbolic procedure swapelements(lst,i,j);
  576. % Uses rplaca to swap ith and jth elements of the list lst.
  577. % Returns nil.
  578. begin scalar temp;
  579. if i>j then <<temp := i; i := j; j := temp>>;
  580. lst := pnth(lst,i);
  581. i := j-i+1;
  582. temp := nth(lst,i);
  583. rplaca(pnth(lst,i),car lst);
  584. rplaca(lst,temp)
  585. end;
  586. symbolic procedure backsub(u,m);
  587. begin scalar detm,det1,ij,ijj,ri,summ,uj,ur; integer i,jj;
  588. %N in comments is number of columns in U.
  589. if null u then rerror(matrix,11,"Singular matrix");
  590. ur := reverse u;
  591. detm := car pnth(car ur,m); %detm := u(i,j).
  592. if null detm then rerror(matrix,12,"Singular matrix");
  593. i := m;
  594. rows:
  595. i := i-1;
  596. ur := cdr ur;
  597. if null ur then return u . detm;
  598. %if i=0 then return u . detm.
  599. ri := car ur;
  600. jj := m+1;
  601. ijj:=pnth(ri,jj);
  602. r2: if null ijj then go to rows; %if jj>n then go to rows;
  603. ij := pnth(ri,i); %j := i;
  604. det1 := car ij; %det1 := u(i,i);
  605. uj := pnth(u,i);
  606. summ := nil; %summ := 0;
  607. r3: uj := cdr uj; %j := j+1;
  608. if null uj then go to r4; %if j>m then go to r4;
  609. ij := cdr ij;
  610. summ := addf(summ,multf(car ij,nth(car uj,jj)));
  611. %summ:=summ+u(i,j)*u(j,jj);
  612. go to r3;
  613. r4: rplaca(ijj,quotf!*(addf(multf(detm,car ijj),negf summ),det1));
  614. %u(i,j):=(detm*u(i,j)-summ)/det1;
  615. jj := jj+1;
  616. ijj := cdr ijj;
  617. go to r2
  618. end;
  619. symbolic procedure normmat u;
  620. %U is a matrix standard form.
  621. %Value is dotted pair of matrix polynomial form and factor.
  622. begin scalar x,y,z;
  623. x := 1;
  624. for each v in u do
  625. <<y := 1;
  626. for each w in v do y := lcm(y,denr w);
  627. z := (for each w in v
  628. collect multf(numr w,quotf(y,denr w)))
  629. . z;
  630. x := multf(y,x)>>;
  631. return reverse z . x
  632. end;
  633. endmodule;
  634. module det; % Determinant and trace routines.
  635. % Author: Anthony C. Hearn.
  636. symbolic procedure simpdet u; detq matsm carx(u,'det);
  637. % The hashing and determinant routines below are due to M. L. Griss.
  638. Comment Some general purpose hashing functions;
  639. flag('(array),'eval); % Declared again for bootstrapping purposes.
  640. array !$hash 64; % General array for hashing.
  641. symbolic procedure gethash key;
  642. % Access previously saved element.
  643. assoc(key,!$hash(remainder(key,64)));
  644. symbolic procedure puthash(key,valu);
  645. begin integer k; scalar buk;
  646. k := remainder(key,64);
  647. buk := (key . valu) . !$hash k;
  648. !$hash k := buk;
  649. return car buk
  650. end;
  651. symbolic procedure clrhash;
  652. for i := 0:64 do !$hash i := nil;
  653. Comment Determinant Routines;
  654. symbolic procedure detq u;
  655. % Top level determinant function.
  656. begin integer len;
  657. len := length u; % Number of rows.
  658. for each x in u do
  659. if length x neq len then rederr "Non square matrix";
  660. if len=1 then return caar u;
  661. clrhash();
  662. u := detq1(u,len,0);
  663. clrhash();
  664. return u
  665. end;
  666. symbolic procedure detq1(u,len,ignnum);
  667. % U is a square matrix of order LEN. Value is the determinant of U.
  668. % Algorithm is expansion by minors of first row.
  669. % IGNNUM is packed set of column indices to avoid.
  670. begin integer n2; scalar row,sign,z;
  671. row := car u; % Current row.
  672. n2 := 1;
  673. if len=1
  674. then return <<while twomem(n2,ignnum)
  675. do <<n2 := 2*n2; row := cdr row>>;
  676. car row>>; % Last row, single element.
  677. if z := gethash ignnum then return cdr z;
  678. len := len-1;
  679. u := cdr u;
  680. z := nil ./ 1;
  681. for each x in row do
  682. <<if not twomem(n2,ignnum)
  683. then <<if numr x
  684. then <<if sign then x := negsq x;
  685. z:= addsq(multsq(x,detq1(u,len,n2+ignnum)),
  686. z)>>;
  687. sign := not sign>>;
  688. n2 := 2*n2>>;
  689. puthash(ignnum,z);
  690. return z
  691. end;
  692. symbolic procedure twomem(n1,n2);
  693. % For efficiency reasons, this procedure should be coded in assembly
  694. % language.
  695. not evenp(n2/n1);
  696. put('det,'simpfn,'simpdet);
  697. flag('(det),'immediate);
  698. symbolic procedure simptrace u;
  699. begin integer n; scalar z;
  700. u := matsm carx(u,'trace);
  701. if length u neq length car u then rederr "Non square matrix";
  702. n := 1;
  703. z := nil ./ 1;
  704. for each x in u do <<z := addsq(nth(x,n),z); n := n+1>>;
  705. return z
  706. end;
  707. put('trace,'simpfn,'simptrace);
  708. endmodule;
  709. module glmat; % Routines for inverting matrices and finding eigen-values
  710. % and vectors. Methods are the same as in glsolve module.
  711. % Author: Eberhard Schruefer.
  712. % Modification: James Davenport and Fran Burstall.
  713. fluid '(!*cramer !*factor !*gcd !*sqfree !*sub2 kord!*);
  714. global '(!!arbint);
  715. if null !!arbint then !!arbint := 0;
  716. switch cramer;
  717. put('cramer,'simpfg,
  718. '((t (put 'mat 'lnrsolvefn 'clnrsolve)
  719. (put 'mat 'inversefn 'matinv))
  720. (nil (put 'mat 'lnrsolvefn 'lnrsolve)
  721. (put 'mat 'inversefn 'matinverse))));
  722. % algebraic operator arbcomplex;
  723. % Done this way since it's also defined in the solve1 module.
  724. deflist('((arbcomplex simpiden)),'simpfn);
  725. symbolic procedure clnrsolve(u,v);
  726. % Interface to matrix package.
  727. multm(matinv u,v);
  728. symbolic procedure minv u;
  729. matinv matsm u;
  730. put('minv,'rtypefn,'quotematrix);
  731. %put('mateigen,'rtypefn,'quotematrix);
  732. remprop('mateigen,'rtypefn);
  733. put('detex,'simpfn,'detex);
  734. symbolic procedure matinv u;
  735. % U is a matrix form. Result is the inverse of matrix u.
  736. begin scalar sgn,x,y,z;
  737. integer l,m,lm;
  738. z := 1;
  739. lm := length car u;
  740. for each v in u do
  741. <<y := 1;
  742. for each w in v do y := lcm(y,denr w);
  743. m := lm;
  744. x := list(nil . (l := l + 1)) .* negf y .+ nil;
  745. for each j in reverse v do
  746. <<if numr j then
  747. x := list m .* multf(numr j,quotf(y,denr j)) .+ x;
  748. m := m - 1>>;
  749. z := c!:extmult(x,z)>>;
  750. if singularchk lpow z then rerror(matrix,13,"Singular matrix");
  751. sgn := evenp length lpow z;
  752. return for each k in lpow z collect
  753. <<sgn := not sgn;
  754. for each j in lpow z collect mkglimat(k,z,sgn,j)>>
  755. end;
  756. symbolic procedure singularchk u;
  757. pairp car reverse u;
  758. flag('(mateigen),'opfn);
  759. flag('(mateigen),'noval);
  760. symbolic procedure mateigen(u,eival);
  761. % U is a matrix form, eival an indeterminate naming the eigenvalues.
  762. % Result is a list of lists:
  763. % {{eival-eq1,multiplicity1,eigenvector1},....},
  764. % where eival-eq is a polynomial and eigenvector is a matrix.
  765. % How much should we attempt to solve the eigenvalue eq.? sqfr?
  766. % Sqfr is necessary if we want to have the full eigenspace. If there
  767. % are multiple roots another pass through eigenvector calculation
  768. % is needed(done).
  769. % We should actually perform the calculations in the extension
  770. % field generated by the eigenvalue equation(done inside).
  771. begin scalar arbvars,exu,sgn,q,r,s,x,y,z,eivec,!*factor,!*sqfree;
  772. integer l;
  773. if not(getrtype u eq 'matrix) then typerr(u,"matrix");
  774. eival := !*a2k eival;
  775. kord!* := eival . kord!*;
  776. exu := mateigen1(matsm u,eival);
  777. q := car exu;
  778. y := cadr exu;
  779. z := caddr exu;
  780. exu := cdddr exu;
  781. !*sqfree := t;
  782. for each j in cdr fctrf numr subs2(lc z ./ 1)
  783. do if null domainp car j and mvar car j eq eival
  784. then s := (if null red car j
  785. then !*k2f mvar car j . (ldeg car j*cdr j)
  786. else j) . s;
  787. for each j in q
  788. do (if x then rplacd(x,cdr x + cdr j)
  789. else s := (y . cdr j) . s)
  790. where x := assoc(y,s) where y := absf reorder car j;
  791. l := length s;
  792. r := 'list .
  793. for each j in s collect
  794. <<if null((cdr j = 1) and (l = 1)) then
  795. <<y := 1;
  796. for each k in exu do
  797. if x := reduce!-mod!-eig(car j,c!:extmult(k,y))
  798. then y := x>>;
  799. arbvars := nil;
  800. for each k in lpow z do
  801. if (y=1) or null(k member lpow y) then
  802. arbvars := (k . makearbcomplex()) . arbvars;
  803. sgn := (y=1) or evenp length lpow y;
  804. eivec := 'mat . for each k in lpow z collect list
  805. if x := assoc(k,arbvars)
  806. then mvar cdr x
  807. else prepsq!* mkgleig(k,y,
  808. sgn := not sgn,arbvars);
  809. list('list,prepsq!*(car j ./ 1),cdr j,eivec)>>;
  810. kord!* := cdr kord!*;
  811. return r
  812. end;
  813. symbolic procedure mateigen1(u,eival);
  814. begin scalar q,x,y,z; integer l,lm,m;
  815. lm := length car u;
  816. z := 1;
  817. u := for each v in u collect
  818. <<y := 1;
  819. for each w in v do y := lcm(y,denr w);
  820. m := lm;
  821. l := l + 1;
  822. x := nil;
  823. for each j in reverse v do
  824. <<if numr j or l = m then
  825. x := list m .* multf(if l = m then
  826. addf(numr j,
  827. negf multf(!*k2f eival,
  828. denr j)) else numr j,
  829. quotf(y,denr j)) .+ x;
  830. m := m - 1>>;
  831. y := z;
  832. z := c!:extmult(if null red x then <<
  833. q := (if p then (car p . (cdr p + 1)) . delete(p,q)
  834. else (lc x . 1) . q) where p = assoc(lc x,q);
  835. !*p2f lpow x>> else x,z);
  836. x>>;
  837. return q . y . z . u
  838. end;
  839. symbolic procedure reduce!-mod!-eig(u,v);
  840. % Reduces exterior product v wrt eigenvalue equation u.
  841. begin scalar x,y;
  842. for each j on v do
  843. if numr(y := reduce!-mod!-eigf(u,lc j)) then
  844. x := lpow j .* y .+ x;
  845. y := 1;
  846. for each j on x do y := lcm(y,denr lc j);
  847. return for each j on reverse x collect
  848. lpow j .* multf(numr lc j,quotf(y,denr lc j))
  849. end;
  850. symbolic procedure reduce!-mod!-eigf(u,v);
  851. (subs2 reduce!-eival!-powers(lpow u . negsq cancel(red u ./ lc u),v))
  852. where !*sub2 = !*sub2;
  853. symbolic procedure reduce!-eival!-powers(v,u);
  854. if domainp u or null(mvar u eq caar v) then u ./ 1
  855. else reduce!-eival!-powers1(v,u ./ 1);
  856. symbolic procedure reduce!-eival!-powers1(v,u);
  857. % Reduces powers with the help of the eigenvalue polynomial.
  858. if domainp numr u or (ldeg numr u<pdeg car v) then u
  859. else if ldeg numr u=pdeg car v then
  860. addsq(multsq(cdr v,lc numr u ./ denr u),
  861. red numr u ./ denr u)
  862. else reduce!-eival!-powers1(v,
  863. addsq(multsq(multpf(mvar numr u .** (ldeg numr u-pdeg car v),
  864. lc numr u) ./ denr u,
  865. cdr v),red numr u ./ denr u));
  866. symbolic procedure detex u;
  867. % U is a matrix form, result is determinant of u.
  868. begin scalar f,x,y,z;
  869. integer m,lm;
  870. z := 1;
  871. u := matsm car u;
  872. lm := length car u;
  873. f := 1;
  874. for each v in u do
  875. <<y := 1;
  876. for each w in v do y := lcm(y,denr w);
  877. f := multf(y,f);
  878. m := lm;
  879. x := nil;
  880. for each j in v do
  881. <<if numr j then
  882. x := list m .* multf(numr j,quotf(y,denr j)) .+ x;
  883. m := m - 1>>;
  884. z := c!:extmult(x,z)>>;
  885. return cancel(lc z ./ f)
  886. end;
  887. symbolic procedure mkglimat(u,v,sgn,k);
  888. begin scalar s,x,y;
  889. x := nil ./ 1;
  890. y := lpow v;
  891. for each j on red v do
  892. if s := glmatterm(u,y,j,k)
  893. then x := addsq(cancel(s ./ lc v),x);
  894. return if sgn then negsq x else x
  895. end;
  896. symbolic procedure glmatterm(u,v,w,k);
  897. begin scalar x,y,sgn;
  898. x := lpow w;
  899. a: if null x then return
  900. if pairp car y and (cdar y = k) then lc w else nil;
  901. if car x = u then return nil
  902. else if car x member v then <<x := cdr x;
  903. if y then sgn := not sgn>>
  904. else if y then return nil
  905. else <<y := list car x; x := cdr x>>;
  906. go to a
  907. end;
  908. symbolic procedure mkgleig(u,v,sgn,arbvars);
  909. begin scalar s,x,y,!*gcd;
  910. x := nil ./ 1;
  911. y := lpow v;
  912. !*gcd := t;
  913. for each j on red v do
  914. if s := glsoleig(u,y,j,arbvars)
  915. then x := addsq(cancel(s ./ lc v),x);
  916. return if sgn then negsq x else x
  917. end;
  918. symbolic procedure glsoleig(u,v,w,arbvars);
  919. begin scalar x,y,sgn;
  920. x := lpow w;
  921. a: if null x then return
  922. if null car y then lc w
  923. else multf(cdr assoc(car y,arbvars),
  924. if sgn then negf lc w else lc w);
  925. if car x = u then return nil
  926. else if car x member v then <<x := cdr x;
  927. if y then sgn := not sgn>>
  928. else if y then return nil
  929. else <<y := list car x; x := cdr x>>;
  930. go to a
  931. end;
  932. %**** Support for exterior multiplication ****
  933. % Data structure is lpow ::= list of col.-ind. in exterior product
  934. % | nil . number of eq. for inhomog. terms.
  935. % lc ::= standard form
  936. % Exterior multiplication and p-forms:
  937. % Let V be a vector space of dimension n.
  938. % We call the elements of V 1-forms and build new objects called
  939. % p-forms as follows: define a multiplication on 1-forms ^ such that
  940. % v^w=-w^v
  941. % then the linear span of such objects is the space of 2-forms and has
  942. % dimension n(n-1)/2. Indeed, if v_1,...,v_n is a basis of V then
  943. % v_i^v_j for i<j is a basis for the 2-forms.
  944. % We extend this multiplication (called exterior multiplication)
  945. % to get products of p vectors, linear combinations of which are
  946. % called p-forms: this extension is defined by the rule that v_1^...^v_p
  947. % vanishes whenever some v_i=v_j (for i not j). Thus the effect of
  948. % permuting the order of the vectors in such a product is to multiply
  949. % the product by the sign of the permutation.
  950. % Using this it is not difficult to show:
  951. % Theorem: Vectors v_1,...,v_p are linear independent iff their exterior
  952. % product v_1^...^v_p is non-zero.
  953. %
  954. % For more information see F. Warner "Foundations of Differentiable
  955. % Manifolds and Lie Groups" (Springer) Chapter 2. (Or any other book
  956. % on differential geometry or multilinear algebra
  957. symbolic procedure c!:extmult(u,v);
  958. % Special exterior multiplication routine. Degree of form v is
  959. % arbitrary, u is a one-form.
  960. if null u or null v then nil
  961. else if v = 1 then u %unity
  962. % else (if x then cdr x .* (if car x
  963. % then negf c!:subs2multf(lc u,lc v)
  964. % else c!:subs2multf(lc u,lc v))
  965. % .+ c!:extadd(c!:extmult(!*t2f lt u,red v),
  966. % ^^ this is bogus: .+ may not be valid in this circumstance
  967. % c!:extmult(red u,v))
  968. else (if x then
  969. c!:extadd(cdr x .* (if car x
  970. then negf c!:subs2multf(lc u,lc v)
  971. else c!:subs2multf(lc u,lc v)) .+ nil,
  972. c!:extadd(c!:extmult(!*t2f lt u,red v),
  973. c!:extmult(red u,v)))
  974. else c!:extadd(c!:extmult(!*t2f lt u,red v),
  975. c!:extmult(red u,v)))
  976. where x = c!:ordexn(car lpow u,lpow v);
  977. symbolic procedure c!:subs2multf(u,v);
  978. (if denr x neq 1 then rerror(matrix,14,"Sub error in glnrsolve")
  979. else numr x)
  980. where x = subs2(multf(u,v) ./ 1) where !*sub2 = !*sub2;
  981. symbolic procedure c!:extadd(u,v);
  982. if null u then v
  983. else if null v then u
  984. else if lpow u = lpow v then
  985. (lambda x,y; if null x then y else lpow u .* x .+ y)
  986. (addf(lc u,lc v),c!:extadd(red u,red v))
  987. else if c!:ordexp(lpow u,lpow v) then lt u .+ c!:extadd(red u,v)
  988. else lt v .+ c!:extadd(u,red v);
  989. symbolic procedure c!:ordexp(u,v);
  990. if null u then t
  991. else if car u = car v then c!:ordexp(cdr u,cdr v)
  992. else c!:ordxp(car u,car v);
  993. symbolic procedure c!:ordexn(u,v);
  994. % U is a single index, v a list. Returns nil if u is a member
  995. % of v or a dotted pair of a permutation indicator and the ordered
  996. % list of u merged into v.
  997. begin scalar s,x;
  998. a: if null v then return(s . reverse(u . x))
  999. else if (u = car v) or (pairp u and pairp car v)
  1000. then return nil
  1001. else if c!:ordxp(u,car v) then
  1002. return(s . append(reverse(u . x),v))
  1003. else <<x := car v . x;
  1004. v := cdr v;
  1005. s := not s>>;
  1006. go to a
  1007. end;
  1008. symbolic procedure c!:ordxp(u,v);
  1009. if pairp u then if pairp v then cdr u < cdr v
  1010. else nil
  1011. else if pairp v then t
  1012. else u < v;
  1013. endmodule;
  1014. module nullsp; % Compute the nullspace (basis vectors) of a matrix.
  1015. % Author: Herbert Melenk <melenk@sc.zib-berlin.de>.
  1016. % Algorithm: Rational Gaussian elimination with standard qutotients.
  1017. put('nullspace,'psopfn,'nullspace!-eval);
  1018. symbolic procedure nullspace!-eval u;
  1019. % interface for the nullspace calculation.
  1020. begin scalar v,n,matinput;
  1021. v := reval car u;
  1022. if eqcar(v,'mat) then
  1023. <<matinput:=t; v := cdr v>>
  1024. else if eqcar(v,'list) then
  1025. v := for each row in cdr v collect
  1026. if not eqcar(row,'list) then typerr ("matrix",u) else
  1027. <<row := cdr row;
  1028. if null n then n := length row else
  1029. if n neq length row
  1030. then rerror(matrix,15,"lists not in matrix shape");
  1031. row>> else rerror(matrix,16,"Not a matrix");
  1032. v := nullspace!-alg v;
  1033. return 'list . for each vect in v collect
  1034. if matinput then 'mat . for each x in vect collect list x
  1035. else 'list . vect;
  1036. end;
  1037. symbolic procedure nullspace!-alg(m);
  1038. % "M" is a Matrix, encoded as list of lists(=rows) of algebraic
  1039. % expressions.
  1040. % Result is the basis of the kernel of M in the same encoding.
  1041. begin scalar mp,vars,rvars,r,res,oldorder; integer n;
  1042. n := length car m;
  1043. vars := for i:=1:n collect gensym();
  1044. rvars := reverse vars;
  1045. oldorder := setkorder rvars;
  1046. mp := for each row in m collect
  1047. <<r := nil ./ 1;
  1048. for each col in pair(vars,row) do
  1049. r := addsq(r,simp list('times,car col,cdr col));
  1050. r>>;
  1051. res := nullspace!-elim(mp,rvars);
  1052. setkorder oldorder;
  1053. return reverse for each q in res collect
  1054. for each x in vars collect
  1055. cdr atsoc(x,q);
  1056. end;
  1057. symbolic procedure nullspace!-elim(m,vars);
  1058. % "M" is a matrix encoded as list of linear polnomials (sq's) in
  1059. % the variables "vars". The current korder cooresponds to vars.
  1060. % Result is a basis for the null space of the matrix, encoded
  1061. % as list of vectors, where each vector is an alist over vars.
  1062. % A rational Gaussian elimination is performed and unit vectors
  1063. % are substituted for the remaining unrestricted variables.
  1064. begin scalar c,s,x,arbvars,depvars,row,res,break;
  1065. while vars and not break do
  1066. <<for each p in m do
  1067. if domainp numr p then if numr p then break:=t %unsolvable
  1068. else m:=delete(p,m);
  1069. if not break then
  1070. <<x:=car vars; vars:=cdr vars; row:=nil;
  1071. % select row with x as leading variable.
  1072. for each p in m do
  1073. if null row and mvar numr p = x then row:=p;
  1074. % if none, then x is a free variable.
  1075. if null row then arbvars:=x.arbvars else
  1076. <<m:=delete(row,m);
  1077. c:=multsq(negf denr row ./1, 1 ./ lc numr row);
  1078. row := multsq(row,c);
  1079. % collect formula for x,
  1080. depvars := (x . (red numr row ./ denr row)) . depvars;
  1081. % and perform elimination with this row.
  1082. m:=for each p in m collect
  1083. if mvar numr p=x then
  1084. addsq(p, multsq(row,lc numr p ./ denr p))
  1085. else p;
  1086. >>;
  1087. >>;
  1088. >>;
  1089. if break then return nil;
  1090. % Constuct solutions by assigning unit vectors to the
  1091. % free variables and perform backsubstitution.
  1092. for each x in arbvars do
  1093. << s := for each y in arbvars collect
  1094. (y . if y=x then 1 else 0);
  1095. for each y in depvars do
  1096. s := (car y . prepsq subsq(cdr y,s)) . s;
  1097. res := s . res;
  1098. >>;
  1099. return res;
  1100. end;
  1101. endmodule;
  1102. module rank;
  1103. % Author: Eberhard Schruefer.
  1104. % Module for calculating the rank of a matrix or a system of linear
  1105. % equations. It is assumed that glmat or glsolve are loaded.
  1106. % Format: rank <matrix> : rank <list of equations> :
  1107. % rank(<list of equations>,<list of unknowns>)
  1108. symbolic procedure rank!-eval u;
  1109. if getrtype car u eq 'matrix
  1110. then if cdr u then rerror(matrix,17,"Wrong number of arguments")
  1111. else rank!-matrix matsm car u
  1112. else if null (getrtype car u eq 'list)
  1113. then rerror(matrix,18,"Wrong type")
  1114. else begin scalar unknowns,equations,okord; integer n;
  1115. if cdr u then
  1116. unknowns := for each j in cdr listeval(cadr u,nil)
  1117. collect !*a2k j;
  1118. okord := setkorder append(unknowns,kord!*);
  1119. equations := for each j in cdr listeval(car u,nil)
  1120. collect reorder numr simp!* j;
  1121. if null unknowns
  1122. then unknowns := allkernf equations;
  1123. n := rank!-gleqs(equations,unknowns);
  1124. setkorder okord;
  1125. return n
  1126. end;
  1127. put('rank,'psopfn,'rank!-eval);
  1128. symbolic procedure rank!-gleqs(u,v);
  1129. begin scalar x,y; integer n;
  1130. n := 1;
  1131. x := !*sf2ex(car u,v);
  1132. u := cdr u;
  1133. for each j in u do
  1134. if y := extmult(!*sf2ex(j,v),x)
  1135. then <<x := y;
  1136. n := n + 1>>;
  1137. return n
  1138. end;
  1139. symbolic procedure rank!-matrix u;
  1140. begin scalar x,y,z; integer m,n;
  1141. z := 1;
  1142. for each v in u do
  1143. <<y := 1;
  1144. for each w in v do y := lcm(y,denr w);
  1145. m := 1;
  1146. x := nil;
  1147. for each j in v do
  1148. <<if numr j then
  1149. x := list m .* multf(numr j,quotf(y,denr j)) .+ x;
  1150. m := m + 1>>;
  1151. if y := c!:extmult(x,z)
  1152. then <<z := y; n := n + 1>>>>;
  1153. return n
  1154. end;
  1155. endmodule;
  1156. module resultant;
  1157. % Author: Eberhard Schruefer.
  1158. %**********************************************************************
  1159. % *
  1160. % The resultant function defined here has the following properties: *
  1161. % *
  1162. % degr(p1,x)*degr(p2,x) *
  1163. % resultant(p1,p2,x) = (-1) *resultant(p2,p1,x) *
  1164. % *
  1165. % degr(p2,x) *
  1166. % resultant(p1,p2,x) = p1 if p1 free of x *
  1167. % *
  1168. % resultant(p1,p2,x) = 1 if p1 free of x and p2 free of x *
  1169. % *
  1170. %**********************************************************************
  1171. %exports resultant;
  1172. %imports reorder,setkorder,degr,addf,negf,multf,multpf;
  1173. fluid '(!*exp kord!*);
  1174. symbolic procedure resultant(u,v,w);
  1175. %u and v are standard forms. Result is resultant of u and v
  1176. %w.r.t. kernel w. Method is Bezout's determinant using exterior
  1177. %multiplication for its calculation.
  1178. begin scalar ap,ep,uh,ut,vh,vt;
  1179. integer n,nm;
  1180. if domainp u and domainp v then return 1;
  1181. kord!* := w . kord!*;
  1182. if null domainp u and null(mvar u eq w) then u := reorder u;
  1183. if null domainp v and null(mvar v eq w) then v := reorder v;
  1184. if domainp u or null(mvar u eq w)
  1185. then <<setkorder cdr kord!*;
  1186. return if not domainp v and mvar v eq w
  1187. then exptf(u,ldeg v)
  1188. else 1>>
  1189. else if domainp v or null(mvar v eq w)
  1190. then <<setkorder cdr kord!*;
  1191. return if mvar u eq w then exptf(v,ldeg u)
  1192. else 1>>;
  1193. n := ldeg u - ldeg v;
  1194. ep := 1;
  1195. if n<0 then
  1196. <<for j := (-n-1) step -1 until 1 do
  1197. ep := b!:extmult(!*sf2exb(multpf(w to j,u),w),ep);
  1198. ep := b!:extmult(!*sf2exb(multd((-1)**(-n*ldeg u),u),
  1199. w),
  1200. ep)>>
  1201. else if n>0 then
  1202. <<for j := (n-1) step -1 until 1 do
  1203. ep := b!:extmult(!*sf2exb(multpf(w to j,v),w),ep);
  1204. ep := b!:extmult(!*sf2exb(v,w),ep)>>;
  1205. nm := max(ldeg u,ldeg v);
  1206. uh := lc u;
  1207. vh := lc v;
  1208. ut := if n<0 then multpf(w to -n,red u)
  1209. else red u;
  1210. vt := if n>0 then multpf(w to n,red v)
  1211. else red v;
  1212. ap := addf(multf(uh,vt),negf multf(vh,ut));
  1213. ep := if null ep then !*sf2exb(ap,w)
  1214. else b!:extmult(!*sf2exb(ap,w),ep);
  1215. for j := (nm - 1) step -1 until (abs n + 1) do
  1216. <<if degr(ut,w) = j then
  1217. <<uh := addf(lc ut,multf(!*k2f w,uh));
  1218. ut := red ut>>
  1219. else uh := multf(!*k2f w,uh);
  1220. if degr(vt,w) = j then
  1221. <<vh := addf(lc vt,multf(!*k2f w,vh));
  1222. vt := red vt>>
  1223. else vh := multf(!*k2f w,vh);
  1224. ep := b!:extmult(!*sf2exb(addf(multf(uh,vt),
  1225. negf multf(vh,ut)),w),ep)>>;
  1226. setkorder cdr kord!*;
  1227. return if null ep then nil else lc ep
  1228. end;
  1229. put('resultant,'simpfn,'simpresultant);
  1230. symbolic procedure simpresultant u;
  1231. begin scalar !*exp;
  1232. if length u neq 3
  1233. then rerror(matrix,19,
  1234. "RESULTANT called with wrong number of arguments");
  1235. !*exp := t;
  1236. return resultant(!*q2f simp!* car u,
  1237. !*q2f simp!* cadr u,
  1238. !*a2k caddr u) ./ 1
  1239. end;
  1240. symbolic procedure !*sf2exb(u,v);
  1241. %distributes s.f. u with respect to powers in v.
  1242. if degr(u,v)=0 then if null u then nil
  1243. else list 0 .* u .+ nil
  1244. else list ldeg u .* lc u .+ !*sf2exb(red u,v);
  1245. %**** Support for exterior multiplication ****
  1246. % Data structure is lpow ::= list of degrees in exterior product
  1247. % lc ::= standard form
  1248. symbolic procedure b!:extmult(u,v);
  1249. %Special exterior multiplication routine. Degree of form v is
  1250. %arbitrary, u is a one-form.
  1251. if null u or null v then nil
  1252. else if v = 1 then u
  1253. else (if x then cdr x .* (if car x then negf multf(lc u,lc v)
  1254. else multf(lc u,lc v))
  1255. .+ b!:extadd(b!:extmult(!*t2f lt u,red v),
  1256. b!:extmult(red u,v))
  1257. else b!:extadd(b!:extmult(red u,v),
  1258. b!:extmult(!*t2f lt u,red v)))
  1259. where x = b!:ordexn(car lpow u,lpow v);
  1260. symbolic procedure b!:extadd(u,v);
  1261. if null u then v
  1262. else if null v then u
  1263. else if lpow u = lpow v then
  1264. (lambda x,y; if null x then y else lpow u .* x .+ y)
  1265. (addf(lc u,lc v),b!:extadd(red u,red v))
  1266. else if b!:ordexp(lpow u,lpow v) then lt u .+ b!:extadd(red u,v)
  1267. else lt v .+ b!:extadd(u,red v);
  1268. symbolic procedure b!:ordexp(u,v);
  1269. if null u then t
  1270. else if car u > car v then t
  1271. else if car u = car v then b!:ordexp(cdr u,cdr v)
  1272. else nil;
  1273. symbolic procedure b!:ordexn(u,v);
  1274. %u is a single integer, v a list. Returns nil if u is a member
  1275. %of v or a dotted pair of a permutation indicator and the ordered
  1276. %list of u merged into v.
  1277. begin scalar s,x;
  1278. a: if null v then return(s . reverse(u . x))
  1279. else if u = car v then return nil
  1280. else if u and u > car v then
  1281. return(s . append(reverse(u . x),v))
  1282. else <<x := car v . x;
  1283. v := cdr v;
  1284. s := not s>>;
  1285. go to a
  1286. end;
  1287. endmodule;
  1288. module cofactor; % Cofactor operator.
  1289. % Author: Alan Barnes <barnesa@kirk.aston.ac.uk>.
  1290. Comment
  1291. Syntax: COFACTOR(MATRIX:matrix,ROW:integer,COLUMN:integer):algebraic
  1292. The cofactor of the element in row ROW and column COLUMN of matrix
  1293. MATRIX is returned. Errors occur if ROW or COLUMN do not simplify to
  1294. integer expressions or if MATRIX is not square;
  1295. symbolic procedure cofactorq (u,i,j);
  1296. begin integer len;
  1297. len:= length u;
  1298. if not(i>0 and i<len+1)
  1299. then rerror(matrix,20,"Row number out of range");
  1300. if not(j>0 and j<len+1)
  1301. then rerror(matrix,21,"Column number out of range");
  1302. foreach x in u do
  1303. if length x neq len then rerror(matrix,22,"non-square matrix");
  1304. u := remove(u,i);
  1305. clrhash();
  1306. u := detq1(u,len-1,2**(j-1));
  1307. clrhash();
  1308. if remainder(i+j,2)=1 then u := negsq u;
  1309. return u;
  1310. end;
  1311. put ('cofactor,'simpfn,'simpcofactor);
  1312. symbolic procedure simpcofactor u;
  1313. cofactorq(matsm car u,ieval cadr u,ieval carx(cddr u,'cofactor));
  1314. endmodule;
  1315. end;