systems.red 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. module systems;
  2. % Operations on exterior differential systems
  3. % Author: David Hartley
  4. fluid '(kord!* xtruncate!* !*arbvars !*edssloppy cfrmcob!*);
  5. global '(indxl!*);
  6. symbolic procedure copyeds s;
  7. % s:eds -> copyeds:eds
  8. % Copy s to allow destructive operations using selectors
  9. append(s,{});
  10. put('augment,'rtypefn,'getrtypecar);
  11. put('augment,'edsfn,'augmenteds);
  12. symbolic procedure augmenteds(s,u);
  13. % s:eds, u:prefix sys -> augmenteds:eds
  14. begin
  15. u := makelist getrlist u;
  16. u := !*a2sys u;
  17. s := augmentsys(s,u);
  18. foreach f in {'pfaffian,'closed,'quasilinear,'involutive} do
  19. rempropeds(s,f);
  20. return checkeds s; % removes all hidden flags, adds new rsx
  21. end;
  22. symbolic procedure augmentsys(s,u);
  23. % s:eds, u:sys -> augmentsys:eds
  24. % Augment system by adding new forms, using ordering of s on input in
  25. % final sort. Doesn't change flags or check integrity.
  26. begin scalar c;
  27. s := copyeds s;
  28. eds_sys s := sortsys(union(u,eds_sys s),edscob s);
  29. return s;
  30. end;
  31. put('quasilinear,'psopfn,'quasilineareval);
  32. symbolic procedure quasilineareval s;
  33. % s:{eds} -> quasilineareval:0 or 1
  34. if edsp(s := reval car s) then
  35. if knowntrueeds(s,'quasilinear) or
  36. not knownfalseeds(s,'quasilinear) and
  37. edscall quasilinearp s then 1 else 0
  38. else typerr(s,'eds);
  39. symbolic procedure quasilinearp s;
  40. % s:eds -> quasilinearp:bool
  41. % Test whether (closure of) system is quasilinear
  42. knowntrueeds(s,'quasilinear) or
  43. not knownfalseeds(s,'quasilinear) and
  44. if not normaledsp s then
  45. rerror(eds,000,{"System not in normal form in quasilinearp"})
  46. else if null scalarpart eds_sys s and
  47. quasilinearsys(nonpfaffpart eds_sys closure s,prlkrns s)
  48. then << flagtrueeds(s,'quasilinear); t >>
  49. else
  50. << flagfalseeds(s,'quasilinear); nil >>;
  51. symbolic procedure quasilinearsys(s,prl);
  52. % s:sys, prl:list of 1-form kernel -> quasilinearsys:bool
  53. % Systems with 0-forms are non-linear by definition here.
  54. null cadr lineargens(s,{},prl);
  55. symbolic procedure lineargenerators s;
  56. % s:eds -> lineargenerators:eds
  57. % Makes linearly generated part of s explicitly linear.
  58. begin scalar p;
  59. p := pfaffpart eds_sys s;
  60. p := append(p,append(car q,cadr q))
  61. where q = lineargens(setdiff(eds_sys s,p),{},prlkrns s);
  62. if p = eds_sys s then return s;
  63. s := copyeds s;
  64. eds_sys s := p;
  65. return sorteds s;
  66. end;
  67. symbolic procedure lineargens(s,g,prl);
  68. % s,g:sys, prl:list of 1-form kernel -> lineargens:{sys,sys}
  69. % g is a GB for a linear system, s is fully reduced wrt g. Returns as
  70. % linear a set of generators as possible. For a linear system,
  71. % returns a linear set of generators. Recursively checks if
  72. % non-linear part of s can be reduced mod linear part + g to give a
  73. % linear system. Systems with 0-forms are non-linear by definition
  74. % here.
  75. begin scalar w,xtruncate!*; integer d;
  76. foreach f in s do
  77. << d := max(d,degreepf f);
  78. if degreepf f neq 0 and quasilinearpf(f,prl) then
  79. w := f . w >>;
  80. w := reversip w;
  81. s := setdiff(s,w);
  82. if null s then return {w,{}};
  83. if null w then return {{},s};
  84. xtruncate!* := d;
  85. g := xidealpf append(g,w);
  86. s := foreach f in s join
  87. if f := xreduce(f,g) then {f};
  88. return {append(w,car p),cadr p} where p = lineargens(s,g,prl);
  89. end;
  90. symbolic procedure quasilinearpf(f,p);
  91. % f:pf, p:list of 1-form kernel -> quasilinearpf:bool
  92. % result is t if f is at most linear in p
  93. if null f then t
  94. else length intersection(wedgefax lpow f,p) <= 1
  95. and quasilinearpf(red f,p);
  96. put('semilinear,'psopfn,'semilineareval);
  97. symbolic procedure semilineareval s;
  98. % s:{eds} -> semilineareval:0 or 1
  99. if edsp(s := reval car s) then
  100. if edscall semilinearp s then 1 else 0
  101. else typerr(s,'eds);
  102. symbolic procedure semilinearp s;
  103. % s:eds -> semilinearp:bool
  104. % Test whether (closure of) system is semilinear
  105. if not normaledsp s then nil
  106. else if !*edssloppy then edscall quasilinearp s
  107. else semilinearsys(nonpfaffpart eds_sys edscall closure s,prlkrns s);
  108. symbolic procedure semilinearsys(s,prl);
  109. % s:sys, prl:list of 1-form kernel -> semilinearsys:bool
  110. % 0-forms are non-linear by definition here.
  111. null s or
  112. degreepf car s neq 0 and
  113. semilinearpf(car s,prl) and
  114. semilinearsys(cdr s,prl);
  115. symbolic procedure semilinearpf(f,p);
  116. % f:pf, p:list of 1-form kernel -> semilinearpf:bool
  117. % Works when xvars!* allows 0-forms as well - used in solvegraded.
  118. % result is t if f is at most linear in p with constant coefficient
  119. null f or
  120. (l = 0 or
  121. l = 1 and
  122. cfrmconstant numr lc f and
  123. cfrmconstant denr lc f
  124. where l = length foreach k in wedgefax lpow f join
  125. if k memq p then {k}) and
  126. semilinearpf(red f,p);
  127. put('pfaffian,'psopfn,'pfaffianeval);
  128. symbolic procedure pfaffianeval s;
  129. % s:{eds} -> pfaffianeval:0 or 1
  130. if edsp(s := reval car s) then
  131. if knowntrueeds(s,'pfaffian) or
  132. not knownfalseeds(s,'pfaffian) and
  133. edscall pfaffian s then 1 else 0
  134. else typerr(s,'eds);
  135. symbolic procedure pfaffian s;
  136. % s:eds -> pfaffian:bool
  137. knowntrueeds(s,'pfaffian) or
  138. not knownfalseeds(s,'pfaffian) and
  139. if not normaledsp s then
  140. rerror(eds,000,{"System not in normal form in pfaffian"})
  141. else if pfaffsys eds_sys s then
  142. << flagtrueeds(s,'pfaffian); t>>
  143. else
  144. << flagfalseeds(s,'pfaffian); nil>>;
  145. symbolic procedure pfaffsys s;
  146. % s:sys -> pfaffsys:bool
  147. % Systems with 0-forms are non-Pfaffian by definition here.
  148. begin scalar p,xtruncate!*; integer d;
  149. if scalarpart s then return nil;
  150. foreach f in s do
  151. << d := max(d,degreepf f);
  152. if degreepf f = 1 then p := f . p >>;
  153. s := setdiff(s,p);
  154. if null s then return t;
  155. if null p then return nil;
  156. xtruncate!* := d;
  157. p := xidealpf foreach f in p collect xreduce(exdfpf f,p);
  158. while s and null xreduce(car s,p) do s := cdr s;
  159. return null s;
  160. end;
  161. put('closure,'edsfn,'closure);
  162. put('closure,'rtypefn,'getrtypecar);
  163. symbolic procedure closure s;
  164. % s:eds -> closure:eds
  165. begin scalar p,sys,s0; integer d;
  166. if knowntrueeds(s,'closed) then return s;
  167. if s0 := geteds(s,'closure) then return s0;
  168. %%% if not normaledsp s then
  169. %%% rerror(eds,000,{"System not in normal form in closure"});
  170. %%% if scalarpart eds_sys s then
  171. %%% rerror(eds,000,{"Closure with 0-forms not yet implemented"});
  172. if scalarpart eds_sys s then
  173. lprim {"0-forms in closure: result may not be closed"};
  174. d := length eds_ind s;
  175. p := solvedpart eds_sys s;
  176. sys := foreach f in eds_sys s join
  177. if degreepf f < d and
  178. (f := xreduce(xreorder exdfpf f,p)) then {f};
  179. if null sys then return <<flagtrueeds(s,'closed); s>>;
  180. s0 := augmentsys(s,sys);
  181. if pfaffpart sys then rempropeds(s0,'solved);
  182. flagtrueeds(s0,'closed);
  183. s0 := normaleds s0; % might add 0-forms or become inconsistent
  184. return if emptyedsp s0 then s0
  185. else if scalarpart eds_sys s0 then s0
  186. else <<puteds(s,'closure,s0); s0>>;
  187. end;
  188. flag('(closure),'hidden);
  189. % symbolic operator closed;
  190. % symbolic procedure closed u;
  191. % % u:eds|rlist of prefix|prefix -> closed:bool
  192. % % True if u is a closed eds, a closed system of forms or a closed
  193. % % form
  194. % if edsp u then
  195. % knowntrueeds(u,'closed) or edscall closededs u
  196. % else if rlistp u then
  197. % closedsys foreach f in getrlist u collect xpartitop f
  198. % else null exdfpf xpartitop u;
  199. % flag('(closed),'boolean);
  200. % symbolic procedure closededs s;
  201. % % s:eds -> closededs:bool
  202. % knowntrueeds(s,'closed) or
  203. % if closedsys eds_sys s then
  204. % << flagtrueeds(s,'closed); t>>;
  205. put('closed,'psopfn,'closedeval);
  206. symbolic procedure closedeval s;
  207. % s:{eds} -> closedeval:0 or 1
  208. if edsp(s := reval car s) then
  209. if knowntrueeds(s,'closed) or
  210. not knownfalseeds(s,'closed) and
  211. edscall closed s then 1 else 0
  212. else if rlistp s then
  213. if closedsys foreach f in getrlist s collect xpartitop f then 1
  214. else 0
  215. else if null exdfpf xpartitop s then 1 else 0;
  216. symbolic procedure closed s;
  217. % s:eds -> closed:bool
  218. knowntrueeds(s,'closed) or
  219. not knownfalseeds(s,'closed) and
  220. if closedsys eds_sys s then
  221. << flagtrueeds(s,'closed); t>>
  222. else
  223. << flagfalseeds(s,'closed); nil>>;
  224. symbolic procedure closedsys s;
  225. % s:sys -> closedsys:bool
  226. begin scalar p,xtruncate!*; integer d;
  227. foreach f in s do
  228. << d := max(d,1 + degreepf f);
  229. f := xreduce(exdfpf f,s);
  230. if f then p := f . p >>;
  231. if null p then return t;
  232. xtruncate!* := d;
  233. s := xidealpf s;
  234. while p and null xreduce(car p,s) do p := cdr p;
  235. return null p;
  236. end;
  237. symbolic operator frobenius;
  238. symbolic procedure frobenius u;
  239. % u:eds|rlist of prefix|prefix -> frobenius:bool
  240. % True if u is an eds or list of forms generated by 1-forms
  241. % satisfying the Frobenius test
  242. if edsp u then
  243. null nonpfaffpart eds_sys u and
  244. null nonpfaffpart eds_sys edscall closure u
  245. else if rlistp u then
  246. frobeniussys foreach f in getrlist u collect xpartitop f
  247. else rerror(eds,000,"Invalid argument to frobenius");
  248. flag('(frobenius),'boolean);
  249. symbolic procedure frobeniussys s;
  250. % s:sys -> frobeniussys:bool
  251. begin scalar p;
  252. p := pfaffpart s;
  253. s := union(foreach f in p collect exdfpf f,setdiff(s,p));
  254. p := xautoreduce p;
  255. while s and null xreduce(car s,p) do s := cdr s;
  256. return null s;
  257. end;
  258. put('cauchy_system,'rtypefn,'quotelist);
  259. put('cauchy_system,'listfn,'evalcauchysys);
  260. symbolic procedure evalcauchysys(u,v);
  261. % u:{prefix}, v:bool -> evalcauchysys:rlist
  262. if xedsp(u := reval car u) then
  263. evalcartansys({edscall closure u},v)
  264. else if rlistp u then
  265. evalcartansys({append(u,foreach f in cdr u collect aeval{'d,f})},v)
  266. else
  267. evalcartansys({makelist {u,aeval{'d,u}}},v);
  268. put('cartan_system,'rtypefn,'quotelist);
  269. put('cartan_system,'listfn,'evalcartansys);
  270. symbolic procedure evalcartansys(u,v);
  271. % u:{prefix}, v:bool -> evalcartansys:rlist
  272. if xedsp(u := reval car u) then
  273. if edsp u then !*sys2a1(edscall cartansyseds u,v)
  274. else makelist for each s in cdr u
  275. collect !*sys2a1(edscall cartansyseds u,v)
  276. else if rlistp u then
  277. !*sys2a1(cartansys !*a2sys u,v)
  278. else
  279. !*sys2a1(cartansyspf xpartitop u,v);
  280. symbolic procedure cartansys u;
  281. % u:list of pf -> cartansys:list of pf
  282. begin scalar xtruncate!*;
  283. xtruncate!* := eval('max.foreach f in u collect degreepf f);
  284. xtruncate!* := xtruncate!* - 1;
  285. u := xidealpf u;
  286. return reversip xautoreduce purge foreach f in u join cartansyspf f;
  287. end;
  288. symbolic procedure cartansyspf f;
  289. % f:pf -> cartansyspf:list of pf
  290. begin scalar x,p,q,z;
  291. if degreepf f = 1 then return {f};
  292. while f do
  293. begin
  294. p := wedgefax lpow f;
  295. foreach k in p do
  296. if not((q := delete(k,p)) member z) then
  297. << z := q . z;
  298. x := xcoeff(f,q) . x >>;
  299. f := red f;
  300. end;
  301. return reverse xautoreduce purge x;
  302. end;
  303. symbolic procedure cartansyseds s;
  304. % s:eds -> cartansyseds:sys
  305. cartansys eds_sys s;
  306. put('linearise,'edsfn,'lineariseeds);
  307. put('linearise,'rtypefn,'quoteeds);
  308. put('linearize,'edsfn,'lineariseeds);
  309. put('linearize,'rtypefn,'quoteeds);
  310. flag('(linearise linearize),'nospread);
  311. symbolic procedure lineariseeds u;
  312. % u:{eds[,rlist]} -> lineariseeds:eds
  313. begin scalar x;
  314. if null u or length u > 2 then
  315. rerror(eds,000,{"Wrong number of arguments to linearise"});
  316. if cdr u then x := !*a2sys cadr u;
  317. if nonpfaffpart x then typerr(cadr u,"integral element");
  318. return edscall linearise(car u,x);
  319. end;
  320. symbolic procedure linearise(s,x);
  321. % s:eds, x:sys -> linearise:eds
  322. % x is an integral element of s, result is linearisation of s at x
  323. % in original cobasis.
  324. if quasilinearp s then lineargenerators s else
  325. begin scalar xx,q,prl;
  326. s := copyeds closure s;
  327. x := xreordersys x;
  328. q := nonpfaffpart eds_sys s;
  329. prl := prlkrns s;
  330. % pick out those products which occur
  331. xx := purge foreach f in q join
  332. foreach k in xpows f join
  333. nonlinfax intersection(wedgefax k,prl);
  334. % form the relevant poducts from x
  335. x := pair(lpows x,x);
  336. xx := foreach pr in xx collect
  337. wedgepf(cdr atsoc(car pr,x),cdr atsoc(cadr pr,x));
  338. % reduce the system mod x^x
  339. eds_sys s := append(setdiff(eds_sys s,q),
  340. foreach f in q join if f := xreduce(f,xx) then {f});
  341. flagtrueeds(s,'quasilinear);
  342. return s;
  343. end;
  344. symbolic procedure nonlinfax l;
  345. % l:list of kernel -> nonlinfax:list of list of 2 kernel
  346. % Collect elements of l pairwise, discarding any odd element.
  347. if length l > 1 then {car l,cadr l} . nonlinfax cddr l;
  348. %% symbolic procedure linearise(s,x);
  349. %% % s:eds, x:sys -> linearise:eds
  350. %% % x is an integral element of s, result is linearisation of s at x
  351. %% % in original cobasis.
  352. %% % NB Changes background coframing.
  353. %% if quasilinearp s then lineargenerators s else
  354. %% begin scalar s1;
  355. %% s1 := linearise0(s,x);
  356. %% x := cadr s1;
  357. %% s1 := car s1;
  358. %% return xformeds0(s1,x,setdiff(edscob s,edscob s1));
  359. %% end;
  360. %%
  361. %%
  362. %% symbolic procedure linearise0(s,x);
  363. %% % s:eds, x:sys -> linearise0:{eds,xform}
  364. %% % x is an integral element of s, result is linearisation of s at x
  365. %% % in a cobasis based on x, together with transform required for
  366. %% % original cobasis. The structure equations are NOT updated.
  367. %% % NB Changes background coframing.
  368. %% begin scalar c,y,prl;
  369. %% c := foreach f in x collect mkform!*(intern gensym(),1);
  370. %% x := pair(c,x);
  371. %% y := invxform x;
  372. %% s := copyeds closure s;
  373. %% s := tmpind xformeds0(s,y,c);
  374. %% x := append(x,cadr s);
  375. %% s := car s;
  376. %% prl := prlkrns s;
  377. %% eds_sys s := foreach f in eds_sys s join
  378. %% if degreepf f < 2 then {f}
  379. %% else if inhomogeneouspart(f,prl) then
  380. %% typerr(!*sys2a foreach p in x collect cdr p,
  381. %% "integral element")
  382. %% else if f := linearpart(f,prl) then {f};
  383. %% flagtrueeds(s,'quasilinear);
  384. %% return {s,x};
  385. %% end;
  386. put('one_forms,'rtypefn,'quotelist);
  387. put('one_forms,'listfn,'oneformseval);
  388. symbolic procedure oneformseval(u,v);
  389. % u:{xeds|rlist}, v:bool -> oneformseds:rlist
  390. if edsp(u := reval car u) then
  391. !*sys2a1(pfaffpart eds_sys u,v)
  392. else if xedsp u then
  393. makelist foreach s in getrlist u collect
  394. !*sys2a1(pfaffpart eds_sys s,v)
  395. else
  396. makelist foreach f in getrlist u join
  397. if reval{'exdegree,f}=1 then {f};
  398. put('zero_forms,'rtypefn,'quotelist);
  399. put('zero_forms,'listfn,'zeroformseval);
  400. put('nought_forms,'rtypefn,'quotelist);
  401. put('nought_forms,'listfn,'zeroformseval);
  402. symbolic procedure zeroformseval(u,v);
  403. % u:{xeds|rlist}, v:bool -> zeroformseval:rlist
  404. if edsp(u := reval car u) then
  405. !*sys2a1(scalarpart eds_sys u,v)
  406. else if xedsp u then
  407. makelist foreach s in getrlist u collect
  408. !*sys2a1(scalarpart eds_sys s,v)
  409. else
  410. makelist foreach f in getrlist u join
  411. if reval{'exdegree,f}=0 then {f};
  412. endmodule;
  413. end;