Annotation of OpenXM/src/Ti/gset.c, Revision 1.1.1.1
1.1 maekawa 1: /*
2: ** gset.c Birk Huber, 4/99
3: ** -- definitions and basic operations on gsets
4: **
5: **
6: ** TiGERS, Toric Groebner Basis Enumeration by Reverse Search
7: ** copyright (c) 1999 Birk Huber
8: **
9: */
10: #include<stdio.h>
11: #include<stdlib.h>
12: #include "utils.h"
13: #include "gset.h"
14: #include "matrices.h"
15: #include "Rsimp.h"
16: extern int NT;
17:
18: /* uncomment the following to cause use sainity checks (not fully tested)*/
19: /*
20: #define GTEST 0
21: #include "gtesting.h"
22: */
23:
24: /*
25: ** create an empty gset, initialize all its pointers to null.
26: */
27: gset gset_new(){
28: gset g=0;
29: if ((g=(gset)malloc(sizeof(struct gset_tag)))==0){
30: fprintf(stderr,"gset_new(): malloc failed\n");
31: return 0;
32: }
33: gset_first(g)=0;
34: gset_cache_vtx(g)=0;
35: gset_cache_edge(g)=0;
36: return g;
37: }
38:
39: /*
40: ** delete a gset and all binomials in it.
41: */
42: void gset_free(gset g){
43: binomial b;
44: while((b=gset_first(g))!=0){
45: gset_first(g)=binomial_next(b);
46: binomial_free(b);
47: }
48: free((void *)g);
49: }
50:
51:
52: /*
53: ** read a gset from an input stream
54: ** (return TRUE if gset read in )
55: */
56: int gset_read(FILE *is,gset g){
57: char c;
58: binomial b;
59:
60: eatwhite(is);
61: c=getc(is);
62: if (c!='{') return FALSE;
63: c=',';
64: while(c==','){
65: b=binomial_new();
66: binomial_read(is,b);
67: gset_insert(g,b);
68: eatwhite(is);
69: c=getc(is);
70: }
71: if (c!='}'){
72: fprintf(stderr,"gset_read(): gset should end with a '}'\n");
73: return FALSE;
74: }
75: ungetc(c,is);
76: return TRUE;
77: }
78:
79: /*
80: ** Display a gset
81: */
82: void gset_print(FILE *of,gset g){
83: binomial b;
84:
85: if (NT == 1) {
86: fprintf(of,"[");
87: for(b=g->bottom;b!=0;b=b->next){
88: binomial_print(of,b);
89: if (b->next!=0) fprintf(of," , ");
90: }
91: fprintf(of,"]");
92: }else{
93: fprintf(of,"{");
94: for(b=g->bottom;b!=0;b=b->next){
95: binomial_print(of,b);
96: if (b->next!=0) fprintf(of,", ");
97: }
98: fprintf(of,"}");
99: }
100: }
101:
102: /*
103: ** Display a gsets initial ideal
104: */
105: void gset_init_print(FILE *of,gset g){
106: binomial b;
107: fprintf(of,"{");
108: for(b=g->bottom;b!=0;b=b->next){
109: print_monomial(of,binomial_lead(b));
110: if (b->next!=0) fprintf(of,", ");
111: }
112: fprintf(of,"}");
113: }
114:
115: /*
116: ** Display a facet binomials
117: */
118: void gset_facet_print(FILE *of,gset g){
119: binomial b;
120: int tog=0;
121: fprintf(of,"{");
122: for(b=g->bottom;b!=0;b=b->next){
123: if (b->ff==FACET){
124: if (tog==1) fprintf(of,",");
125: else tog=1;
126: binomial_print(of,b);
127: }
128: }
129: fprintf(of,"}");
130: }
131:
132: /*
133: ** place binomial in gset in decreasing lexicographic order.
134: ** (using binomial_compair(,) to determine reletive order or
135: ** binomials)
136: */
137: void gset_insert(gset g, binomial b){
138: binomial t1,t2;
139: if (gset_first(g)==0 || binomial_compair(gset_first(g),b)==FALSE){
140: binomial_next(b)=gset_first(g);
141: gset_first(g)=b;
142: }
143: else{
144: t1=gset_first(g);
145: while(t1!=0){
146: t2=binomial_next(t1);
147: if (t2==0 || binomial_compair(t2,b)==FALSE){
148: binomial_next(t1)=b;
149: binomial_next(b)=t2;
150: break;
151: }
152: t1=t2;
153: }
154: }
155: }
156:
157: /*
158: ** return first facet binomial which is mis-marked
159: */
160: binomial gset_downedge(gset g){
161: binomial ptr=0;
162: for(ptr=gset_first(g);ptr!=0;ptr=binomial_next(ptr)){
163: if (binomial_ordered(ptr)==FALSE && gset_isfacet(g,ptr)==TRUE)break;
164: }
165: return ptr;
166: }
167:
168:
169: /*
170: ++void bmprint(FILE *of,binomial B, binomial M):
171: ++ simple output function for a generating set consisting of a binomial and
172: ++ a list of monomials --- usefull mainly for debugging. -- gset output
173: ++ routing may be modified in such a way as to use code which could double
174: ++ for this purpose.
175: ++
176: */
177: void bmprint(FILE *of,binomial B, binomial M){
178: fprintf(of,"{ ");
179: if (B!=0) binomial_print(of,B);
180: while(M!=0){
181: fprintf(of,",");
182: binomial_print(of,M);
183: M=binomial_next(M);
184: }
185: fprintf(of,"}\n");
186: }
187:
188: /*
189: **binomial bmleadreduce(binomial m1, binomial B, binomial mlist):
190: ** "lift" monomial m1 to a binomial using bmlist B,mlist.
191: */
192: binomial bmleadreduce(binomial m1, binomial B, binomial mlist){
193: binomial res,ptr;
194: /* case 1: the binomial is used in the decomp:*/
195: if (monomial_divides(binomial_lead(B),binomial_lead(m1))==TRUE){
196: res=binomial_new();
197: binomial_copy(B,res);
198: binomial_bumpto(res,m1);
199:
200: /* now reduce by lt(b) as many times as possible */
201: while(monomial_divides(binomial_lead(B),binomial_trail(res))==TRUE){
202: reducetrail(res,B);
203: }
204:
205: /* now find a monomial deviding whats left and reduce by it*/
206: for(ptr=mlist;ptr!=0;ptr=ptr->next){
207: if (monomial_divides(binomial_lead(ptr),binomial_trail(res))==TRUE){
208: reducetrail(res,ptr);
209: return res;
210: }
211: }
212: }
213: else { /* case 2 -- our monomial is a multiple of some monomial*/
214: for(ptr=mlist;ptr!=0;ptr=ptr->next){
215: if (monomial_divides(binomial_lead(ptr),binomial_lead(m1))==TRUE){
216: res=binomial_new();
217: binomial_copy(ptr,res);
218: binomial_set(res);
219: binomial_bumpto(res,m1);
220: return res;
221: }
222: }
223: }
224: fprintf(stderr, "Warning BMreduce does not get to zero\n");
225: }
226:
227:
228:
229: /*
230: ++ binomial find_divisor(binomial S,binomial L):
231: ++ search list starting at L for a monomial dividing S
232: ++ return this binomial or zero if no such binomial exists on list.
233: ++
234: */
235: binomial find_divisor(binomial S,binomial L){
236: binomial ptr;
237: for(ptr=L;ptr!=0;ptr=ptr->next){
238: if(ptr!=S&&monomial_divides(binomial_lead(ptr),binomial_lead(S))==TRUE){
239: break;
240: }
241: }
242: return ptr;
243: }
244:
245:
246: /*
247: ++ void remove_multiples(binomial S, binomial *L):
248: ++ Pass through list starting at *L, removing all multiples of *S
249: ++ encountered (except S if it is on the list).
250: ++
251: */
252: void remove_multiples(binomial S, binomial *L){
253: binomial tlist=*L,ptr;
254: *L=0;
255: while(tlist!=0){
256: ptr=tlist; tlist=tlist->next; ptr->next=0; /* pop tlist*/
257: if (S==ptr || monomial_divides(binomial_lead(S),binomial_lead(ptr))==FALSE) {
258: ptr->next=*L; /* push L */
259: *L=ptr;
260: }
261: else binomial_free(ptr);
262: }
263: }
264:
265: /*
266: ** void bmrgb(binomial B, binomial *ms):
267: ** transform a marked binomial and a list of monomials into the
268: ** reduced grobner basis for the ideal the generate.
269: **
270: */
271: void bmrgb(binomial B, binomial *ms){
272: int i,jk;
273: binomial DL,SL,tlist,S,tmp,ptr;
274: int szero;
275:
276: DL=*ms;
277: SL=0;
278:
279: while(DL!=0){
280: tmp=DL; DL=DL->next; /* pop DL */
281: tmp->next=SL; SL=tmp; /* push SL */
282:
283: /* calculate normal form of S pair with respect to {B}*/
284: S=monomial_spair(B,binomial_lead(tmp));
285:
286: /* check if anything on DL or on SL divides S*/
287: if (find_divisor(S,SL)!=0||find_divisor(S,DL)!=0)binomial_free(S);
288: else {
289: remove_multiples(S,&SL); /* remove any multiples of S from SL*/
290: remove_multiples(S,&DL); /* remove any multiples of S from DL*/
291: S->next=DL; DL=S; /* finally push S onto DL */
292: }
293: }
294:
295: remove_multiples(B,&SL); /* now that we have a grobner basis
296: we can remove multiples of lead(B)
297: from the monomial list */
298:
299: // replace list bottom pointer
300: *ms=SL;
301:
302: }
303:
304: /*
305: ** gset gset_flip(gset g1, binomial b):
306: ** Take a gset and one of its facet binomials and produce the new gset
307: ** corresponding to the grobner cone which shares the given facet binomial.
308: **
309: */
310: gset gset_flip(gset g1, binomial b){
311: binomial old=0,new=0,tmp,ptr,B,Bold;
312: gset gres=0, gtest=0;
313:
314: /* sainity check -- remove eventually*/
315: #ifdef GTEST
316: if (lp_isfacet(g1,b)!=FACET){
317: fprintf(stdout,"WARNING flip asked to flip non-binomial\n");
318: }
319: #endif
320:
321: /* copy all binomials of g's list ecept b to old and new lists*/
322: for(ptr=gset_first(g1);ptr!=0;ptr=ptr->next){
323: if (ptr!=b){
324: tmp=binomial_new();
325: binomial_copy(ptr,tmp);
326: monomial_set(tmp);
327: binomial_next(tmp)=new;
328: new=tmp;
329: tmp=binomial_new();
330: binomial_copy(ptr,tmp);
331: monomial_set(tmp);
332: binomial_next(tmp)=old;
333: old=tmp;
334: }
335: }
336: Bold=binomial_new();
337: binomial_copy(b,Bold);
338:
339: /* make fliped copy of b*/
340: B=binomial_new();
341: binomial_copy(b,B);
342: binomial_flip(B);
343:
344: /* calculate the reduced GB of the binomial b and the monomials in M */
345: bmrgb(B,&new);
346:
347: /* create new gset and insert flipped copy of b */
348: gres=gset_new();
349: gset_insert(gres,B);
350:
351: /* do lifting of elements in mlist and add them to new gset*/
352: while((tmp=new)!=0){
353: new=new->next;
354: ptr=bmleadreduce(tmp,Bold,old);
355: gset_insert(gres,ptr);
356: binomial_free(tmp);
357: }
358:
359: /* sainity check -- remove eventually*/
360: #ifdef GTEST
361: if (gset_is_gb(gres)==FALSE){
362: fprintf(stderr,"flipped failed to find grobner basis \n");
363: fprintf(stderr,"g1=");gset_print(stderr,g1);fprintf(stderr,"\n");
364: fprintf(stderr,"b=");binomial_print(stderr,b);fprintf(stderr,"\n");
365: exit(1);
366: }
367: #endif
368:
369: binomial_free(Bold);
370: while(old!=0){
371: ptr=old;
372: old=old->next;
373: binomial_free(ptr);
374: }
375:
376: gset_autoreduce(gres);
377:
378: /* sainity check -- remove eventually */
379: #ifdef GTEST
380: if ( gset_is_reduced(gres)==FALSE){
381: fprintf(stderr,"flipped failed to find reduced grobner basis \n");
382: fprintf(stderr,"g1=");gset_print(stderr,g1);fprintf(stderr,"\n");
383: fprintf(stderr,"b=");binomial_print(stderr,b);fprintf(stderr,"\n");
384: exit(1);
385: }
386: #endif
387:
388: return gres;
389: }
390:
391:
392: /*
393: ** void gset_autoreduce(gset g):
394: ** autoreduce g according to its marking
395: */
396: void gset_autoreduce(gset g){
397: binomial b1,b2;
398: int changed;
399:
400: /* First remove redundant elements from the grobner basis*/
401: while(find_divisor(gset_first(g),gset_first(g))!=0){
402: gset_first(g)=(b1=gset_first(g))->next;
403: binomial_free(b1);
404: }
405: b1=gset_first(g);
406: while(b1!=0 && binomial_next(b1)!=0){
407: if (find_divisor(binomial_next(b1),gset_first(g))!=0) {
408: b2=binomial_next(b1);
409: binomial_next(b1)=binomial_next(b2);
410: binomial_free(b2);
411: }
412: else b1=binomial_next(b1);
413: }
414:
415: /* now reduce trailing terms */
416: b1=gset_first(g);
417: while(b1!=0){
418: changed=1;
419: while(changed==1){
420: changed=0;
421: b2=gset_first(g);
422: while(b2!=0){
423: if (b2!=b1 &&
424: monomial_divides(binomial_lead(b2),binomial_trail(b1))==TRUE){
425: reducetrail(b1,b2);
426: changed=1;
427: }
428: b2=binomial_next(b2);
429: }
430: }
431: b1=binomial_next(b1);
432: }
433:
434: /* now reinsert terms to ensure list is in order */
435: b1=gset_first(g);
436: gset_first(g)=0;
437: while((b2=b1)!=0) {
438: b1=binomial_next(b1);
439: gset_insert(g,b2);
440: }
441:
442: }
443:
444: /*
445: ** void gset_rgb(gset g, int (*comp)(monomial,monomial))
446: ** Use buchberger's algorithm to transform g into groebner basis
447: ** wrt the term order implemented by comp
448: */
449: #define ordered(b) ((comp(binomial_lead(b),binomial_trail(b))>=0)?TRUE:FALSE)
450: int changed;
451: void gset_rgb(gset g, int (*comp)(monomial,monomial)){
452: void process_pair(binomial,binomial,binomial,binomial,binomial *,int (*comp)());
453: binomial ptr,b,DL=0,SL=0,NL=0;
454: int passes=0;
455:
456: do{
457: DL=0; SL=0; NL=0;
458: changed=FALSE;
459:
460: /* reorient g and put binomial list on DL*/
461: ptr=gset_first(g);
462: while((b=ptr)!=0){
463: ptr=binomial_next(ptr);
464: if (ordered(b)==FALSE) binomial_flip(b);
465: binomial_next(b)=DL;
466: DL=b;
467: }
468:
469: /* */
470: while(DL!=0){
471: NL=0;
472: b=DL; DL=DL->next; /* pop DL*/
473: b->next=SL; SL=b; /* push ptr onto SL*/
474: for(ptr=SL;ptr!=0;ptr=binomial_next(ptr)) process_pair(b,ptr,DL,SL,&NL,comp);
475: for(ptr=DL;ptr!=0;ptr=binomial_next(ptr)){
476: process_pair(b,ptr,DL,SL,&NL,comp);
477: if (binomial_next(ptr)==0){ binomial_next(ptr)=NL; NL=0;}
478: }
479: }
480:
481: /* reinsert elements in SL into gset */
482: ptr=SL;
483: gset_first(g)=0;
484: while(ptr!=0){
485: ptr=(b=ptr)->next;
486: gset_insert(g,b);
487: }
488:
489:
490: gset_autoreduce(g);
491:
492: if (passes>1){
493: if (changed==TRUE ){fprintf(stderr,"looping pass (%d)\n",passes);}
494: else {fprintf(stderr,"stopping after %d passes\n",passes);}
495: }
496: passes++;
497: }while(changed==TRUE);
498:
499: }
500:
501: /*
502: -- process_pair(b1,b2,DL,SL,NL,comp):
503: -- process spair defined by binomials b1 and b2.
504: -- taking spair wrt union of DL SL and *NL lists
505: -- if non-zero add result to NL list.
506: -- comp is a monomial compairison function used throuout.
507: */
508: void process_pair(binomial b1,binomial b2,binomial DL,binomial SL,binomial *NL,
509: int (*comp)(monomial,monomial)){
510: binomial S,ptr,find_divisor(binomial,binomial);
511: int i,tmp;
512:
513: /* test is lead terms are rel prime [buchberger's first criterion]*/
514: if (monomial_rel_prime(binomial_lead(b1),binomial_lead(b2))==TRUE)return;
515:
516: /* buchberger's second criterion ?*/
517:
518:
519: S=binomial_new();
520: binomial_copy(b1,S);
521: if (binomial_spair(S,b2)==TRUE){
522: binomial_free(S);
523: return;
524: }
525: if (ordered(S)==FALSE) binomial_flip(S);
526: while(((ptr=find_divisor(S,DL))!=0)||
527: ((ptr=find_divisor(S,SL))!=0)||
528: ((ptr=find_divisor(S,*NL))!=0)){
529: if (binomial_spair(S,ptr)==TRUE){
530: binomial_free(S);
531: return;
532: }
533: if (ordered(S)==FALSE) binomial_flip(S);
534: }
535: changed=TRUE;
536: binomial_next(S)=*NL;
537: *NL=S;
538: }
539:
540: /*
541: ** void gset_setfacets(gset g):
542: ** Use repeated calls to gset_isfacet to ensure that all facet flags
543: ** are set.
544: ** Also sets nfacets, nelts and deg counters (these contain garbage except
545: ** right after a call to set facets).
546: **
547: ** NOTE 4/20 the deg counter was just added and the code to load it is
548: ** cludged in here -- logically it should be part of the
549: ** binomial.c file -- for now it is here.
550: */
551: #define max(a,b) (((a)>(b))?(a):(b))
552: void gset_setfacets(gset g){
553: binomial b;
554: monomial ml,mt;
555: int i,d=0,dl,dt;
556: gset_nfacets(g)=0;
557: gset_nelts(g)=0;
558: for(b=gset_first(g);b!=0;b=binomial_next(b)){
559: if (gset_isfacet(g,b)==FACET) gset_nfacets(g)++;
560: gset_nelts(g)++;
561: ml=binomial_lead(b); dl=0;
562: mt=binomial_trail(b); dt=0;
563: for(i=0;i<ring_N;i++){ dl+=ml[i]; dt+=mt[i];}
564: d=max(d,max(dl,dt));
565: }
566: gset_deg(g)=d;
567: }
568:
569: /*
570: ** int gset_isfacet(gset g,binomial b):
571: ** check whether b is known to be a facet or not. if not call lp_isfacet()
572: ** to use a linear program to set b's facet flag.
573: **
574: */
575: int lptest=1; /* 1 test only LP, 2 test only flipability, 3 test both */
576: int gset_isflippable(gset g,binomial b);
577: int gset_isfacet(gset g,binomial b){
578: int rval=UNKNOWN;
579: rval=b->ff;
580: if (rval!=FACET && rval!=NONFACET){
581: switch(lptest){
582: case 1: rval=(b->ff=lp_isfacet(g,b));
583: break;
584: case 2: if (gset_isflippable(g,b)==FALSE) rval=(b->ff=NONFACET);
585: else rval=(b->ff=FACET);
586: break;
587: case 3: if (gset_isflippable(g,b)==FALSE) rval=(b->ff=NONFACET);
588: else rval=(b->ff=lp_isfacet(g,b));
589: break;
590: default: fprintf(stderr,"Warning lptest has invalid value in gset_isflippable()\n");
591: exit(4);
592: }
593: }
594: return rval;
595: }
596:
597: /*
598: **
599: */
600: int gset_isflippable(gset g,binomial b){
601: int ctg=0,ctn=1,val=TRUE;
602: binomial new=0,tmp,ptrg,ptrn,btmp;
603: /* copy all binomials of g's list ecept b to old and new lists*/
604: for(ptrg=gset_first(g);ptrg!=0;ptrg=ptrg->next){
605: ctg++;
606: if (ptrg!=b){
607: tmp=binomial_new();
608: binomial_copy(ptrg,tmp);
609: monomial_set(tmp);
610: binomial_next(tmp)=new;
611: new=tmp;
612: }
613: }
614: btmp=binomial_new();
615: binomial_copy(b,btmp);
616:
617:
618: /* calculate the reduced GB of the binomial b and the monomials in M */
619: bmrgb(btmp,&new);
620:
621: /* test if new and old have same leading terms */
622: for(ptrn=new ;ptrn!=0;ptrn=ptrn->next) ctn++;
623: if (ptrn!=ptrg) val=FALSE; /* initial ideals have diferent numbers of generators */
624: else {
625: for(ptrn=new;ptrn!=0;ptrn=ptrn->next){
626: for(ptrg=gset_first(g);ptrg!=0;ptrg=ptrg->next){
627: if (monomial_equal(binomial_lead(ptrn),binomial_lead(ptrg))==TRUE)break;
628: }
629: if (ptrg==0)break; /* no match found */
630: }
631: if (ptrn!=0)val=FALSE; /* not all terms had matches found */
632: }
633:
634: /* clean up */
635: binomial_free(btmp);
636: while(new!=0){
637: ptrn=new;
638: new=new->next;
639: binomial_free(ptrn);
640: }
641:
642: return val;
643: }
644:
645: /*
646: ** int lp_isfacet(gset g,binomial b):
647: ** set up and run linear program to set b's facet flag.
648: **
649: */
650: int lp_isfacet(gset g,binomial b){
651: binomial ptr;
652: int D=ring_N,M=0;
653: int idx=0,i;
654: double dtmp0,dtmp;
655:
656: /* need cheeper way to determine the size of g */
657: for(ptr=gset_first(g);ptr!=0;ptr=binomial_next(ptr)){
658: if (ptr->ff!=NONFACET)M++;
659: }
660:
661: /* make sure the lp structures have enough space for the program*/
662: LP_get_space(M,D+2*M);
663:
664: /* Set up linear program. */
665: ptr=gset_first(g);
666: idx=0;
667: while(ptr!=0){
668: if (ptr->ff!=NONFACET){
669: for(i=0;i<D;i++){ /* make sure supports of trail and lead disjoint? */
670: LP_A(idx,i)=binomial_lead(ptr)[i]-binomial_trail(ptr)[i];
671: }
672: for(i=0;i<M;i++){
673: LP_A(idx,D+i)=0;
674: LP_A(idx,D+M+i)=0;
675: }
676: if (ptr==b) {for(i=0;i<D;i++) LP_A(idx,i)*=-1;}
677: LP_A(idx,D+M+idx)=1;
678: LP_A(idx,D+idx)=-1;
679: LP_B[idx]=1;
680: idx++;
681: }
682: ptr=ptr->next;
683: }
684: for(i=0;i<D+M;i++){
685: LP_C[i]=0;
686: LP_X[i]=0;
687: LP_NonBasis[i]=i;
688: }
689: for(i=0;i<M;i++){
690: LP_Basis[i]=D+M+i;
691: LP_X[D+M+i]=1;
692: LP_C[D+M+i]=1;
693: }
694:
695: /* Run simplex algorithm */
696: Rsimp(LP_M,LP_N,LP_A,LP_B,LP_C,LP_X,LP_Basis,LP_NonBasis,
697: LP_R,LP_Q,LP_t1,LP_t2);
698:
699: /* use results to determine if the b is a facet*/
700: b->ff=FACET;
701: for(i=0;i<M;i++) if (LP_Basis[i]>=M+D) {b->ff=NONFACET;break;}
702:
703: return b->ff;
704: }
705:
706:
707:
708:
709:
710:
711:
712:
713:
714:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>