edscfrm.red 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. module edscfrm;
  2. % Coframing structure for EDS
  3. % Author: David Hartley
  4. Comment. An EDS coframing is stored in a list:
  5. cfrm ::= {'!!cfrm!!,cob,crd,drv,rsx}
  6. cob ::= list of kernel
  7. crd ::= list of kernel
  8. drv ::= list of rule
  9. rsx ::= list of prefix (mostly !*sq)
  10. The procedure !*a2cfrm allows a number of algebraic quantities to be
  11. turned into coframings. These quantities will be collectively termed
  12. cfrmdef's.
  13. cfrmdef ::= cfrm|eds|rlist of pform
  14. endcomment;
  15. fluid '(cfrmcob!* cfrmcrd!* cfrmdrv!* cfrmrsx!* xvars!* kord!*);
  16. global '(!*sqvar!*);
  17. % Type definition
  18. put('cfrm,'tag,'!!cfrm!!);
  19. put('!!cfrm!!,'rtypefn,'quotecfrm);
  20. symbolic procedure quotecfrm u; 'cfrm;
  21. % Evaluation interface
  22. put('cfrm,'evfn,'cfrmeval);
  23. symbolic procedure cfrmeval(u,v);
  24. % u:prefix, v:bool -> cfrmeval:prefix
  25. % v is t for reval, nil for aeval. Here it is ignored (and abused as
  26. % a local variable!). u is either an id with an avalue whose car has
  27. % rtype cfrm or a list with rtype cfrm. This routine differs from
  28. % most evfn's in that the argument list is evaluated prior to calling
  29. % a cfrmfn.
  30. if atom u then
  31. cfrmeval(if flagp(u,'share) then eval u
  32. else cadr get(u,'avalue),v)
  33. else if cfrmp u then u
  34. else if v := get(car u,'cfrmfn) then
  35. if flagp(car u,'nospread) then cfrmprotect{v,revlis cdr u}
  36. else cfrmprotect(v . revlis cdr u)
  37. else rerror(eds,000,{"Illegal operation on coframings"});
  38. symbolic procedure cfrmprotect u;
  39. % u:prefix -> cfrmprotect:prefix
  40. % Protected evaluation environment for
  41. % operations on coframings.
  42. begin scalar m,ok,od;
  43. scalar xvars!*;
  44. % If one of the arguments is cfrm, take the last one
  45. foreach v in cdr u do if cfrmp v then m := v;
  46. % Save environment and adjust for cfrm calculation.
  47. ok := kord!*; od := append(get('d,'kvalue),nil); % copy pairs
  48. if m then m := setcfrm m;
  49. u := errorset!*(car u . foreach j in cdr u collect mkquote j,t);
  50. % Restore environment
  51. if m then setcfrm m;
  52. setkorder ok; if od then put('d,'kvalue,od) else remprop('d,'kvalue);
  53. if errorp u then error1()
  54. else return car u;
  55. end;
  56. % Constructors and tests
  57. symbolic procedure mkcfrm u;
  58. % tag u as cfrm
  59. '!!cfrm!! . u;
  60. symbolic procedure copycfrm u;
  61. % copy pairs in u to allow destructive operations
  62. foreach p in u collect p;
  63. symbolic procedure cfrmp u;
  64. % u:any -> cfrmp:bool
  65. eqcar(u,'!!cfrm!!);
  66. symbolic procedure emptycfrm;
  67. % -> emptycfrm:cfrm
  68. mkcfrm{{},{},{},{}};
  69. % Global background coframing
  70. put('set_coframing,'psopfn,'setcfrmeval);
  71. symbolic procedure setcfrmeval u;
  72. % u:{cfrm|nil} -> setcfrmeval:cfrm
  73. begin scalar m;
  74. u :=
  75. if null u or (u = {nil}) then setcfrm emptycfrm()
  76. else if cfrmp(m := reval car u) then setcfrm m
  77. else if edsp m then setcfrm eds_cfrm m
  78. else typerr(u,'cfrm);
  79. rmsubs();
  80. return u;
  81. end;
  82. symbolic procedure setcfrm m;
  83. % m:cfrm -> setcfrm:cfrm
  84. % Set up m as background coframing, returning old one.
  85. % NB. Changes kernel order and let rules.
  86. begin scalar n;
  87. n := getcfrm();
  88. if m = n then return n;
  89. cfrmswapkord(cfrm_cob m,cfrm_cob n);
  90. cfrmswaprules(cfrm_drv m,cfrm_drv n);
  91. cfrmcob!* := cfrm_cob m;
  92. cfrmcrd!* := cfrm_crd m;
  93. cfrmdrv!* := cfrm_drv m;
  94. cfrmrsx!* := (foreach p in cfrm_rsx m collect
  95. xpartitop p) where xvars!* = cfrm_crd m;
  96. return n;
  97. end;
  98. symbolic procedure cfrmswapkord(new,old);
  99. % new,old:list of kernel -> cfrmswapkord:list of kernel
  100. % Swap old for new in kernel ordering. New kernels come first.
  101. % Return old kernel ordering.
  102. setkorder append(new,setdiff(kord!*,append(new,old)));
  103. symbolic procedure cfrmswaprules(new,old);
  104. % new,old:list of rules -> cfrmswaprules:nil
  105. % Swap the current rules given by old for those contained in
  106. % new. Since these rules will be removed before returning to the
  107. % outside, try to preserve !*sqvar!*. This may cause trouble.
  108. begin scalar sq;
  109. if new = old then return;
  110. sq := !*sqvar!*;
  111. if old then rule!-list(old,nil);
  112. if new then rule!-list(new,t);
  113. !*sqvar!* := sq;
  114. car !*sqvar!* := t;
  115. end;
  116. symbolic procedure getcfrm();
  117. % -> getcfrm:cfrm
  118. % Get background coframing.
  119. mkcfrm{cfrmcob!*,cfrmcrd!*,cfrmdrv!*,
  120. foreach f in cfrmrsx!* collect !*pf2a f};
  121. % Input interface
  122. put('coframing,'rtypefn,'quotecfrm);
  123. put('coframing,'cfrmfn,'!*a2cfrm);
  124. flag('(coframing),'nospread);
  125. symbolic procedure !*a2cfrm u;
  126. % u:nil|{cfrmdef}|{xeds}|list of cpt(see below) -> !*a2cfrm:cfrm
  127. % With no arguments, return the background coframing. For a cfrm,
  128. % just return it (this redundancy allows !*a2cfrm to be called from
  129. % contact etc). For an eds or xeds, just return the associated
  130. % coframing(s). For a list of pforms, deduce the coframing
  131. % structure required to sustain them. Otherwise, the coframing is
  132. % specified by a list of its components.
  133. if null u then getcfrm()
  134. else if length u = 1 then
  135. if cfrmp car u then
  136. car u
  137. else if edsp car u then
  138. eds_cfrm car u
  139. else if xedsp car u then
  140. makelist foreach s in getrlist car u collect eds_cfrm s
  141. else
  142. !*sys2cfrm !*a2sys car u
  143. else !*a2cfrm1 u;
  144. symbolic procedure !*a2cfrm1 u;
  145. % u:list of cpt -> !*a2cfrm1:cfrm
  146. % where cpt is one of
  147. % cob - list of 1-form kernel
  148. % crd - list of 0-form kernel
  149. % rsx - list of prefix inequality
  150. % drv - list of rule
  151. begin scalar cob,crd,drv,rsx;
  152. % Read through arguments
  153. foreach l in u do
  154. if null(l := getrlist indexexpandeval {l}) then nil
  155. else if eqexpr car l then drv := l
  156. else if eqcar(car l,'neq) then rsx := l
  157. else if xdegree car l = 1 then cob := l
  158. else if xdegree car l = 0 then crd := l
  159. else rerror(eds,000,"Badly formed coframing");
  160. % Check correctness of each item and convert to desired type
  161. cob := foreach k in cob collect
  162. if xdegree(k := !*a2k k) = 1 then k
  163. else typerr(k,"cobasis element");
  164. crd := foreach k in crd collect
  165. if xdegree(k := !*a2k k) = 0 and
  166. xvarp k where xvars!* = t then k
  167. else typerr(k,"coordinate");
  168. drv := foreach r in drv collect
  169. if eqexpr r then r
  170. else typerr(r,"structure equation");
  171. rsx := foreach f in rsx collect
  172. if eqcar(f,'neq) then aeval {'difference,cadr f,caddr f}
  173. else typerr(f,"restriction (only neq allowed)");
  174. return checkcfrm mkcfrm{cob,crd,drv,rsx};
  175. end;
  176. symbolic procedure !*sys2cfrm s;
  177. % s:sys -> !*sys2cfrm:cfrm
  178. % Return coframing suitable for set of pforms s. Error if variables
  179. % of other degrees found explicitly in s. All structure equations are
  180. % checked for new forms and restrictions.
  181. begin scalar crd,cob,drv,rsx;
  182. while s do
  183. begin scalar new;
  184. foreach k in kernelspf car s do
  185. if not(k memq crd or k memq cob) and exformp k then
  186. if xdegree k = 0 then
  187. if assoc(k,depl!*) or eqcar(k,'partdf) or
  188. not(xvarp k where xvars!* = t) then % function
  189. foreach p in xpows exdfk k do new := !*k2pf p . new
  190. else
  191. << crd := k . crd;
  192. new := exdfk k . new;
  193. if car new neq !*k2pf {'d,k} then
  194. drv := {'replaceby,{'d,k},!*pf2a car new} . drv >>
  195. else if xdegree k = 1 then
  196. << cob := k . cob;
  197. if not exact k then
  198. << new := exdfk k . new;
  199. if car new neq !*k2pf {'d,k} then
  200. drv := {'replaceby,{'d,k},!*pf2a car new} . drv
  201. else
  202. new := cdr new >>
  203. else if not(cadr k memq crd) then
  204. crd := cadr k . crd >>
  205. else typerr(k,"0-form or 1-form");
  206. foreach q in xcoeffs car s do
  207. if not freeoffl(denr q,crd) then
  208. rsx := mk!*sq !*f2q denr q . rsx;
  209. s := append(cdr s,new);
  210. end;
  211. return purgecfrm mkcfrm{sort(cob,'termordp),sort(crd,'termordp),drv,
  212. rsx}
  213. end;
  214. % Output interface
  215. put('!!cfrm!!,'prifn,'cfrmprint);
  216. put('!!cfrm!!,'fancy!-reform,'!*cfrm2a);
  217. put('cfrm,'texprifn,'texpricfrm);
  218. %put('cfrm,'prepfn,'!*cfrm2a);
  219. symbolic procedure cfrmprint m;
  220. % m:cfrm -> cfrmprint:bool
  221. % if already in external format, use inprint
  222. maprin !*cfrm2a m;
  223. symbolic procedure !*cfrm2a m;
  224. % m:cfrm -> !*cfrm2a:prefix
  225. "coframing" .
  226. {makelist cfrm_cob m,
  227. makelist cfrm_crd m,
  228. makelist foreach r in cfrm_drv m collect !*rule2prefix r,
  229. makelist foreach f in cfrm_rsx m collect {'neq,reval f,0}};
  230. symbolic procedure !*rule2prefix r;
  231. car r . foreach a in cdr r collect
  232. if eqcar(a,'!*sq) then prepsq!* cadr a else a;
  233. symbolic procedure texpricfrm(u,v,w);
  234. % Have to hide coframing from TRI's makeprefix
  235. texvarpri('texpriedsop . !*cfrm2a u,v,w);
  236. symbolic procedure texpricfrm(u,v,w);
  237. % Have to hide the coframing from TRI's makeprefix
  238. % but not from TRIX's makeprefix.
  239. texvarpri(
  240. if get('hodge,'texname) then !*cfrm2a u
  241. else 'texpriedsop . !*cfrm2a u,v,w);
  242. % Algebraic access to coframing parts
  243. put('cobasis,'rtypefn,'quotelist);
  244. put('cobasis,'listfn,'cobeval);
  245. symbolic procedure cobeval(s,v);
  246. % s:{any}, v:bool -> cobeval:prefix cob
  247. % cobeval1 returns true prefix always
  248. if null v then aeval cobeval1 s else cobeval1 s;
  249. symbolic procedure cobeval1 s;
  250. % s:{any} -> cobeval1:prefix cob
  251. % For an eds, returns the cobasis in the ordering used internally.
  252. if cfrmp(s := reval car s) then
  253. makelist cfrm_cob s
  254. else if edsp s then
  255. makelist edscob s
  256. else if xedsp s then
  257. makelist foreach x in cdr s collect makelist edscob x
  258. else edsparterr(s,"cobasis");
  259. put('coordinates,'rtypefn,'quotelist);
  260. put('coordinates,'listfn,'crdeval);
  261. symbolic procedure crdeval(s,v);
  262. % s:{any}, v:bool -> crdeval:prefix cob
  263. % crdeval1 returns true prefix always
  264. if null v then aeval crdeval1 s else crdeval1 s;
  265. symbolic procedure crdeval1 s;
  266. % s:{any} -> crdeval1:prefix cob
  267. if cfrmp(s := reval car s) then
  268. makelist cfrm_crd s
  269. else if edsp s then
  270. makelist cfrm_crd eds_cfrm s
  271. else if xedsp s then
  272. makelist foreach x in cdr s collect makelist cfrm_crd eds_cfrm x
  273. else if rlistp s then
  274. makelist purge foreach x in getrlist s join
  275. getrlist allcoords x
  276. else if null getrtype s then
  277. allcoords s
  278. else edsparterr(s,"coordinates");
  279. put('structure_equations,'rtypefn,'quotelist);
  280. put('structure_equations,'listfn,'drveval);
  281. symbolic procedure drveval(s,v);
  282. % s:{cfrm}|{eds}|{xeds}|{rlist}|{rlist,rlist}, v:bool
  283. % -> drveval:prefix cob
  284. reval1(drveval1 s,v);
  285. symbolic procedure drveval1 s;
  286. % s:{cfrm}|{eds}|{xeds}|{rlist}|{rlist,rlist} -> drveval1:prefix cob
  287. % Input can be cfrm, eds, xeds, xform or xform + inverse
  288. if cfrmp car(s := revlis s) then
  289. makelist cfrm_drv car s
  290. else if edsp car s then
  291. makelist cfrm_drv eds_cfrm car s
  292. else if xedsp car s then
  293. makelist foreach x in getrlist car s collect
  294. makelist cfrm_drv eds_cfrm x
  295. else if rlistp car s and cdr car s and eqexpr cadr car s then
  296. xformdrveval s
  297. else edsparterr(s,"structure equations");
  298. put('restrictions,'rtypefn,'quotelist);
  299. put('restrictions,'listfn,'rsxeval);
  300. symbolic procedure rsxeval(s,v);
  301. % s:{any}, v:bool -> rsxeval:prefix cob
  302. if cfrmp(s := reval car s) then
  303. makelist foreach r in cfrm_rsx s collect
  304. {'neq,reval1(r,v),0}
  305. else if edsp s then
  306. makelist foreach r in cfrm_rsx eds_cfrm s collect
  307. {'neq,reval1(r,v),0}
  308. else if xedsp s then
  309. makelist foreach x in cdr s collect
  310. makelist foreach r in cfrm_rsx eds_cfrm x collect
  311. {'neq,reval1(r,v),0}
  312. else edsparterr(s,"restrictions");
  313. symbolic procedure edsparterr(u,v);
  314. % u:prefix, v:any -> edsparterr:error
  315. % u is math-printed (with nat off), v is line-printed
  316. msgpri(nil,u,{"has no",v},nil,t);
  317. symbolic procedure cfrmpart(m,n);
  318. % m:cfrm, n:int -> cfrmpart:prefix
  319. if n = 0 then 'coframing
  320. else if n = 1 then makelist cfrm_cob m
  321. else if n = 2 then makelist cfrm_crd m
  322. else if n = 3 then makelist cfrm_drv m
  323. else if n = 4 then
  324. makelist foreach r in cfrm_rsx m collect {'neq,r,0}
  325. else parterr(m,n);
  326. put('!!cfrm!!,'partop,'cfrmpart);
  327. symbolic procedure cfrmsetpart(m,l,r);
  328. % m:cfrm, l:list of int, r:prefix -> cfrmsetpart:error
  329. rerror(eds,000,"Part setting disabled on coframing operator");
  330. put('!!cfrm!!,'setpartop,'cfrmsetpart);
  331. % Consistency check, resimplification and cleanup
  332. symbolic procedure checkcfrm m;
  333. % m:cfrm -> checkcfrm:cfrm
  334. % Check integrity and completeness of m. Cobasis must be correctly
  335. % specified, other details (eg missing coordinates, restrictions) can
  336. % be deduced via !*sys2cfrm. Call via cfrmprotect to install correct
  337. % structure equations and korder.
  338. cfrmprotect {'checkcfrm1,m};
  339. symbolic procedure checkcfrm1 m;
  340. % m:cfrm -> checkcfrm1:cfrm
  341. % As checkcfrm, but assumes m is background coframing.
  342. begin scalar n,u,drv;
  343. m := copycfrm m;
  344. % Pick up coframing implied by cob/crd
  345. n := !*sys2cfrm !*a2sys makelist append(cfrm_cob m,cfrm_crd m);
  346. % Error if cobasis different
  347. if cfrm_cob n neq cfrm_cob m then
  348. rerror(eds,000,"Missing cobasis elements");
  349. % Coordinates and structure equations of n must include those of m,
  350. % but some restrictions may not be noticed.
  351. cfrm_rsx n := union(cfrm_rsx m,cfrm_rsx n);
  352. % Check whether all structure equations are known.
  353. % Missing coordinate differentials show up as missing cobasis
  354. % elements.
  355. drv := foreach d in cfrm_drv n collect cadr d;
  356. foreach k in cfrm_cob n do
  357. if not exact k and not member({'d,k},drv) then u := k . u;
  358. if u then edsverbose("Missing structure equations",reverse u,'cob);
  359. return purgecfrm n;
  360. end;
  361. symbolic procedure resimpcfrm s;
  362. % s:cfrm -> resimpcfrm:cfrm
  363. begin scalar r;
  364. r := copycfrm s;
  365. cfrm_cob r := foreach f in cfrm_cob s collect reval f;
  366. cfrm_crd r := foreach f in cfrm_crd s collect reval f;
  367. cfrm_drv r := foreach f in cfrm_drv s collect reval f;
  368. cfrm_rsx r := foreach f in cfrm_rsx s collect aeval f;
  369. return if r = s then s else checkcfrm r;
  370. end;
  371. put('reorder,'psopfn,'reordereval);
  372. % Can't have an cfrmfn here because we want the external kernel order
  373. symbolic procedure reordereval s;
  374. % s:{any} -> reordereval:prefix cob
  375. if cfrmp(s := reval car s) then
  376. reordercfrm s
  377. else if edsp s then
  378. reordereds s
  379. else if xedsp s then
  380. makelist foreach x in cdr s collect reordereds x
  381. else msgpri(nil,nil,"Don't know how to reorder",s,t);
  382. symbolic procedure reordercfrm s;
  383. % s:cfrm -> reordercfrm:cfrm
  384. begin scalar r;
  385. r := copycfrm s;
  386. cfrm_cob r := sort(cfrm_cob s,'termordp);
  387. cfrm_crd r := sort(cfrm_crd s,'termordp);
  388. cfrm_drv r :=
  389. sort(cfrm_drv s,'(lambda (x y) (termordp (cadr x) (cadr y))));
  390. cfrm_rsx r := sort(cfrm_rsx s,'ordop);
  391. return if r = s then s else r;
  392. end;
  393. put('cleanup,'rtypefn,'getrtypecar);
  394. put('cleanup,'cfrmfn,'cleancfrm);
  395. symbolic procedure cleancfrm m;
  396. % m:cfrm -> cleancfrm:cfrm
  397. % Clean up, resimplify and check m.
  398. begin scalar n;
  399. n := resimpcfrm m;
  400. return % eq test here essential!
  401. if n eq m then checkcfrm m
  402. else n;
  403. end;
  404. symbolic procedure purgecfrm m;
  405. % m:cfrm -> purgecfrm:cfrm
  406. % Clean up drv and rsx parts of m.
  407. % Background coframing need not be m.
  408. begin scalar cfrmcrd!*,cfrmcob!*;
  409. m := copycfrm m;
  410. cfrmcob!* := cfrm_cob m;
  411. cfrmcrd!* := cfrm_crd m;
  412. cfrm_drv m := purgedrv cfrm_drv m;
  413. cfrm_rsx m := purgersx cfrm_rsx m;
  414. return m;
  415. end;
  416. symbolic procedure purgedrv x;
  417. % x:drv -> purgedrv:drv
  418. % Sift through structure equations, checking they are all current.
  419. % Can't use memq here because lhs's are not evaluated, so kernels may
  420. % not be unique. Take out d x => d x as well. Should we catch d(0)?
  421. begin scalar drv,dl,dr,r2;
  422. foreach r in x do
  423. if exact(dl := cadr r) and
  424. (cadr dl member cfrmcob!* or cadr dl member cfrmcrd!*) and
  425. not(kernp(dr := simp!* caddr r) and dl = mvar numr dr) then
  426. if null (r2 := assoc(dl,drv)) then
  427. drv := (dl . dr) . drv
  428. else if cdr r2 neq dr and
  429. resimp cdr r2 neq resimp dr then
  430. << edsdebug("Inconsistent structure equations",
  431. makelist{{'replaceby,dl,mk!*sq dr},
  432. {'replaceby,car r2,mk!*sq cdr r2}},
  433. 'prefix);
  434. rerror(eds,000,"Inconsistent structure equations") >>;
  435. drv := foreach p in reversip drv collect
  436. {'replaceby,car p,mk!*sq cdr p};
  437. return sort(drv,'(lambda (x y) (termordp (cadr x) (cadr y))));
  438. end;
  439. symbolic procedure purgersx x;
  440. % x:rsx -> purgersx:rsx
  441. begin scalar rsx;
  442. foreach f in reverse purge x do
  443. rsx := addrsx(numr simp!* f,rsx);
  444. return rsx;
  445. end;
  446. symbolic procedure addrsx(x,rsx);
  447. % x:sf, rsx:rsx -> addrsx:rsx
  448. % Must reorder before fctrf in case we are handling expressions from
  449. % another coframing.
  450. begin
  451. if not cfrmconstant x and
  452. not member(mk!*sq !*f2q x,rsx)
  453. then foreach f in cdr fctrf reorder x do
  454. if not cfrmconstant car f and
  455. not member(f := mk!*sq !*f2q car f,rsx)
  456. then rsx := f . rsx;
  457. return rsx;
  458. end;
  459. % Algebraic operations
  460. infix cross;
  461. precedence cross,times;
  462. put('cross,'rtypefn,'getrtypecar);
  463. put('cross,'edsfn,'extendeds);
  464. put('cross,'cfrmfn,'cfrmprod);
  465. flag('(cross),'nospread);
  466. flag('(cross),'nary);
  467. symbolic procedure extendeds u;
  468. % u:eds.list of cfrmdef -> extendeds:eds
  469. begin scalar s,jet0;
  470. % trivial case first
  471. if null cdr u then return car u;
  472. s := copyeds car u;
  473. u := cfrmprod cdr u;
  474. if jet0 := geteds(s,'jet0) then
  475. puteds(s,'jet0,
  476. purgejet0(append(jet0,setdiff(cfrm_crd u,edscrd s)),
  477. uniqids indkrns s));
  478. eds_cfrm s := cfrmprod2(eds_cfrm s,u);
  479. remkrns s;
  480. return normaleds purgeeds!* s;
  481. end$
  482. symbolic procedure purgejet0(crd,idxl);
  483. begin scalar j,j0;
  484. idxl := foreach i in flatindxl idxl collect lowerind i;
  485. foreach c in crd do
  486. << j := j0;
  487. while j and not jetprl(c,car j,idxl) do j := cdr j;
  488. if null j then
  489. j0 := c . foreach c0 in j0 join
  490. if not jetprl(c0,c,idxl) then {c0} >>;
  491. return j0;
  492. end$
  493. symbolic procedure jetprl(c,c0,idxl);
  494. if c := splitoffindices(c0,c) then subsetp(cdr c,idxl)$
  495. symbolic procedure cfrmprod u;
  496. % u:list of cfrmdef -> cfrmprod:cfrm
  497. % u is non-empty, first line excludes m:xeds
  498. (if not cfrmp m then typerr(car u,"coframing")
  499. else if length u = 1 then m
  500. else cfrmprotect {'cfrmprod2,m,cfrmprod cdr u})
  501. where m = !*a2cfrm{car u};
  502. symbolic procedure cfrmprod2(m,n);
  503. % m,n:cfrm -> cfrmprod2:cfrm
  504. if xnp(cfrm_cob m,cfrm_cob n) or
  505. xnp(cfrm_crd m,cfrm_crd n)
  506. then cfrmbprod(m,n)
  507. else mkcfrm{append(cfrm_cob m,cfrm_cob n),
  508. append(cfrm_crd m,cfrm_crd n),
  509. append(cfrm_drv m,cfrm_drv n),
  510. append(cfrm_rsx m,cfrm_rsx n)}$
  511. symbolic procedure cfrmbprod(m,n);
  512. % m,n:cfrm -> cfrmbprod:cfrm
  513. % m and n are cfrm with common elements,
  514. % result is bundle product.
  515. begin scalar z,u,v;
  516. % get common elements
  517. z := !*a2sys makelist append(
  518. intersection(cfrm_cob m,cfrm_cob n),
  519. intersection(cfrm_crd m,cfrm_crd n));
  520. % generate coframing from each
  521. setcfrm m; u := !*sys2cfrm z;
  522. setcfrm n; v := !*sys2cfrm z;
  523. % check equivalence
  524. if not equalcfrm(u,v) then
  525. rerror(eds,000,
  526. "Cannot form coframing product: overlap cannot be factored");
  527. % compose as (m/u).n
  528. return resimpcfrm mkcfrm{
  529. append(setdiff(cfrm_cob m,cfrm_cob u),cfrm_cob n),
  530. append(setdiff(cfrm_crd m,cfrm_crd u),cfrm_crd n),
  531. append(setdiff(cfrm_drv m,cfrm_drv u),cfrm_drv n),
  532. append(setdiff(cfrm_rsx m,cfrm_rsx u),cfrm_rsx n)};
  533. end$
  534. put('dim,'simpfn,'simpdim);
  535. symbolic procedure simpdim u;
  536. % u:{any} -> simpdim:sq
  537. if cfrmp(u := reval car u) then
  538. length cfrm_cob u ./ 1
  539. else if edsp u then
  540. length edscob u ./ 1
  541. else edsparterr(u,"dimension");
  542. % Auxiliary routines
  543. Comment. The following routines are for testing whether an expression
  544. is nowhere zero on a restricted coframing specified by some coordinates
  545. and some expressions assumed not to vanish. Expressions with unknown
  546. (explicit or implicit) dependence on the coordinates are not nowhere
  547. zero.
  548. endcomment;
  549. symbolic procedure cfrmnowherezero x;
  550. % x:sf -> cfrmnowherezero:bool
  551. % Heuristic to test if x is nowhere zero on the coframing described
  552. % by cfrmcrd!* restricted away from the zeros of the expressions in
  553. % cfrmrsx!*. This version checks first directly, and then tests (if
  554. % x can be factorised) whether all the factors are nowhere zero.
  555. (domainp x or % quick exit for constants
  556. cfrmnowherezero1 xpartitsq(x ./ 1) or % check x as a whole
  557. if (x := cdr fctrf x) and (length x > 1 or cdar x > 1) then
  558. << while x and cfrmnowherezero1 xpartitsq(caar x ./ 1) do
  559. x := cdr x;
  560. null x >>)
  561. where xvars!* = cfrmcrd!*;
  562. symbolic procedure cfrmnowherezero1 x;
  563. % x:pf -> cfrmnowherezero1:bool
  564. % Result is t if x is constant or doesn't vanish on restricted space,
  565. % as tested by substituting x=0 into the expressions in cfrmrsx!* and
  566. % seeing if one vanishes. If lc x contains an (explicit or implicit)
  567. % unknown dependence on cfrmcrd!*, result is nil.
  568. if lpow x = 1 then cfrmconstant numr lc x
  569. else cfrmviolatesrsx x;
  570. symbolic procedure cfrmconstant x;
  571. % x:sf -> cfrmconstant:bool
  572. freeoffl(x,cfrmcrd!*);
  573. symbolic procedure freeoffl(x,v);
  574. % x:sf, v:list of kernel -> freeoffl:bool
  575. % freeofl for sf's
  576. null v or freeoff(x,car v) and freeoffl(x,cdr v);
  577. symbolic procedure freeoff(x,v);
  578. % x:sf, v:kernel -> freeoff:bool
  579. % freeof for sf's, using ndepends from EXCALC to handle indexed
  580. % forms properly
  581. if domainp x then t
  582. else if sfp mvar x then
  583. freeoff(mvar x,v) and freeoff(lc x,v) and freeoff(red x,v)
  584. else
  585. not ndepends(mvar x,v) and freeoff(lc x,v) and freeoff(red x,v);
  586. symbolic procedure cfrmviolatesrsx x;
  587. % x:pf -> cfrmviolatesrsx:bool
  588. % result is t if x = 0 annihilates at least one of cfrmrsx!*
  589. begin scalar rsx;
  590. rsx := cfrmrsx!*; x := {x};
  591. while rsx and xreduce(car rsx,x) do rsx := cdr rsx;
  592. return not null rsx; % to give true bool and make trace nicer
  593. end;
  594. endmodule;
  595. end;