hilberts.red 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. module hilberts; % Hilbert series of a set of Monomials.
  2. % Author: Joachim Hollman, Royal Institute for Technology,
  3. % Stockholm, Sweden
  4. % email: <joachim@nada.kth.se>
  5. comment
  6. --------------------------------------------------------
  7. A very brief "description" of the method used.
  8. M=k[x,y,z]/(x^2*y,x*z^2,y^2)
  9. x.
  10. 0 --> ker(x.) --> M --> M --> M/x --> 0
  11. M/x = k[x,y,z]/(x^2*y,x*z^2,y^2,x) = k[x,y,z]/(x,y^2)
  12. ker(x.) = ((x) + (x^2*y,x*z^2,y^2))/(x^2*y,x*z^2,y^2) =
  13. = (x,y^2)/(x^2*y,x*z^2,y^2)
  14. Hilb(ker(x.)) = Hilb - Hilb
  15. (x,y^2) (x^2*y,x*z^2,y^2)
  16. = 1/(1-t)^3 - Hilb -
  17. k[x,y,z]/(x,y^2)
  18. - (1/(1-t)^3 - Hilb
  19. k[x,y,z]/(x^2*y,x*z^2,y^2)
  20. = Hilb -Hilb
  21. M k[x,y,z]/(x,y^2)
  22. If you only keep the numerator in Hilb = N(t)/(1-t)^3
  23. M
  24. then you get
  25. (1-t)N (t) = N (t) - t (N (t) - N (t) )
  26. I I+(x) I Ann(x) + I
  27. i.e.
  28. N (t) = N (t) + t N (t) (*)
  29. I I+(x) Ann(x) + I
  30. Where
  31. I = (x^2*y,x*z^2,y^2)
  32. I + (x) = (x,y^2)
  33. I + Ann(x) = (x*y,z^2,y^2)
  34. N (t) is the numerator polynomial in Hilb
  35. I k[x,y,z]/I
  36. Equation (*) is what we use to compute the numerator polynomial, i.e.
  37. we "divide out" one variable at a time until we reach a base case.
  38. (One is not limited to single variables but I don't know of any good
  39. strategy for selecting a monomial.)
  40. Usage: hilb({monomial_1,...,monomial_n} [,variable])
  41. ;
  42. fluid '(nvars!*);
  43. % ************** MACROS ETC. **************
  44. smacro procedure term(c,v,e);
  45. list('times,c,list('expt,v,e));
  46. % -------------- safety check --------------
  47. smacro procedure var!-p(m);
  48. and(m,atom(m),not(numberp(m)));
  49. smacro procedure check!-expt(m);
  50. and(eqcar(m,'expt),var!-p(cadr(m)),numberp(caddr(m)));
  51. smacro procedure check!-single!-var(m);
  52. if var!-p(m) then t
  53. else check!-expt(m);
  54. smacro procedure check!-mon(m);
  55. if check!-single!-var(m) then t
  56. else if eqcar(m,'times) then check!-times(cdr(m))
  57. else nil;
  58. smacro procedure check!-args(monl,var);
  59. and(listp monl,eqcar(monl,'list),var!-p(var), check!-monl(monl));
  60. symbolic procedure make!-vector (n,pat);
  61. begin scalar v;
  62. v:=mkvect n;
  63. for i:=1:n do putv(v,i,pat);
  64. return v;
  65. end;
  66. % -------------- monomials --------------
  67. smacro procedure alloc!-mon(n);
  68. make!-vector(n,0);
  69. smacro procedure get!-nth!-exp(mon,n);
  70. getv(mon,n);
  71. smacro procedure set!-nth!-exp(mon,n,d);
  72. putv(mon,n,d);
  73. smacro procedure get!-tdeg(mon);
  74. getv(mon,0);
  75. smacro procedure set!-tdeg(mon,d);
  76. putv(mon,0,d);
  77. % -------------- ideals --------------
  78. smacro procedure the!-empty!-ideal();
  79. list(nil,nil);
  80. smacro procedure get!-next!-mon(ideal);
  81. <<x:=caadr ideal;
  82. if cdadr ideal then ideal:=list(car ideal,cdadr ideal)
  83. else ideal:=the!-empty!-ideal();
  84. x>>;
  85. smacro procedure not!-empty!-ideal(ideal);
  86. cadr ideal;
  87. smacro procedure first!-mon(ideal);
  88. caadr ideal;
  89. smacro procedure append!-ideals(ideal1,ideal2);
  90. list(car ideal2,append(cadr ideal1,cadr ideal2));
  91. symbolic procedure insert!-var(var,ideal);
  92. % inserts variable var as last generator of ideal
  93. begin
  94. scalar last;
  95. last:=list(make!-one!-var!-mon(var));
  96. return(list(last,append(cadr ideal,last)));
  97. end;
  98. symbolic procedure add!-to!-ideal(mon,ideal);
  99. % add mon as generator to the ideal
  100. begin
  101. scalar last;
  102. last := list(mon);
  103. if ideal = the!-empty!-ideal() then
  104. rplaca(cdr(ideal),last)
  105. else
  106. rplacd(car(ideal),last);
  107. rplaca(ideal,last);
  108. end;
  109. % ************** END OF MACROS ETC. **************
  110. % ************** INTERFACE TO ALGEBRAIC MODE **************
  111. symbolic procedure HilbSerEval(u);
  112. begin
  113. scalar l,monl,var;
  114. l:=length(u);
  115. if l < 1 or l > 2 then
  116. rerror(groebnr2,17,
  117. "Usage: hilb({monomial_1,...,monomial_n} [,variable])")
  118. else if l = 1 then
  119. <<
  120. monl:= reval car u;
  121. var:= 'x;
  122. >>
  123. else
  124. <<
  125. monl:= reval car u;
  126. var:= reval cadr u;
  127. >>;
  128. monl := 'list . for each aa in (cdr monl) collect reval aa;
  129. if not check!-args(monl,var) then
  130. rerror(groebnr2,18,
  131. "Usage: hilb({monomial_1,...,monomial_n} [,variable])");
  132. % return(aeval
  133. % list('QUOTIENT,
  134. % coefflist2prefix(NPol(gltb2arrideal(monl)), var),
  135. % list('EXPT,list('PLUS,1,list('TIMES,-1,var)),
  136. % nvars!*)));
  137. return(aeval
  138. coefflist2prefix(NPol(gltb2arrideal(monl)), var));
  139. end;
  140. % define "hilb" to be the algebraic mode function
  141. put('hilb,'psopfn,'HilbSerEval);
  142. symbolic procedure check!-monl(monl);
  143. begin
  144. scalar flag,tmp;
  145. flag:=t;
  146. monl:=gltb!-fix(monl);
  147. while monl and flag do
  148. <<
  149. tmp:=car monl;
  150. flag:=check!-mon(tmp);
  151. monl:=cdr monl;
  152. >>;
  153. return(flag);
  154. end;
  155. symbolic procedure check!-times(m);
  156. begin
  157. scalar flag,tmp;
  158. flag:=t;
  159. while m and flag do
  160. <<
  161. tmp:= car m;
  162. flag:=check!-single!-var(tmp);
  163. m:=cdr m;
  164. >>;
  165. return(flag);
  166. end;
  167. symbolic procedure coefflist2prefix(cl,var);
  168. begin
  169. scalar i,poly;
  170. i:=0;
  171. for each c in cl do
  172. <<
  173. poly:= cons(term(c,var,i),poly);
  174. i:=i+1;
  175. >>;
  176. return (cons('plus,poly));
  177. end;
  178. symbolic procedure indets(l);
  179. % "indets" returns a list containing all the
  180. % indeterminates of l.
  181. % l is supposed to have a form similar to the variable
  182. % GLTB in the Groebner basis package.
  183. % (LIST (EXPT Z 2) (EXPT X 2) Y)
  184. begin
  185. scalar varlist;
  186. for each m in l do
  187. if m neq 'list then
  188. if atom(m) then varlist:=union(list(m),varlist)
  189. else if eqcar(m,'expt)
  190. then varlist:=union(list(cadr(m)),varlist)
  191. else varlist:=union(indets(cdr(m)),varlist);
  192. return(varlist);
  193. end;
  194. symbolic procedure build!-assoc(l);
  195. % Given a list of indeterminates (x1 x2 ...xn) we produce
  196. % an a-list of the form ((x1.1) (x2.2)... (xn.n))
  197. begin
  198. scalar i;
  199. i:=0;
  200. return(for each var in l collect progn(i:=i+1,cons(var,i)));
  201. end;
  202. symbolic procedure mons(l);
  203. % rewrite the leading monomials (i.e. GLTB).
  204. % the result is a list of monomials of the form:
  205. % (variable . exponent) or ((variable1 . exponent1) ...
  206. % (variablen . exponentn))
  207. %
  208. % mons('(LIST (EXPT Z 2) (EXPT X 2) (TIMES Y (EXPT X 3))));
  209. % (((Y . 1) (X . 3)) (X . 2) (Z . 2))
  210. begin
  211. scalar monlist;
  212. for each m in l do
  213. if m neq 'list then monlist:=
  214. if atom(m) then cons(cons(m,1),monlist)
  215. else if eqcar(m,'expt)
  216. then cons(cons(cadr(m),caddr(m)),monlist)
  217. else (for each x in cdr(m) collect mons!-aux(x)) . monlist;
  218. return(monlist);
  219. end;
  220. symbolic procedure mons!-aux(m);
  221. if atom(m) then cons(m,1)
  222. else if eqcar(m,'expt) then cons(cadr(m),caddr(m));
  223. symbolic procedure lmon2arrmon(m);
  224. % list-monomial to array-monomial
  225. % a list-monomial has the form: (variable_number . exponent)
  226. % or is a list with entries of this form.
  227. % "variable_number" is the number associated with the variable,
  228. % see build!-assoc()
  229. begin
  230. scalar tdeg,mon;
  231. mon:=alloc!-mon(nvars!*);
  232. tdeg:=0;
  233. if listp m then
  234. for each varnodotexp in m do
  235. <<
  236. set!-nth!-exp(mon,car varnodotexp, cdr varnodotexp);
  237. tdeg:=tdeg+cdr varnodotexp;
  238. >>
  239. else
  240. <<
  241. set!-nth!-exp(mon,car m, cdr m);
  242. tdeg:=tdeg+cdr m;
  243. >>;
  244. set!-tdeg(mon,tdeg);
  245. return(mon);
  246. end;
  247. symbolic procedure gltb!-fix(l);
  248. % sometimes GLTB has the form (list (list...))
  249. % instead of (list ...)
  250. if and(listp cadr l,caadr(l) = 'list) then cadr l else l;
  251. symbolic procedure ge(m1,m2);
  252. if get!-tdeg(m1) >= get!-tdeg(m2) then t else nil;
  253. symbolic procedure get!-end!-ptr(l);
  254. begin
  255. scalar ptr;
  256. while l do
  257. <<
  258. ptr:=l;
  259. l:=cdr l;
  260. >>;
  261. return(ptr);
  262. end;
  263. symbolic procedure gltb2arrideal(xgltb);
  264. % Convert the monomial ideal given by GLTB (in list form)
  265. % to a list of vectors where each vector represents a monomial.
  266. begin
  267. scalar l;
  268. l:=indets(gltb!-fix(xgltb));
  269. nvars!* := length(l);
  270. l:= sublis(build!-assoc(l),mons(gltb!-fix(xgltb)));
  271. l:=for each m in l collect lmon2arrmon(m);
  272. l:=sort(l,'ge);
  273. return(list(get!-end!-ptr(l),l));
  274. end;
  275. % ************** END OF INTERFACE TO ALGEBRAIC MODE **************
  276. %************** PROCEDURES **************
  277. symbolic procedure npol(ideal);
  278. % recursively computes the numerator of the Hilbert series
  279. begin
  280. scalar v,si;
  281. v:=next!-var(ideal);
  282. if not v then return(base!-case!-pol(ideal));
  283. si:=split!-ideal(ideal,v);
  284. return(shift!-add(npol(car si),npol(cadr si)));
  285. end;
  286. symbolic procedure divides!-by!-var(var,mon);
  287. begin
  288. scalar div;
  289. if get!-nth!-exp(mon,var) = 0 then return(nil);
  290. div:=alloc!-mon(nvars!*);
  291. for i:=1 : nvars!* do set!-nth!-exp(div,i,get!-nth!-exp(mon,i));
  292. set!-nth!-exp(div,var,get!-nth!-exp(mon,var)-1);
  293. set!-tdeg(div,get!-tdeg(mon)-1);
  294. return(div);
  295. end;
  296. symbolic procedure divides(m1,m2);
  297. % does m1 divide m2?
  298. % m1 and m2 are monomials
  299. % result: either nil (when m1 does not divide m2) or m2/m1
  300. begin
  301. scalar m,d,i;
  302. i:=1;
  303. m:=alloc!-mon(nvars!*);
  304. set!-tdeg(m,d:=get!-tdeg(m2)-get!-tdeg(m1));
  305. while d >= 0 and i <= nvars!* do
  306. <<
  307. set!-nth!-exp(m,i,d:=get!-nth!-exp(m2,i) - get!-nth!-exp(m1,i));
  308. i:= i+1;
  309. >>;
  310. if d < 0 then
  311. return (nil)
  312. else
  313. return(m);
  314. end;
  315. symbolic procedure shift!-add(p1,p2);
  316. % p1+z*p2
  317. % p1 and p2 are polynomials (nonempty coefficient lists)
  318. begin
  319. scalar p,pptr;
  320. pptr:=p:=cons(car p1,nil);
  321. p1:=cdr p1;
  322. while p1 and p2 do
  323. <<
  324. rplacd(pptr,cons(car p1 + car p2,nil));
  325. p1:=cdr p1;
  326. p2:=cdr p2;
  327. pptr:=cdr pptr;
  328. >>;
  329. if p1 then
  330. rplacd(pptr,p1)
  331. else
  332. rplacd(pptr,p2);
  333. return(p);
  334. end;
  335. symbolic procedure rem!-mult(ipp1,ipp2);
  336. % the union of two ideals with redundancy of generators eliminated
  337. begin
  338. scalar fmon,inew,isearch,primeflag,x;
  339. % fix; x is used in the macro...
  340. inew := the!-empty!-ideal();
  341. while not!-empty!-ideal(ipp1) and not!-empty!-ideal(ipp2) do
  342. begin
  343. if get!-tdeg(first!-mon(ipp2)) < get!-tdeg(first!-mon (ipp1))
  344. then <<
  345. fmon:=get!-next!-mon(ipp1);
  346. isearch:=ipp2;
  347. >>
  348. else
  349. <<
  350. fmon:=get!-next!-mon(ipp2);
  351. isearch:=ipp1;
  352. >>;
  353. primeflag:=T;
  354. while primeflag and not!-empty!-ideal(isearch) do
  355. if divides(get!-next!-mon(isearch),fmon) then primeflag:=nil;
  356. if primeflag then add!-to!-ideal(fmon,inew);
  357. end;
  358. if not!-empty!-ideal(ipp1) then return(append!-ideals(inew,ipp1))
  359. else return(append!-ideals(inew,ipp2));
  360. end;
  361. symbolic procedure next!-var(ideal);
  362. % extracts a variable in the ideal suitable for division
  363. begin
  364. scalar x,m,var;
  365. repeat
  366. << m:=get!-next!-mon(ideal);
  367. var:=get!-var!-if!-not!-single(m);
  368. >> until var or ideal = the!-empty!-ideal();
  369. return(var);
  370. end;
  371. symbolic procedure get!-var!-if!-not!-single(mon);
  372. % returns nil if the monomial is in a single variable,
  373. % otherwise the index of the second variable of the monomial
  374. begin
  375. scalar i,foundvarflag,exp;
  376. i := 0;
  377. foundvarflag:=nil;
  378. while not foundvarflag do
  379. <<
  380. i:=i+1;
  381. exp:=get!-nth!-exp(mon,i);
  382. if exp > 0 then foundvarflag:=T;
  383. >>;
  384. foundvarflag:=nil;
  385. while i < nvars!* and not foundvarflag do
  386. <<
  387. i:=i+1;
  388. exp:=get!-nth!-exp(mon,i);
  389. if exp > 0 then foundvarflag:=T;
  390. >>;
  391. if foundvarflag then return(i)
  392. else return(nil);
  393. end;
  394. symbolic procedure make!-one!-var!-mon(vindex);
  395. % returns the monomial consisting of the single variable vindex
  396. begin
  397. scalar mon;
  398. mon := alloc!-mon(nvars!*);
  399. for i := 1:nvars!* do set!-nth!-exp(mon,i,0);
  400. set!-nth!-exp(mon,vindex,1);
  401. set!-tdeg(mon,1);
  402. return(mon);
  403. end;
  404. symbolic procedure split!-ideal(ideal,var);
  405. % splits the ideal into two simpler ideals
  406. begin
  407. scalar div,ideal1,ideal2,m,x;
  408. ideal1 := the!-empty!-ideal();
  409. ideal2 := the!-empty!-ideal();
  410. while not!-empty!-ideal(ideal) do
  411. <<
  412. m:=get!-next!-mon(ideal);
  413. if div:=divides!-by!-var(var,m) then
  414. add!-to!-ideal(div,ideal2)
  415. else
  416. add!-to!-ideal(m,ideal1);
  417. >>;
  418. ideal2:=rem!-mult(ideal1,ideal2);
  419. ideal1:=insert!-var(var,ideal1);
  420. return(list(ideal1,ideal2));
  421. end;
  422. symbolic procedure base!-case!-pol(ideal);
  423. % in the base case every monomial is of the form Xi^ei
  424. % result : the numerator polynomial of the Hilbert series
  425. % i.e. (1-z^e1)*(1-z^e2)*...
  426. begin
  427. scalar p,degsofar,e,tdeg;
  428. tdeg:=0;
  429. for each mon in cadr ideal do tdeg:=tdeg + get!-tdeg(mon);
  430. p:=make!-vector(tdeg,0);
  431. putv(p,0,1);
  432. degsofar:=0;
  433. for each mon in cadr ideal do
  434. <<
  435. e:=get!-tdeg(mon);
  436. for j:= degsofar step -1 until 0 do
  437. putv(p,j+e,getv(p,j+e)-getv(p,j));
  438. degsofar:=degsofar+e;
  439. >>;
  440. return(vector2list(p));
  441. end;
  442. symbolic procedure vector2list v;
  443. % Convert a vector v to a list. No type checking is done.
  444. begin scalar u;
  445. for i:= upbv v step -1 until 0 do u := getv(v,i) . u;
  446. return u;
  447. end;
  448. endmodule;
  449. end;