ncfactor.red 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. module ncfactor; % factorization for non-commutative polynomials.
  2. % Author: H. Melenk, ZIB Berlin, J. Apel, University of Leipzig.
  3. % version 1.4: using the commutative factorizer as preprocessor.
  4. % Oct 2001: using "sove", hoping, that the user did not switch off 'varopt'.
  5. share nc_factor_time; % time limit in milliseconds.
  6. nc_factor_time:=0;
  7. algebraic operator cc!*;
  8. symbolic procedure nc_factorize u;
  9. begin scalar r,o,!*gsugar,comm,cr,cl;
  10. o:=apply1('torder,'(gradlex));
  11. nc!-gsetup();
  12. comm := nc_commfactors!* u;
  13. cl:=car comm; u:=cadr comm;cr:=caddr comm;
  14. if constant_exprp u then (if u neq 1 then cl:=u.cl)
  15. else
  16. r:=for each p in nc_factorize0(a2ncvdp u,nil,nil,nil,nil,nil)
  17. collect num vdp2a p;
  18. o:=apply1('torder,{o});
  19. return'list.append(cl,append(r,cr))end;
  20. symbolic operator nc_factorize;
  21. % copyd('nc_commfactors!*,'nc_commfactors);
  22. symbolic procedure nc_commfactors u;
  23. begin scalar o,!*gsugar,comm,cr,cl;
  24. o:=apply1('torder,'(gradlex));
  25. nc!-gsetup();
  26. comm:=nc_commfactors!* u;
  27. cl:=car comm;u:=cadr comm;cr:=caddr comm;
  28. o:=apply1('torder,{o});
  29. return{'list,'list.cl,u,'list.cr}end;
  30. symbolic operator nc_commfactors;
  31. symbolic procedure nc_commfactors!* u;
  32. (begin scalar f,ff,uu,comm,l,crl,cll,!*ncg!-right,w;
  33. uu:=sublis(ncpi!-names!*,numr simp u);
  34. comm:=(fctrf reorder uu) where ncmp!*=nil;
  35. if null cddr comm and cdadr comm=1 then
  36. <<if !*trnc then writepri("no commutative factors found",'only);
  37. go to no_comm>>;
  38. l:=for each f in cdr comm join
  39. for i:=1:cdr f collect reval prepf car f;
  40. if !*trnc then writepri("testing commutative factors:",'only);
  41. uu:=a2ncvdp u;
  42. while l do
  43. <<f:=car l;l:=cdr l;
  44. if !*trnc then writepri(mkquote f,'first);
  45. !*ncg!-right:=right;
  46. if vdpzero!? cdr(w:=nc!-qremf(uu,ff:=a2ncvdp f))then
  47. <<if !*trnc then writepri(nc_dir(),'last);cll:=append(cll,{f});uu:=car w>>
  48. else
  49. if vdpzero!? cdr<<!*ncg!-right:=not right;w:=nc!-qremf(uu,ff)>>
  50. then<<if !*trnc then writepri(nc_dir(),'last);crl:=f.crl;uu:=car w>>
  51. else if !*trnc then writepri(" -- discarded",'last)>>;
  52. if null crl and null cll then go to no_comm;
  53. u:=vdp2a uu;
  54. if !*trnc then
  55. <<writepri("remaining noncom part:",'first);writepri(mkquote u,'last)>>;
  56. no_comm:return {crl,u,cll};
  57. end)where right=!*ncg!-right;
  58. symbolic procedure nc_dir();if !*ncg!-right then " right" else " left";
  59. symbolic procedure oneside!-factor(w,m,all);
  60. % NOTE: we must perform a factorization based on left
  61. % division (m='l) for obtaining a right factor.
  62. begin scalar u,d,r,mx,o,!*gsugar;
  63. % preprocessing for psopfn.
  64. d:=r:=0;
  65. u:=reval car w;
  66. if cdr w then<<d:=reval car(w:=cdr w);if cdr w then r:=reval cadr w>>;
  67. % preparing for the altorithm.
  68. o:=apply1('torder,'(gradlex));
  69. nc!-gsetup();
  70. if r=0 or r='(list)then r:=nil else
  71. <<r:=cdr listeval(r,nil);
  72. r:=vdpevlmon a2vdp(if null cdr r then reval car r else
  73. 'times.for each y in r collect reval y)>>;
  74. d:=reval d;
  75. if d=0 then d:=1000 else if not fixp d then<<mx:=vdpevlmon a2vdp d;d:=1000>>;
  76. r:=nc_factorize0(a2ncvdp u,m,d,r,mx,all);
  77. o:=apply1('torder,{o});
  78. return for each w in r collect num vdp2a w end;
  79. put('left_factor,'psopfn,
  80. function (lambda(w);<<w:=oneside!-factor(w,'r,nil) or w;reval car w>>));
  81. put('left_factors,'psopfn,
  82. function (lambda(w);'list. oneside!-factor(w,'r,t)));
  83. put('right_factor,'psopfn,
  84. function (lambda(w);<<w:=oneside!-factor(w,'l,nil) or w;reval car w>>));
  85. put('right_factors,'psopfn,
  86. function (lambda(w);'list.oneside!-factor(w,'l,t)));
  87. algebraic procedure nc_factorize_all u;
  88. % Compute all possible factorizations based on successive
  89. % right factor extraction.
  90. begin scalar !*ncg!-right,d,f,w,wn,q,r,trnc,nc_factor_time!*;
  91. nc_factor_time!*:=lisp time();
  92. trnc:=lisp !*trnc;lisp(!*trnc:=nil);
  93. w:={{u}};r:={};lisp(!*ncg!-right:=nil);
  94. loop:if w={} then go to done;
  95. lisp(wn:='(list));
  96. for each c in w do
  97. <<lisp(q:= cadr c);
  98. f:=right_factors(q,{},{});
  99. if trnc then write "ncfctrall: Right factors of (",q,"): ",f;
  100. if f={} then r:=c.r;
  101. for each fc in f do
  102. <<d:=nc_divide(q,fc);
  103. if trnc then write "ncfctrall: Quotient (",q,") / (",fc,"): ",d;
  104. wn:=(first d.fc.rest c).wn>>>>;
  105. w:=wn; go to loop;
  106. done:lisp(!*trnc:=trnc);
  107. return r end;
  108. symbolic procedure nc_factorize0(u,m,d,rs,mx,all);
  109. <<if not numberp nc_factor_time!* then nc_factor_time!*:=time();
  110. nc_factorize1(u,m,d,rs,mx,all)>>where nc_factor_time!*=nc_factor_time!*;
  111. symbolic procedure nc_factorize1(u,m,d,rs,mx,all);
  112. % split all left(right) factor of u off.
  113. % u: polynomial,
  114. % m: mode: restriction for left or right factor:
  115. % d: maximum degree restriction,
  116. % r: variable set restriction (r is an exponent vector).
  117. % mx: maximum exponent for each variable (is an exponent vector).
  118. % all: true if we look for all right(left) factors.
  119. begin scalar ev,evl,evlx,f,ff,!*ncg!-right;
  120. nc_factorize_timecheck();
  121. mx:=if null mx then for each y in vdpvars!* collect 1000 else
  122. for each y in mx collect if y>0 then y else 1000;
  123. if !*trnc then<<prin2 "factorize ";vdpprint u>>;
  124. ev:=vdpevlmon u;
  125. if vevzero!? ev then return{u};
  126. d:=d or vevtdeg ev/2;
  127. evlx:=sort(nc_factorize1!-evl ev,function(lambda(x,y);vevcomp(x,y)<0));
  128. if m='r then go to r;
  129. % factors up to n
  130. evl:=evlx;
  131. while (null f or all) and evl and vevtdeg car evl<=d do
  132. <<if not vevzero!? car evl
  133. and car evl neq ev
  134. % testing support;
  135. and(null rs or vevmtest!?(car evl,rs))
  136. % testing maximal degrees;
  137. and vevmtest!?(mx,car evl)
  138. then f:=append(f,nc_factorize2(u,car evl,rs,mx,all));
  139. evl:=cdr evl>>;
  140. if f or m='l then go to c;
  141. % right factors up to tdg-n
  142. d:=vevtdeg ev -d;
  143. r:!*ncg!-right:=t;
  144. evl:=evlx;
  145. while (null f or all)and evl and vevtdeg car evl<=d do
  146. <<if not vevzero!? car evl
  147. and car evl neq ev
  148. % testing support;
  149. and(null rs or vevmtest!?(car evl,rs))
  150. % testing maximal degrees;
  151. and vevmtest!?(mx,car evl)
  152. then f:=append(f,nc_factorize2(u,car evl,rs,mx,all));
  153. evl:=cdr evl>>;
  154. c:if null f then return if m then nil else{u};
  155. if all then return f;
  156. % only one factor wanted?
  157. if m then return{cdr f};
  158. ff:=nc_factorize1(car f,nil,nil,nil,mx,all);
  159. return if !*ncg!-right then append({cdr f},ff)else append(ff,{cdr f})end;
  160. symbolic procedure nc_factorize1!-evl u;
  161. % Collect all monomials dividing u.
  162. if null u then'(nil) else
  163. (for i:=0:car u join
  164. for each e in w collect i.e)where w=nc_factorize1!-evl cdr u;
  165. algebraic operator ncc!@;
  166. symbolic procedure nc_factorize2(u,ev,rs,mx,all);
  167. begin scalar ar,p,q,vl,r,s,so,sol,w,y;integer n;
  168. scalar !*bcsubs2;
  169. nc_factorize_timecheck();
  170. p:=a2dip 0;
  171. if !*trnc then
  172. <<prin2 if !*ncg!-right then "right " else "left ";
  173. prin2 "Ansatz for leading term > ";
  174. vdpprin2 vdpfmon(a2bc 1,ev);
  175. prin2 " < time so far:";
  176. prin2 (time()-nc_factor_time!*);
  177. prin2t "ms">>;
  178. % establish formal Ansatz.
  179. for each e in nc_factorize2evl(ev,rs,mx) do
  180. <<q:={'ncc!@,n:=n+1};p:=dipsum(p,dipfmon(a2vbc q,e))>>;
  181. w:=p;
  182. while not dipzero!? w do<<vl:=bc2a diplbc w.vl;w:=dipmred w>>;
  183. vl:=reversip vl;
  184. p:=dip2vdp p;
  185. % prin2 "complete Ansatz:";vdpprint p;
  186. % pseudo division.
  187. r:=nc!-normalform(u,{p},nil,nil);
  188. nc_factorize_timecheck();
  189. while not vdpzero!? r do<<s:=vbc2a vdplbc r.s;r:=vdpred r>>;
  190. if !*trnc then
  191. <<prin2t "internal equation system:";writepri(mkquote('list.s),'only)>>;
  192. % solve system
  193. % 1. look for a free variable:
  194. %###### but that must be the leading variable!!!
  195. for each v in vl do if not smember(v,s) then so:=v;
  196. if !*trnc and so then<<prin2"free:";prin2t so>>;
  197. if so then sol:={(so.1).for each v in vl collect v.0};
  198. if null sol or all then sol:=append(sol,nc_factsolve(s,vl,all));
  199. if null sol then return nil;
  200. if !*trnc then
  201. <<prin2t "internal solutions:";
  202. for each s in so do
  203. <<for each q in s do
  204. <<writepri(mkquote car q,'first);
  205. writepri(mkquote " = ",nil);
  206. writepri(mkquote cdr q,'last)>>;
  207. prin2t "=====================================">>;
  208. % prin2 "check internal solution:";
  209. % for each e in s do writepri(mkquote aeval sublis(so,e),'only);
  210. >>;
  211. coll:nc_factorize_timecheck();
  212. so:=car sol;sol:=cdr sol;
  213. y:=dip2vdp dippolish dipsubf(so,vdppoly p);
  214. % leading term preserved?
  215. % if vdpevlmon y neq vdpevlmon p then
  216. % return nil;
  217. % prin2 "computed factor:";vdpprint y;
  218. if vevzero!? vdpevlmon y then
  219. if not all then return nil else
  220. if sol then go to coll else go to done_all;
  221. % turn on bcsubs2 if there is an algebraic number.
  222. if smemq('expt,y) or smemq('sqrt,y) or smemq('root_of,y) then !*bcsubs2:=t;
  223. w:=nc!-qremf(u,y);
  224. if not vdpzero!? cdr w then
  225. <<prin2 "division failure";
  226. vdpprint u;prin2t "/";
  227. vdpprint y;prin2 "=> ";vdpprint car w;
  228. prin2 "rem: ";vdpprint cdr w;
  229. rederr "noncom factorize">>;
  230. if !*trnc then
  231. <<terpri();prin2 "splitting into > ";
  232. vdpprin2 car w;prin2t " < and";prin2 " > ";
  233. vdpprin2 y;prin2t " <";terpri()>>;
  234. ar:=y.ar;
  235. if all then if sol then go to coll else go to done_all;
  236. done_one:return car w.y;
  237. done_all:return ar end;
  238. symbolic procedure nc_factsolve(s,vl,all);
  239. begin scalar v,sb,ns,so,soa,sol,nz,w,q,z,r,abort;
  240. % 1st phase: divide out leading term variable,
  241. % remove zero products, and terminate for explicitly
  242. % unsolvable system.
  243. v:=numr simp car vl;
  244. ns:=for each e in s collect numr simp e;
  245. % remove factors of leading coefficient,
  246. % remove trivial parts and propagate them into system.
  247. r:=t;
  248. while r do
  249. <<r:=nil; s:=ns; ns:=nil;
  250. for each e in s do if not abort then
  251. <<e:=absf numr subf(e,sb);
  252. while(q:=quotf(e,v))do e:=q;
  253. if null e then nil else
  254. if domainp e or not(mvar e member vl)then abort:=t else
  255. if null red e and domainp lc e then
  256. <<w:=mvar e;sb:=(w.0).sb;r:=t;vl:=delete(w,vl)>>
  257. else if not member(e,ns)then ns:=e.ns>>>>;
  258. if abort or null vl then return nil;
  259. nc_factorize_timecheck();
  260. % all equations solved, free variable(s) left
  261. if null ns and vl then
  262. <<sol:={for each x in vl collect x.1};go to done>>;
  263. % solve the system.
  264. s:=for each e in ns collect prepf e;
  265. if !*trnc then
  266. <<prin2 "solving ";
  267. prin2 length s;prin2 " polynomial equations for ";
  268. prin2 length vl;
  269. prin2t"variables";
  270. for each e in s do writepri(mkquote e,'only)>>;
  271. % modification HM 24.10.2001: introduction of the fluid variable
  272. % '*varoptt' and setting it 't' locally.
  273. w:=(cdr solveeval{'list.s,'list.vl} where dipvars!*=nil);
  274. % Select appropriate solution.
  275. loop:nc_factorize_timecheck();
  276. if null w then go to done;
  277. so:=cdr car w;w:=cdr w;soa:=nil;
  278. if smemq('i,so)and null !*complex then go to loop;
  279. % Insert values for non occurring variables.
  280. for each y in vl do if not smember(y,so)then<<soa:=(y.1).soa; nz:=t>>;
  281. for each y in so do
  282. <<z:=nc_factorize_unwrap(reval caddr y,soa);
  283. nz:=nz or z neq 0;
  284. soa:=(cadr y.z).soa>>;
  285. % don't accept solution with leading term 0.
  286. if not nz then go to loop;
  287. q:=assoc(car vl,soa);
  288. if null q or cdr q=0 then go to loop;
  289. % Make sure solutions are in lowest terms.
  290. soa:=for each j in soa collect(car j.sublis(soa,cdr j));
  291. sol:=soa.sol;
  292. if all then go to loop;
  293. done:sol:=for each s in sol collect append(sb,s);
  294. if !*trnc then
  295. <<prin2t "solutions:";
  296. for each w in sol do
  297. writepri(mkquote('list.
  298. for each s in w collect{'equal,car s,cdr s}),'only);
  299. prin2t "-------------------------">>;
  300. return sol end;
  301. symbolic procedure dipsubf(a,u);
  302. % construct polynomial u with coefficients from a.
  303. if dipzero!? u then nil else
  304. <<q:=if q then cdr q else diplbc u;
  305. if q neq 0 then dipmoncomp(a2bc q,dipevlmon u,r) else r>>
  306. where q=assoc(bc2a diplbc u,a),r=dipsubf(a,dipmred u);
  307. symbolic procedure dippolish p1;diprectoint(p1,diplcm p1);
  308. symbolic procedure nc_factorize_unwrap(u,s);
  309. if atom u then u else
  310. if eqcar(u,'arbcomplex)then 1 else
  311. (if q then cdr q else
  312. for each x in u collect nc_factorize_unwrap(x,s))where q=assoc(u,s);
  313. symbolic procedure nc_factorize2evl(ev,rs,mx);
  314. % make list of monomials below ev in gradlex ordering,
  315. % but only those which occur in rs (if that is non-nil)
  316. % and which have the maximal degress of mx.
  317. for each q in nc_factorize2!-evl1(min(evtdeg mx,evtdeg ev),length ev,rs)
  318. join if not vevcompless!?(ev,q) and vevmtest!?(mx,q)then{q};
  319. symbolic procedure nc_factorize2!-evl1(n,m,rs);
  320. % Collect all 'm' exponent vectors with total degree <='n'.
  321. if m=0 then'(nil)else
  322. for i:=0:(if null rs or car rs>0 then n else 0)join
  323. for each e in nc_factorize2!-evl1(n#-i,m#-1,if rs then cdr rs)
  324. collect i.e;
  325. symbolic procedure nc_factorize_timecheck();
  326. if fixp nc_factor_time and nc_factor_time>0 and
  327. (time() - nc_factor_time!*) > nc_factor_time
  328. then rederr "time overflow in noncom. factorization";
  329. endmodule;;end;