lf.red 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. module lf;
  2. COMMENT
  3. ###############################
  4. #### ####
  5. #### DUAL BASES APPROACH ####
  6. #### ####
  7. ###############################
  8. The general idea for the dual bases approach :
  9. Given a finite collection of linear functionals L : M=S^n --> k^N, we
  10. want to compute a basis for Ker L as in
  11. [MMM] : Marinari et al., Proc. ISSAC'91, p. 55-63
  12. This generalizes the approach from
  13. [FGLM] : Faugere, Gianni, Lazard, Mora: JSC 16 (1993), 329 - 344.
  14. L is given through values on the generators,
  15. {[e_i,L(e_i)], i=1 ... n},
  16. and an evaluation function evlf([p,L(p)],x), that evaluates L(p*x)
  17. from L(p) for p in M and the variable x .
  18. We process a queue of elements of M with increasing leading terms,
  19. evaluating each time L on them. Different to [MMM] the queue is stored
  20. as
  21. {[p,L(p)], l=list of potential multipliers, lt(p*(x:=first l))}
  22. for the potential evaluation of L(p*x) and sorted by the term order
  23. wrt. the third slot. Since we proceed by increasing lt, Gaussian
  24. elimination doesn't disturb leading terms. Hence leading terms of the
  25. result are linearly independent and thus the result a Groebner basis.
  26. This approach applies to very different problem settings, see
  27. [MMM]. CALI manages this variety of applications through different
  28. values on the property list of 'cali.
  29. There are general entries with information about the computation
  30. 'varlessp -- a sort predicate for lf variable names
  31. 'evlf -- the evaluation function
  32. and special entries, depending on the problem to be solved.
  33. [p,L(p)] is handled as data type lf (linear functions)
  34. < dpoly > . < list of (var. name).(base coeff.) >
  35. The lf cdr list is the list of the values of the linear functionals
  36. on the given car lf dpoly.
  37. evlf(lf,var) evaluates lf*var and returns a new lf.
  38. There are the following order functions :
  39. varlessp = (cdr lf) variable order
  40. lf!=sort = lf queue order
  41. term order = (car lf) dpoly order
  42. end comment;
  43. symbolic procedure lf_dualbasis(q);
  44. % q is the dual generator set given as a list of input lf values.
  45. % l is the queue to be processed and updated, g the list of kernel
  46. % elements, produced so far.
  47. begin scalar g,l,q,r,p,v,u,vars,rf,q1;
  48. v:=ring_names cali!=basering;
  49. if null(rf:=get('cali,'evlf)) then
  50. rederr"For DUALBASIS no evaluation function defined";
  51. for each ev1 in q do
  52. if lf!=zero ev1 then
  53. << if cali_trace()>20 then dp_print2 car q; g:=car q . g >>
  54. else
  55. << vars:=v; q1:=ev1.q1;
  56. while vars do
  57. << l:={ev1, vars, mo_from_a car vars}.l; vars:=cdr vars >>;
  58. >>;
  59. q:=sort(q1,function lf!=less); % The reducer in triangular order.
  60. l:=sort(l, function lf!=sort); % The queue in increasing term order.
  61. while l do
  62. << r:=car l; l:=cdr l;
  63. vars:=second r; r:=car r;
  64. p:=lf!=reduce(apply2(rf,r,car vars),q);
  65. if lf!=zero p then
  66. << if cali_trace()>20 then dp_print2 car p; g:=car p . g >>
  67. else
  68. << q:=merge({p},q,function lf!=less);
  69. u:=nil; v:=dp_lmon car p;
  70. while vars do
  71. << u:={p,vars,mo_sum(v,mo_from_a car vars)}.u;
  72. vars:=cdr vars
  73. >>;
  74. l:=merge(sort(u,function lf!=sort),l,function lf!=sort);
  75. >>;
  76. >>;
  77. g:=bas_renumber bas_zerodelete for each x in g collect bas_make(0,x);
  78. return interreduce!* groeb_mingb dpmat_make(length g,0,g,nil,t);
  79. end;
  80. symbolic procedure lf!=sort(a,b);
  81. % Term order on the third slot. Niermann proposes another order here.
  82. mo_compare(third a,third b)=-1;
  83. symbolic procedure lf_dualhbasis(q,s);
  84. % The homogenized version.
  85. % s is the length of the dual homogenized basis.
  86. % For modules with column degrees not yet correct.
  87. begin scalar a,d,g,l,l1,r,p,v,u,vars,rf,q1;
  88. v:=ring_names cali!=basering; d:=0;
  89. if null(rf:=get('cali,'evlf)) then
  90. rederr"For DUALHBASIS no evaluation function defined";
  91. for each ev1 in q do
  92. if lf!=zero ev1 then
  93. << if cali_trace()>20 then dp_print2 car q; g:=car q . g >>
  94. else
  95. << vars:=v; q1:=ev1.q1;
  96. while vars do
  97. << l:={ev1, vars, mo_from_a car vars}.l; vars:=cdr vars >>;
  98. >>;
  99. q:=sort(q1,function lf!=less); % The reducer in triangular order.
  100. l1:=sort(l,function lf!=sort); % The queue in increasing term order.
  101. repeat
  102. << % Initialize the computation of the next degree.
  103. l:=l1; q:=l1:=nil; d:=d+1;
  104. while l do
  105. << r:=car l; l:=cdr l;
  106. vars:=second r; r:=car r;
  107. p:=lf!=reduce(apply2(rf,r,car vars),q);
  108. if lf!=zero p then
  109. << if cali_trace()>20 then dp_print2 car p;
  110. g:=bas_make(0,car p) . g
  111. >>
  112. else
  113. << q:=merge({p},q,function lf!=less);
  114. u:=nil; v:=dp_lmon car p;
  115. while vars do
  116. << u:={p,vars,mo_sum(v,mo_from_a car vars)}.u;
  117. vars:=cdr vars
  118. >>;
  119. l1:=merge(sort(u,function lf!=sort),l1,function lf!=sort);
  120. >>;
  121. g:=bas_renumber bas_zerodelete g;
  122. a:=dpmat_make(length g,0,g,nil,t);
  123. >>;
  124. >>
  125. until (d>=s) or ((dim!* a = 1) and (length q = s));
  126. return interreduce!* groeb_mingb a;
  127. end;
  128. symbolic procedure lf!=compact u;
  129. % Sort the cdr of the lf u and remove zeroes.
  130. sort(for each x in u join if not bc_zero!? cdr x then {x},
  131. function (lambda(x,y);
  132. apply2(get('cali,'varlessp),car x,car y)));
  133. symbolic procedure lf!=zero l; null cdr l;
  134. symbolic procedure lf!=sum(a,b);
  135. dp_sum(car a,car b) . lf!=sum1(cdr a,cdr b);
  136. symbolic procedure lf!=times_bc(z,a);
  137. dp_times_bc(z,car a) . lf!=times_bc1(z,cdr a);
  138. symbolic procedure lf!=times_bc1(z,a);
  139. if bc_zero!? z then nil
  140. else for each x in a collect car x . bc_prod(z,cdr x);
  141. symbolic procedure lf!=sum1(a,b);
  142. if null a then b
  143. else if null b then a
  144. else if equal(caar a,caar b) then
  145. (if bc_zero!? u then lf!=sum1(cdr a,cdr b)
  146. else (caar a . u).lf!=sum1(cdr a,cdr b))
  147. where u:=bc_sum(cdar a,cdar b)
  148. else if apply2(get('cali,'varlessp),caar a,caar b) then
  149. (car a).lf!=sum1(cdr a,b)
  150. else (car b).lf!=sum1(a,cdr b);
  151. symbolic procedure lf!=simp a;
  152. if null cdr a then car dp_simp car a. nil
  153. else begin scalar z;
  154. if (z:=bc_inv lf!=lc a) then return lf!=times_bc(z,a);
  155. z:=dp_content car a;
  156. for each x in cdr a do z:=bc_gcd(z,cdr x);
  157. return (for each x in car a collect car x . bc_quot(cdr x,z)) .
  158. (for each x in cdr a collect car x . bc_quot(cdr x,z));
  159. end;
  160. % Leading variable and coefficient assuming cdr a nonempty :
  161. symbolic procedure lf!=lvar a; caadr a;
  162. symbolic procedure lf!=lc a; cdadr a;
  163. symbolic procedure lf!=less(a,b);
  164. apply2(get('cali,'varlessp),lf!=lvar a,lf!=lvar b);
  165. symbolic procedure lf!=reduce(a,l);
  166. if lf!=zero a or null l or lf!=less(a, car l) then a
  167. else if (lf!=lvar a = lf!=lvar car l) then
  168. begin scalar z,z1,z2,b;
  169. b:=car l; z1:=bc_neg lf!=lc a; z2:=lf!=lc b;
  170. if !*bcsimp then
  171. << if (z:=bc_inv z1) then <<z1:=bc_fi 1; z2:=bc_prod(z2,z)>>
  172. else
  173. << z:=bc_gcd(z1,z2);
  174. z1:=bc_quot(z1,z);
  175. z2:=bc_quot(z2,z);
  176. >>;
  177. >>;
  178. a:=lf!=sum(lf!=times_bc(z2,a),lf!=times_bc(z1,b));
  179. if !*bcsimp then a:=lf!=simp a;
  180. return lf!=reduce(a,cdr l)
  181. end
  182. else lf!=reduce(a,cdr l);
  183. % ------------ Application to point evaluation -------------------
  184. % cali has additionally 'varnames and 'sublist.
  185. % It works also for symbolic matrix entries.
  186. symbolic operator affine_points;
  187. symbolic procedure affine_points m;
  188. % m is an algebraic matrix, which rows are the coordinates of points
  189. % in the affine space with Spec = the current ring.
  190. if !*mode='algebraic then dpmat_2a affine_points!* reval m
  191. else affine_points!* m;
  192. symbolic procedure affine_points!* m;
  193. begin scalar names;
  194. if length(names:=ring_names cali!=basering) neq length cadr m then
  195. typerr(m,"coordinate matrix");
  196. put('cali,'sublist,for each x in cdr m collect pair(names,x));
  197. put('cali,'varnames, names:=for each x in cdr m collect gensym());
  198. put('cali,'varlessp,'lf!=pointvarlessp);
  199. put('cali,'evlf,'lf!=pointevlf);
  200. return lf_dualbasis(
  201. { dp_fi 1 . lf!=compact
  202. for each x in names collect (x . bc_fi 1) });
  203. end;
  204. symbolic operator proj_points;
  205. symbolic procedure proj_points m;
  206. % m is an algebraic matrix, which rows are the coordinates of _points
  207. % in the projective space with Proj = the current ring.
  208. if !*mode='algebraic then dpmat_2a proj_points!* reval m
  209. else proj_points!* m;
  210. symbolic procedure proj_points!* m;
  211. % Points must be different in proj. space. This will not be tested !
  212. begin scalar u,names;
  213. if length(names:=ring_names cali!=basering) neq length cadr m then
  214. typerr(m,"coordinate matrix");
  215. put('cali,'sublist,u:=for each x in cdr m collect pair(names,x));
  216. put('cali,'varnames, names:=for each x in cdr m collect gensym());
  217. put('cali,'varlessp,'lf!=pointvarlessp);
  218. put('cali,'evlf,'lf!=pointevlf);
  219. return lf_dualhbasis(
  220. { dp_fi 1 . lf!=compact
  221. for each x in names collect (x . bc_fi 1) },
  222. length u);
  223. end;
  224. symbolic procedure lf!=pointevlf(p,x);
  225. begin scalar q; p:=dp_2a (q:=dp_prod(car p,dp_from_a x));
  226. return q . lf!=compact
  227. pair(get('cali,'varnames),
  228. for each x in get('cali,'sublist) collect
  229. bc_from_a subeval1(x,p));
  230. end;
  231. symbolic procedure lf!=pointvarlessp(x,y); not ordp(x,y);
  232. % ------ Application to Groebner bases under term order change ----
  233. % ----- The version with borderbases :
  234. % cali has additionally 'oldborderbasis.
  235. put('change_termorder,'psopfn,'lf!=change_termorder);
  236. symbolic procedure lf!=change_termorder m;
  237. begin scalar c,r;
  238. if (length m neq 2) then
  239. rederr "Syntax : Change_TermOrder(dpmat identifier, new ring)";
  240. if (not idp car m) then typerr(m,"dpmat identifier");
  241. r:=ring_from_a reval second m;
  242. m:=car m; intf_get m;
  243. if not (c:=get(m,'gbasis)) then
  244. put(m,'gbasis,c:=gbasis!* get(m,'basis));
  245. c:=change_termorder!*(c,r);
  246. return dpmat_2a c;
  247. end;
  248. symbolic procedure change_termorder!*(m,r);
  249. % m must be a zerodimensional gbasis with respect to the current term
  250. % order, r the new ring (with the same var. names).
  251. % This procedure sets r as the current ring and computes a gbasis
  252. % of m with respect to r.
  253. if (dpmat_cols m neq 0) or not dimzerop!* m then
  254. rederr("CHANGE_TERMORDER only for zerodimensional ideals")
  255. else if ring_names r neq ring_names cali!=basering then
  256. typerr(makelist ring_names r,"variable names")
  257. else begin scalar b;
  258. if cali_trace()>20 then print"Precomputing the border basis";
  259. b:=for each x in odim_borderbasis m collect bas_dpoly x;
  260. if cali_trace()>20 then print"Borderbasis computed";
  261. setring!* r;
  262. put('cali,'oldborderbasis, for each x in b collect
  263. {mo_neworder dp_lmon x, dp_lc x,dp_neg dp_neworder cdr x});
  264. put('cali,'varlessp,'lf!=tovarlessp);
  265. put('cali,'evlf,'lf!=toevlf);
  266. return lf_dualbasis({dp_fi 1 . dp_fi 1})
  267. end;
  268. symbolic procedure lf!=tovarlessp(a,b); mo_compare(a,b)=1;
  269. symbolic procedure lf!=toevlf(p,x);
  270. begin scalar a,b,c,d;
  271. x:=mo_from_a x; c:=get('cali,'oldborderbasis);
  272. p:=dp_times_mo(x,car p).dp_times_mo(x,cdr p);
  273. % Now reduce the terms in cdr p with the old borderbasis.
  274. for each x in cdr p do
  275. % b is the list of terms already in canonical form,
  276. % a is a list of (can. form) . (bc_quot), where bc_quot is
  277. % a pair of bc's interpreted as a rational multiplier
  278. % for the can. form.
  279. if d:=assoc(car x,c) then a:=(third d . (cdr x . second d)) .a
  280. else b:=x.b;
  281. a:=for each x in a collect car x . lf!=reducebc cdr x;
  282. d:=lf!=denom a;
  283. a:=for each x in a collect
  284. dp_times_bc(bc_quot(bc_prod(d,cadr x),cddr x),car x);
  285. b:=dp_times_bc(d,reversip b);
  286. for each x in a do b:=dp_sum(x,b);
  287. return dp_times_bc(d,car p) . b;
  288. end;
  289. symbolic procedure lf!=reducebc z;
  290. begin scalar g;
  291. if g:=bc_inv cdr z then return bc_prod(g,car z) . bc_fi 1;
  292. g:=bc_gcd(car z,cdr z);
  293. return bc_quot(car z,g) . bc_quot(cdr z,g);
  294. end;
  295. symbolic procedure lf!=denom a;
  296. if null a then bc_fi 1
  297. else if null cdr a then cddar a
  298. else bc_lcm(cddar a,lf!=denom cdr a);
  299. % ----- The version without borderbases :
  300. % cali has additionally 'oldring, 'oldbasis
  301. put('change_termorder1,'psopfn,'lf!=change_termorder1);
  302. symbolic procedure lf!=change_termorder1 m;
  303. begin scalar c,r;
  304. if (length m neq 2) then
  305. rederr "Syntax : Change_TermOrder1(dpmat identifier, new ring)";
  306. if (not idp car m) then typerr(m,"dpmat identifier");
  307. r:=ring_from_a reval second m;
  308. m:=car m; intf_get m;
  309. if not (c:=get(m,'gbasis)) then
  310. put(m,'gbasis,c:=gbasis!* get(m,'basis));
  311. c:=change_termorder1!*(c,r);
  312. return dpmat_2a c;
  313. end;
  314. symbolic procedure change_termorder1!*(m,r);
  315. % m must be a zerodimensional gbasis with respect to the current term
  316. % order, r the new ring (with the same var. names).
  317. % This procedure sets r as the current ring and computes a gbasis
  318. % of m with respect to r.
  319. if (dpmat_cols m neq 0) or not dimzerop!* m then
  320. rederr("change_termorder1 only for zerodimensional ideals")
  321. else if ring_names r neq ring_names cali!=basering then
  322. typerr(makelist ring_names r,"variable names")
  323. else begin scalar c,d;
  324. c:=if dpmat_cols m=0 then {dp_fi 1}
  325. else for k:=1:dpmat_cols m collect dp_from_ei k;
  326. put('cali,'varlessp,'lf!=tovarlessp1);
  327. put('cali,'evlf,'lf!=toevlf1);
  328. put('cali,'oldring,cali!=basering);
  329. put('cali,'oldbasis,m);
  330. setring!* r;
  331. d:=if dpmat_cols m=0 then {dp_fi 1}
  332. else for k:=1:dpmat_cols m collect dp_from_ei k;
  333. return lf_dualbasis(pair(d,c))
  334. end;
  335. symbolic procedure lf!=tovarlessp1(a,b);
  336. (mo_compare(a,b)=1)
  337. where cali!=basering=get('cali,'oldring);
  338. symbolic procedure lf!=toevlf1(p,x);
  339. % p = ( a . b ). Returns (c*a*x,d) where (d.c)=mod!*(b*x,m).
  340. begin scalar a,b,c,d;
  341. a:=dp_times_mo(mo_from_a x,car p);
  342. (<< b:=dp_times_mo(mo_from_a x,cdr p);
  343. b:=mod!*(b,get('cali,'oldbasis));
  344. d:=car b; c:=dp_lc cdr b;
  345. >>) where cali!=basering:=get('cali,'oldring);
  346. return dp_times_bc(c,a) . d;
  347. end;
  348. endmodule; % lf
  349. end;