[BACK]Return to distm.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / engine

Diff for /OpenXM_contrib2/asir2000/engine/distm.c between version 1.8 and 1.12

version 1.8, 2000/12/05 08:29:44 version 1.12, 2003/07/20 08:55:23
Line 45 
Line 45 
  * DEVELOPER SHALL HAVE NO LIABILITY IN CONNECTION WITH THE USE,   * DEVELOPER SHALL HAVE NO LIABILITY IN CONNECTION WITH THE USE,
  * PERFORMANCE OR NON-PERFORMANCE OF THE SOFTWARE.   * PERFORMANCE OR NON-PERFORMANCE OF THE SOFTWARE.
  *   *
  * $OpenXM: OpenXM_contrib2/asir2000/engine/distm.c,v 1.7 2000/12/05 06:59:16 noro Exp $   * $OpenXM: OpenXM_contrib2/asir2000/engine/distm.c,v 1.11 2003/07/18 10:13:13 noro Exp $
 */  */
 #include "ca.h"  #include "ca.h"
 #include "inline.h"  #include "inline.h"
Line 53 
Line 53 
 extern int (*cmpdl)();  extern int (*cmpdl)();
 extern int do_weyl;  extern int do_weyl;
   
 void comm_mulmd();  void ptomd(VL vl,int mod,VL dvl,P p,DP *pr)
 void weyl_mulmd();  
 void weyl_mulmdm();  
 void weyl_mulmmm();  
   
 void mulmdm_dup();  
 void comm_mulmd_dup();  
 void weyl_mulmd_dup();  
 void weyl_mulmdm_dup();  
 void weyl_mulmmm_dup();  
 void comm_mulmd_tab_destructive();  
 void adddl_dup();  
 void ptomd(vl,mod,dvl,p,pr)  
 VL vl,dvl;  
 int mod;  
 P p;  
 DP *pr;  
 {  {
         P t;          P t;
   
Line 77  DP *pr;
Line 61  DP *pr;
         mptomd(vl,mod,dvl,t,pr);          mptomd(vl,mod,dvl,t,pr);
 }  }
   
 void mptomd(vl,mod,dvl,p,pr)  void mptomd(VL vl,int mod,VL dvl,P p,DP *pr)
 VL vl,dvl;  
 int mod;  
 P p;  
 DP *pr;  
 {  {
         int n,i;          int n,i;
         VL tvl;          VL tvl;
Line 111  DP *pr;
Line 91  DP *pr;
                         } else {                          } else {
                                 for ( dc = DC(p), s = 0; dc; dc = NEXT(dc) ) {                                  for ( dc = DC(p), s = 0; dc; dc = NEXT(dc) ) {
                                         mptomd(vl,mod,dvl,COEF(dc),&t);                                          mptomd(vl,mod,dvl,COEF(dc),&t);
                                         NEWDL(d,n); d->td = QTOS(DEG(dc)); d->d[i] = d->td;                                          NEWDL(d,n); d->d[i] = QTOS(DEG(dc));
                                           d->td = MUL_WEIGHT(d->d[i],i);
                                         NEWMP(m); m->dl = d; C(m) = (P)ONEM; NEXT(m) = 0; MKDP(n,m,u);                                          NEWMP(m); m->dl = d; C(m) = (P)ONEM; NEXT(m) = 0; MKDP(n,m,u);
                                         comm_mulmd(vl,mod,t,u,&r); addmd(vl,mod,r,s,&t); s = t;                                          comm_mulmd(vl,mod,t,u,&r); addmd(vl,mod,r,s,&t); s = t;
                                 }                                  }
Line 121  DP *pr;
Line 102  DP *pr;
         }          }
 }  }
   
 void mdtop(vl,mod,dvl,p,pr)  void mdtop(VL vl,int mod,VL dvl,DP p,P *pr)
 VL vl,dvl;  
 int mod;  
 DP p;  
 P *pr;  
 {  {
         int n,i;          int n,i;
         DL d;          DL d;
Line 149  P *pr;
Line 126  P *pr;
         }          }
 }  }
   
 void addmd(vl,mod,p1,p2,pr)  void addmd(VL vl,int mod,DP p1,DP p2,DP *pr)
 VL vl;  
 int mod;  
 DP p1,p2,*pr;  
 {  {
         int n;          int n;
         MP m1,m2,mr,mr0;          MP m1,m2,mr,mr0;
Line 210  DP p1,p2,*pr;
Line 184  DP p1,p2,*pr;
         }          }
 }  }
   
 void submd(vl,mod,p1,p2,pr)  void submd(VL vl,int mod,DP p1,DP p2,DP *pr)
 VL vl;  
 int mod;  
 DP p1,p2,*pr;  
 {  {
         DP t;          DP t;
   
Line 224  DP p1,p2,*pr;
Line 195  DP p1,p2,*pr;
         }          }
 }  }
   
 void chsgnmd(mod,p,pr)  void chsgnmd(int mod,DP p,DP *pr)
 int mod;  
 DP p,*pr;  
 {  {
         MP m,mr,mr0;          MP m,mr,mr0;
   
Line 242  DP p,*pr;
Line 211  DP p,*pr;
         }          }
 }  }
   
 void mulmd(vl,mod,p1,p2,pr)  void mulmd(VL vl,int mod,DP p1,DP p2,DP *pr)
 VL vl;  
 int mod;  
 DP p1,p2,*pr;  
 {  {
         if ( !do_weyl )          if ( !do_weyl )
                 comm_mulmd(vl,mod,p1,p2,pr);                  comm_mulmd(vl,mod,p1,p2,pr);
Line 253  DP p1,p2,*pr;
Line 219  DP p1,p2,*pr;
                 weyl_mulmd(vl,mod,p1,p2,pr);                  weyl_mulmd(vl,mod,p1,p2,pr);
 }  }
   
 void comm_mulmd(vl,mod,p1,p2,pr)  void comm_mulmd(VL vl,int mod,DP p1,DP p2,DP *pr)
 VL vl;  
 int mod;  
 DP p1,p2,*pr;  
 {  {
         MP m;          MP m;
         DP s,t,u;          DP s,t,u;
Line 292  DP p1,p2,*pr;
Line 255  DP p1,p2,*pr;
         }          }
 }  }
   
 void weyl_mulmd(vl,mod,p1,p2,pr)  void weyl_mulmd(VL vl,int mod,DP p1,DP p2,DP *pr)
 VL vl;  
 int mod;  
 DP p1,p2,*pr;  
 {  {
         MP m;          MP m;
         DP s,t,u;          DP s,t,u;
         int i,l,l1;          int i,l;
         static MP *w;          static MP *w;
         static int wlen;          static int wlen;
   
Line 326  DP p1,p2,*pr;
Line 286  DP p1,p2,*pr;
         }          }
 }  }
   
 void mulmdm(vl,mod,p,m0,pr)  void mulmdm(VL vl,int mod,DP p,MP m0,DP *pr)
 VL vl;  
 int mod;  
 DP p;  
 MP m0;  
 DP *pr;  
 {  {
         MP m,mr,mr0;          MP m,mr,mr0;
         P c;          P c;
Line 358  DP *pr;
Line 313  DP *pr;
         }          }
 }  }
   
 void weyl_mulmdm(vl,mod,p,m0,pr)  void weyl_mulmdm(VL vl,int mod,DP p,MP m0,DP *pr)
 VL vl;  
 int mod;  
 DP p;  
 MP m0;  
 DP *pr;  
 {  {
         DP r,t,t1;          DP r,t,t1;
         MP m;          MP m;
Line 395  DP *pr;
Line 345  DP *pr;
   
 /* m0 = x0^d0*x1^d1*... * dx0^d(n/2)*dx1^d(n/2+1)*... */  /* m0 = x0^d0*x1^d1*... * dx0^d(n/2)*dx1^d(n/2+1)*... */
   
 void weyl_mulmmm(vl,mod,m0,m1,n,pr)  void weyl_mulmmm(VL vl,int mod,MP m0,MP m1,int n,DP *pr)
 VL vl;  
 int mod;  
 MP m0,m1;  
 int n;  
 DP *pr;  
 {  {
         MP m,mr,mr0;          MP mr,mr0;
         MQ mq;          MQ mq;
         DP r,t,t1;          DP r,t,t1;
         P c,c0,c1,cc;          P c,c0,c1;
         DL d,d0,d1;          DL d,d0,d1;
         int i,j,a,b,k,l,n2,s,min;          int i,j,a,b,k,l,n2,s,min;
         static int *tab;          static int *tab;
Line 430  DP *pr;
Line 375  DP *pr;
                 for ( i = 0; i < n2; i++ ) {                  for ( i = 0; i < n2; i++ ) {
                         a = d0->d[i]; b = d1->d[n2+i];                          a = d0->d[i]; b = d1->d[n2+i];
                         k = d0->d[n2+i]; l = d1->d[i];                          k = d0->d[n2+i]; l = d1->d[i];
   
                         /* degree of xi^a*(Di^k*xi^l)*Di^b */                          /* degree of xi^a*(Di^k*xi^l)*Di^b */
                         s = a+k+l+b;                          a += l;
                           b += k;
                           s = MUL_WEIGHT(a,i)+MUL_WEIGHT(b,n2+i);
   
                         /* compute xi^a*(Di^k*xi^l)*Di^b */                          /* compute xi^a*(Di^k*xi^l)*Di^b */
                         min = MIN(k,l);                          min = MIN(k,l);
   
Line 444  DP *pr;
Line 393  DP *pr;
                         if ( n & 1 )                          if ( n & 1 )
                                 for ( mr0 = 0, j = 0; j <= min; j++ ) {                                  for ( mr0 = 0, j = 0; j <= min; j++ ) {
                                         NEXTMP(mr0,mr); NEWDL(d,n);                                          NEXTMP(mr0,mr); NEWDL(d,n);
                                         d->d[i] = l-j+a; d->d[n2+i] = k-j+b;                                          d->d[i] = a-j; d->d[n2+i] = b-j;
                                         d->td = s;                                          d->td = s;
                                         d->d[n-1] = s-(d->d[i]+d->d[n2+i]);                                          d->d[n-1] = s-(MUL_WEIGHT(a-j,i)+MUL_WEIGHT(b-j,n2+i));
                                         STOMQ(tab[j],mq); mr->c = (P)mq; mr->dl = d;                                          STOMQ(tab[j],mq); mr->c = (P)mq; mr->dl = d;
                                 }                                  }
                         else                          else
                                 for ( mr0 = 0, s = 0, j = 0; j <= min; j++ ) {                                  for ( mr0 = 0, s = 0, j = 0; j <= min; j++ ) {
                                         NEXTMP(mr0,mr); NEWDL(d,n);                                          NEXTMP(mr0,mr); NEWDL(d,n);
                                         d->d[i] = l-j+a; d->d[n2+i] = k-j+b;                                          d->d[i] = a-j; d->d[n2+i] = b-j;
                                         d->td = d->d[i]+d->d[n2+i]; /* XXX */                                          d->td = MUL_WEIGHT(a-j,i)+MUL_WEIGHT(b-j,n2+i); /* XXX */
                                         s = MAX(s,d->td); /* XXX */                                          s = MAX(s,d->td); /* XXX */
                                         STOMQ(tab[j],mq); mr->c = (P)mq; mr->dl = d;                                          STOMQ(tab[j],mq); mr->c = (P)mq; mr->dl = d;
                                 }                                  }
Line 469  DP *pr;
Line 418  DP *pr;
         }          }
 }  }
   
 void mulmdc(vl,mod,p,c,pr)  void mulmdc(VL vl,int mod,DP p,P c,DP *pr)
 VL vl;  
 int mod;  
 DP p;  
 P c;  
 DP *pr;  
 {  {
         MP m,mr,mr0;          MP m,mr,mr0;
         int t;          int t;
Line 498  DP *pr;
Line 442  DP *pr;
         }          }
 }  }
   
 void divsmdc(vl,mod,p,c,pr)  void divsmdc(VL vl,int mod,DP p,P c,DP *pr)
 VL vl;  
 int mod;  
 DP p;  
 P c;  
 DP *pr;  
 {  {
         MP m,mr,mr0;          MP m,mr,mr0;
   
Line 521  DP *pr;
Line 460  DP *pr;
         }          }
 }  }
   
 void _dtop_mod(vl,dvl,p,pr)  void _dtop_mod(VL vl,VL dvl,DP p,P *pr)
 VL vl,dvl;  
 DP p;  
 P *pr;  
 {  {
         int n,i;          int n,i;
         DL d;          DL d;
Line 549  P *pr;
Line 485  P *pr;
         }          }
 }  }
   
 void _dp_mod(p,mod,subst,rp)  void _dp_mod(DP p,int mod,NODE subst,DP *rp)
 DP p;  
 int mod;  
 NODE subst;  
 DP *rp;  
 {  {
         MP m,mr,mr0;          MP m,mr,mr0;
         P t,s;          P t,s;
Line 579  DP *rp;
Line 511  DP *rp;
         }          }
 }  }
   
 void _dp_monic(p,mod,rp)  void _dp_monic(DP p,int mod,DP *rp)
 DP p;  
 int mod;  
 DP *rp;  
 {  {
         MP m,mr,mr0;          MP m,mr,mr0;
         int c,c1;          int c,c1;
         NODE tn;  
   
         if ( !p )          if ( !p )
                 *rp = 0;                  *rp = 0;
Line 600  DP *rp;
Line 528  DP *rp;
         }          }
 }  }
   
 void _printdp(d)  void _printdp(DP d)
 DP d;  
 {  {
         int n,i;          int n,i;
         MP m;          MP m;
Line 623  DP d;
Line 550  DP d;
   
 /* merge p1 and p2 into pr */  /* merge p1 and p2 into pr */
   
 void addmd_destructive(mod,p1,p2,pr)  void addmd_destructive(int mod,DP p1,DP p2,DP *pr)
 int mod;  
 DP p1,p2,*pr;  
 {  {
         int n;          int n;
         MP m1,m2,mr,mr0,s;          MP m1,m2,mr,mr0,s;
Line 676  DP p1,p2,*pr;
Line 601  DP p1,p2,*pr;
         }          }
 }  }
   
 void mulmd_dup(mod,p1,p2,pr)  void mulmd_dup(int mod,DP p1,DP p2,DP *pr)
 int mod;  
 DP p1,p2,*pr;  
 {  {
         if ( !do_weyl )          if ( !do_weyl )
                 comm_mulmd_dup(mod,p1,p2,pr);                  comm_mulmd_dup(mod,p1,p2,pr);
Line 686  DP p1,p2,*pr;
Line 609  DP p1,p2,*pr;
                 weyl_mulmd_dup(mod,p1,p2,pr);                  weyl_mulmd_dup(mod,p1,p2,pr);
 }  }
   
 void comm_mulmd_dup(mod,p1,p2,pr)  void comm_mulmd_dup(int mod,DP p1,DP p2,DP *pr)
 int mod;  
 DP p1,p2,*pr;  
 {  {
         MP m;          MP m;
         DP s,t,u;          DP s,t,u;
Line 720  DP p1,p2,*pr;
Line 641  DP p1,p2,*pr;
         }          }
 }  }
   
 void weyl_mulmd_dup(mod,p1,p2,pr)  void weyl_mulmd_dup(int mod,DP p1,DP p2,DP *pr)
 int mod;  
 DP p1,p2,*pr;  
 {  {
         MP m;          MP m;
         DP s,t,u;          DP s,t,u;
         int i,l,l1;          int i,l;
         static MP *w;          static MP *w;
         static int wlen;          static int wlen;
   
Line 749  DP p1,p2,*pr;
Line 668  DP p1,p2,*pr;
         }          }
 }  }
   
 void mulmdm_dup(mod,p,m0,pr)  void mulmdm_dup(int mod,DP p,MP m0,DP *pr)
 int mod;  
 DP p;  
 MP m0;  
 DP *pr;  
 {  {
         MP m,mr,mr0;          MP m,mr,mr0;
         DL d,dt,dm;          DL d,dt,dm;
         int c,n,r,i;          int c,n,i;
         int *pt,*p1,*p2;          int *pt,*p1,*p2;
   
         if ( !p )          if ( !p )
Line 779  DP *pr;
Line 694  DP *pr;
         }          }
 }  }
   
 void weyl_mulmdm_dup(mod,m0,p,pr)  void weyl_mulmdm_dup(int mod,MP m0,DP p,DP *pr)
 int mod;  
 MP m0;  
 DP p;  
 DP *pr;  
 {  {
         DP r,t,t1;          DP r,t,t1;
         MP m;          MP m;
Line 841  DP *pr;
Line 752  DP *pr;
   
 /* m0 = x0^d0*x1^d1*... * dx0^d(n/2)*dx1^d(n/2+1)*... */  /* m0 = x0^d0*x1^d1*... * dx0^d(n/2)*dx1^d(n/2+1)*... */
   
 void weyl_mulmmm_dup(mod,m0,m1,n,rtab,rtablen)  void weyl_mulmmm_dup(int mod,MP m0,MP m1,int n,struct cdlm *rtab,int rtablen)
 int mod;  
 MP m0,m1;  
 int n;  
 struct cdlm *rtab;  
 int rtablen;  
 {  {
         MP m,mr,mr0;          int c,c0,c1;
         DP r,t,t1;  
         int c,c0,c1,cc;  
         DL d,d0,d1,dt;          DL d,d0,d1,dt;
         int i,j,a,b,k,l,n2,s,min,h,curlen;          int i,j,a,b,k,l,n2,s,min,curlen;
         struct cdlm *p;          struct cdlm *p;
         static int *ctab;          static int *ctab;
         static struct cdlm *tab;          static struct cdlm *tab;
Line 889  int rtablen;
Line 793  int rtablen;
         for ( i = 0; i < n2; i++ ) {          for ( i = 0; i < n2; i++ ) {
                 a = d0->d[i]; b = d1->d[n2+i];                  a = d0->d[i]; b = d1->d[n2+i];
                 k = d0->d[n2+i]; l = d1->d[i];                  k = d0->d[n2+i]; l = d1->d[i];
   
                   /* degree of xi^a*(Di^k*xi^l)*Di^b */
                   a += l;
                   b += k;
                   s = MUL_WEIGHT(a,i)+MUL_WEIGHT(b,n2+i);
   
                 if ( !k || !l ) {                  if ( !k || !l ) {
                         a += l;  
                         b += k;  
                         s = a+b;  
                         for ( j = 0, p = rtab; j < curlen; j++, p++ ) {                          for ( j = 0, p = rtab; j < curlen; j++, p++ ) {
                                 if ( p->c ) {                                  if ( p->c ) {
                                         dt = p->d;                                          dt = p->d;
Line 911  int rtablen;
Line 818  int rtablen;
                         tab = (struct cdlm *)MALLOC(tablen*sizeof(struct cdlm));                          tab = (struct cdlm *)MALLOC(tablen*sizeof(struct cdlm));
                         ctab = (int *)MALLOC(tablen*sizeof(int));                          ctab = (int *)MALLOC(tablen*sizeof(int));
                 }                  }
                 /* degree of xi^a*(Di^k*xi^l)*Di^b */  
                 s = a+k+l+b;  
                 /* compute xi^a*(Di^k*xi^l)*Di^b */                  /* compute xi^a*(Di^k*xi^l)*Di^b */
                 min = MIN(k,l);                  min = MIN(k,l);
                 mkwcm(k,l,mod,ctab);                  mkwcm(k,l,mod,ctab);
Line 921  int rtablen;
Line 826  int rtablen;
                 if ( n & 1 )                  if ( n & 1 )
                         for ( j = 0; j <= min; j++ ) {                          for ( j = 0; j <= min; j++ ) {
                                 NEWDL(d,n);                                  NEWDL(d,n);
                                 d->d[i] = l-j+a; d->d[n2+i] = k-j+b;                                  d->d[i] = a-j; d->d[n2+i] = b-j;
                                 d->td = s;                                  d->td = s;
                                 d->d[n-1] = s-(d->d[i]+d->d[n2+i]);                                  d->d[n-1] = s-(MUL_WEIGHT(a-j,i)+MUL_WEIGHT(b-j,n2+i));
                                 tab[j].d = d;                                  tab[j].d = d;
                                 tab[j].c = ctab[j];                                  tab[j].c = ctab[j];
                         }                          }
                 else                  else
                         for ( j = 0; j <= min; j++ ) {                          for ( j = 0; j <= min; j++ ) {
                                 NEWDL(d,n);                                  NEWDL(d,n);
                                 d->d[i] = l-j+a; d->d[n2+i] = k-j+b;                                  d->d[i] = a-j; d->d[n2+i] = b-j;
                                 d->td = d->d[i]+d->d[n2+i]; /* XXX */                                  d->td = MUL_WEIGHT(a-j,i)+MUL_WEIGHT(b-j,n2+i); /* XXX */
                                 tab[j].d = d;                                  tab[j].d = d;
                                 tab[j].c = ctab[j];                                  tab[j].c = ctab[j];
                         }                          }
Line 940  int rtablen;
Line 845  int rtablen;
         }          }
 }  }
   
 void comm_mulmd_tab_destructive(mod,nv,t,n,t1,n1)  void comm_mulmd_tab_destructive(int mod,int nv,struct cdlm *t,int n,struct cdlm *t1,int n1)
 int mod;  
 int nv;  
 struct cdlm *t;  
 int n;  
 struct cdlm *t1;  
 int n1;  
 {  {
         int i,j;          int i,j;
         struct cdlm *p;          struct cdlm *p;
Line 975  int n1;
Line 874  int n1;
                 }                  }
 }  }
   
 void adddl_dup(n,d1,d2,dr)  void adddl_dup(int n,DL d1,DL d2,DL *dr)
 int n;  
 DL d1,d2;  
 DL *dr;  
 {  {
         DL dt;          DL dt;
         int i;          int i;
Line 988  DL *dr;
Line 884  DL *dr;
         dt->td = d1->td + d2->td;          dt->td = d1->td + d2->td;
         for ( i = 0; i < n; i++ )          for ( i = 0; i < n; i++ )
                 dt->d[i] = d1->d[i]+d2->d[i];                  dt->d[i] = d1->d[i]+d2->d[i];
   }
   
   /* ------------------------------------------------------ */
   
   #if defined(__GNUC__)
   #define INLINE inline
   #elif defined(VISUAL)
   #define INLINE __inline
   #else
   #define INLINE
   #endif
   
   typedef struct oPGeoBucket {
           int m;
           struct oND *body[32];
   } *PGeoBucket;
   
   typedef struct oND {
           struct oNM *body;
           int nv;
           int sugar;
   } *ND;
   
   typedef struct oNM {
           struct oNM *next;
           int td;
           int c;
           unsigned int dl[1];
   } *NM;
   
   typedef struct oND_pairs {
           struct oND_pairs *next;
           int i1,i2;
           int td,sugar;
           unsigned int lcm[1];
   } *ND_pairs;
   
   static ND *nps;
   int nd_mod,nd_nvar;
   int is_rlex;
   int nd_epw,nd_bpe,nd_wpd;
   unsigned int nd_mask[32];
   unsigned int nd_mask0;
   NM _nm_free_list;
   ND _nd_free_list;
   ND_pairs _ndp_free_list;
   
   extern int Top,Reverse;
   int nd_psn,nd_pslen;
   
   void GC_gcollect();
   NODE append_one(NODE,int);
   
   #define HTD(d) ((d)->body->td)
   #define HDL(d) ((d)->body->dl)
   #define HC(d) ((d)->body->c)
   
   #define NEWND_pairs(m) if(!_ndp_free_list)_NDP_alloc(); (m)=_ndp_free_list; _ndp_free_list = NEXT(_ndp_free_list)
   #define NEWNM(m) if(!_nm_free_list)_NM_alloc(); (m)=_nm_free_list; _nm_free_list = NEXT(_nm_free_list)
   #define MKND(n,m,d) if(!_nd_free_list)_ND_alloc(); (d)=_nd_free_list; _nd_free_list = (ND)BDY(_nd_free_list); (d)->nv=(n); BDY(d)=(m)
   
   #define NEXTNM(r,c) \
   if(!(r)){NEWNM(r);(c)=(r);}else{NEWNM(NEXT(c));(c)=NEXT(c);}
   #define NEXTNM2(r,c,s) \
   if(!(r)){(c)=(r)=(s);}else{NEXT(c)=(s);(c)=(s);}
   #define FREENM(m) NEXT(m)=_nm_free_list; _nm_free_list=(m)
   #define FREEND(m) BDY(m)=(NM)_nd_free_list; _nd_free_list=(m)
   
   #define NEXTND_pairs(r,c) \
   if(!(r)){NEWND_pairs(r);(c)=(r);}else{NEWND_pairs(NEXT(c));(c)=NEXT(c);}
   
   ND_pairs crit_B( ND_pairs d, int s );
   void nd_gr(LIST f,LIST v,int m,struct order_spec *ord,LIST *rp);
   NODE nd_setup(NODE f);
   int nd_newps(ND a);
   ND_pairs nd_minp( ND_pairs d, ND_pairs *prest );
   NODE update_base(NODE nd,int ndp);
   static ND_pairs equivalent_pairs( ND_pairs d1, ND_pairs *prest );
   int crit_2( int dp1, int dp2 );
   ND_pairs crit_F( ND_pairs d1 );
   ND_pairs crit_M( ND_pairs d1 );
   ND_pairs nd_newpairs( NODE g, int t );
   ND_pairs update_pairs( ND_pairs d, NODE /* of index */ g, int t);
   NODE nd_gb(NODE f);
   void nd_free_private_storage();
   void _NM_alloc();
   void _ND_alloc();
   int ndl_td(unsigned int *d);
   ND nd_add(ND p1,ND p2);
   ND nd_mul_nm(ND p,NM m0);
   ND nd_sp(ND_pairs p);
   ND nd_reducer(ND p1,ND p2);
   ND nd_find_reducer(ND g);
   ND nd_nf(ND g,int full);
   void ndl_print(unsigned int *dl);
   void nd_print(ND p);
   void ndp_print(ND_pairs d);
   int nd_length(ND p);
   void nd_monic(ND p);
   
   void nd_free_private_storage()
   {
           _nd_free_list = 0;
           _nm_free_list = 0;
           GC_gcollect();
   }
   
   void _NM_alloc()
   {
           NM p;
           int i;
   
           for ( i = 0; i < 10240; i++ ) {
                   p = (NM)GC_malloc(sizeof(struct oNM)+(nd_wpd-1)*sizeof(unsigned int));
                   p->next = _nm_free_list; _nm_free_list = p;
           }
   }
   
   void _ND_alloc()
   {
           ND p;
           int i;
   
           for ( i = 0; i < 10240; i++ ) {
                   p = (ND)GC_malloc(sizeof(struct oND));
                   p->body = (NM)_nd_free_list; _nd_free_list = p;
           }
   }
   
   void _NDP_alloc()
   {
           ND_pairs p;
           int i;
   
           for ( i = 0; i < 10240; i++ ) {
                   p = (ND_pairs)GC_malloc(sizeof(struct oND_pairs)
                           +(nd_wpd-1)*sizeof(unsigned int));
                   p->next = _ndp_free_list; _ndp_free_list = p;
           }
   }
   
   INLINE nd_length(ND p)
   {
           NM m;
           int i;
   
           if ( !p )
                   return 0;
           else {
                   for ( i = 0, m = BDY(p); m; m = NEXT(m), i++ );
                   return i;
           }
   }
   
   INLINE int ndl_reducible(unsigned int *d1,unsigned int *d2)
   {
           unsigned int u1,u2;
           int i,j;
   
           switch ( nd_bpe ) {
                   case 4:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   if ( (u1&0xf0000000) < (u2&0xf0000000) ) return 0;
                                   if ( (u1&0xf000000) < (u2&0xf000000) ) return 0;
                                   if ( (u1&0xf00000) < (u2&0xf00000) ) return 0;
                                   if ( (u1&0xf0000) < (u2&0xf0000) ) return 0;
                                   if ( (u1&0xf000) < (u2&0xf000) ) return 0;
                                   if ( (u1&0xf00) < (u2&0xf00) ) return 0;
                                   if ( (u1&0xf0) < (u2&0xf0) ) return 0;
                                   if ( (u1&0xf) < (u2&0xf) ) return 0;
                           }
                           return 1;
                           break;
                   case 8:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   if ( (u1&0xff000000) < (u2&0xff000000) ) return 0;
                                   if ( (u1&0xff0000) < (u2&0xff0000) ) return 0;
                                   if ( (u1&0xff00) < (u2&0xff00) ) return 0;
                                   if ( (u1&0xff) < (u2&0xff) ) return 0;
                           }
                           return 1;
                           break;
                   case 16:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   if ( (u1&0xffff0000) < (u2&0xffff0000) ) return 0;
                                   if ( (u1&0xffff) < (u2&0xffff) ) return 0;
                           }
                           return 1;
                           break;
                   case 32:
                           for ( i = 0; i < nd_wpd; i++ )
                                   if ( d1[i] < d2[i] ) return 0;
                           return 1;
                           break;
                   default:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   for ( j = 0; j < nd_epw; j++ )
                                           if ( (u1&nd_mask[j]) < (u2&nd_mask[j]) ) return 0;
                           }
                           return 1;
           }
   }
   
   void ndl_lcm(unsigned int *d1,unsigned *d2,unsigned int *d)
   {
           unsigned int t1,t2,u,u1,u2;
           int i,j;
   
           switch ( nd_bpe ) {
                   case 4:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   t1 = (u1&0xf0000000); t2 = (u2&0xf0000000); u = t1>t2?t1:t2;
                                   t1 = (u1&0xf000000); t2 = (u2&0xf000000); u |= t1>t2?t1:t2;
                                   t1 = (u1&0xf00000); t2 = (u2&0xf00000); u |= t1>t2?t1:t2;
                                   t1 = (u1&0xf0000); t2 = (u2&0xf0000); u |= t1>t2?t1:t2;
                                   t1 = (u1&0xf000); t2 = (u2&0xf000); u |= t1>t2?t1:t2;
                                   t1 = (u1&0xf00); t2 = (u2&0xf00); u |= t1>t2?t1:t2;
                                   t1 = (u1&0xf0); t2 = (u2&0xf0); u |= t1>t2?t1:t2;
                                   t1 = (u1&0xf); t2 = (u2&0xf); u |= t1>t2?t1:t2;
                                   d[i] = u;
                           }
                           break;
                   case 8:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   t1 = (u1&0xff000000); t2 = (u2&0xff000000); u = t1>t2?t1:t2;
                                   t1 = (u1&0xff0000); t2 = (u2&0xff0000); u |= t1>t2?t1:t2;
                                   t1 = (u1&0xff00); t2 = (u2&0xff00); u |= t1>t2?t1:t2;
                                   t1 = (u1&0xff); t2 = (u2&0xff); u |= t1>t2?t1:t2;
                                   d[i] = u;
                           }
                           break;
                   case 16:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   t1 = (u1&0xffff0000); t2 = (u2&0xffff0000); u = t1>t2?t1:t2;
                                   t1 = (u1&0xffff); t2 = (u2&0xffff); u |= t1>t2?t1:t2;
                                   d[i] = u;
                           }
                           break;
                   case 32:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   d[i] = u1>u2?u1:u2;
                           }
                           break;
                   default:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   for ( j = 0, u = 0; j < nd_epw; j++ ) {
                                           t1 = (u1&nd_mask[j]); t2 = (u2&nd_mask[j]); u |= t1>t2?t1:t2;
                                   }
                                   d[i] = u;
                           }
                           break;
           }
   }
   
   int ndl_td(unsigned int *d)
   {
           unsigned int t,u;
           int i,j;
   
           for ( t = 0, i = 0; i < nd_wpd; i++ ) {
                   u = d[i];
                   for ( j = 0; j < nd_epw; j++, u>>=nd_bpe )
                           t += (u&nd_mask0);
           }
           return t;
   }
   
   INLINE int ndl_compare(unsigned int *d1,unsigned int *d2)
   {
           int i;
   
           for ( i = 0; i < nd_wpd; i++, d1++, d2++ )
                   if ( *d1 > *d2 )
                           return is_rlex ? -1 : 1;
                   else if ( *d1 < *d2 )
                           return is_rlex ? 1 : -1;
           return 0;
   }
   
   INLINE int ndl_equal(unsigned int *d1,unsigned int *d2)
   {
           int i;
   
           for ( i = 0; i < nd_wpd; i++ )
                   if ( d1[i] != d2[i] )
                           return 0;
           return 1;
   }
   
   INLINE void ndl_add(unsigned int *d1,unsigned int *d2,unsigned int *d)
   {
           int i;
   
           for ( i = 0; i < nd_wpd; i++ )
                   d[i] = d1[i]+d2[i];
   }
   
   void ndl_sub(unsigned int *d1,unsigned int *d2,unsigned int *d)
   {
           int i;
   
           for ( i = 0; i < nd_wpd; i++ )
                   d[i] = d1[i]-d2[i];
   }
   
   int ndl_disjoint(unsigned int *d1,unsigned int *d2)
   {
           unsigned int t1,t2,u,u1,u2;
           int i,j;
   
           switch ( nd_bpe ) {
                   case 4:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   t1 = u1&0xf0000000; t2 = u2&0xf0000000; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xf000000; t2 = u2&0xf000000; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xf00000; t2 = u2&0xf00000; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xf0000; t2 = u2&0xf0000; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xf000; t2 = u2&0xf000; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xf00; t2 = u2&0xf00; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xf0; t2 = u2&0xf0; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xf; t2 = u2&0xf; if ( t1&&t2 ) return 0;
                           }
                           return 1;
                           break;
                   case 8:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   t1 = u1&0xff000000; t2 = u2&0xff000000; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xff0000; t2 = u2&0xff0000; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xff00; t2 = u2&0xff00; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xff; t2 = u2&0xff; if ( t1&&t2 ) return 0;
                           }
                           return 1;
                           break;
                   case 16:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   t1 = u1&0xffff0000; t2 = u2&0xffff0000; if ( t1&&t2 ) return 0;
                                   t1 = u1&0xffff; t2 = u2&0xffff; if ( t1&&t2 ) return 0;
                           }
                           return 1;
                           break;
                   case 32:
                           for ( i = 0; i < nd_wpd; i++ )
                                   if ( d1[i] && d2[i] ) return 0;
                           return 1;
                           break;
                   default:
                           for ( i = 0; i < nd_wpd; i++ ) {
                                   u1 = d1[i]; u2 = d2[i];
                                   for ( j = 0; j < nd_epw; j++ ) {
                                           if ( (u1&nd_mask0) && (u2&nd_mask0) ) return 0;
                                           u1 >>= nd_bpe; u2 >>= nd_bpe;
                                   }
                           }
                           return 1;
                           break;
           }
   }
   
   ND nd_reduce(ND p1,ND p2)
   {
           int c,t,td,td2,mul;
           NM m2,prev,head,cur,new;
           unsigned int *d;
   
           if ( !p1 )
                   return 0;
           else {
                   mul = ((nd_mod-HC(p1))*invm(HC(p2),nd_mod))%nd_mod;
                   td = HTD(p1)-HTD(p2);
                   d = (unsigned int *)ALLOCA(nd_wpd*sizeof(unsigned int));
                   ndl_sub(HDL(p1),HDL(p2),d);
                   prev = 0; head = cur = BDY(p1);
                   NEWNM(new);
                   for ( m2 = BDY(p2); m2; ) {
                           td2 = new->td = m2->td+td;
                           ndl_add(m2->dl,d,new->dl);
                           if ( !cur ) {
                                   C(new) = (C(m2)*mul)%nd_mod;
                                   if ( !prev ) {
                                           prev = new;
                                           NEXT(prev) = 0;
                                           head = prev;
                                   } else {
                                           NEXT(prev) = new;
                                           NEXT(new) = 0;
                                           prev = new;
                                   }
                                   m2 = NEXT(m2);
                                   NEWNM(new);
                                   continue;
                           }
                           if ( cur->td > td2 )
                                   c = 1;
                           else if ( cur->td < td2 )
                                   c = -1;
                           else
                                   c = ndl_compare(cur->dl,new->dl);
                           switch ( c ) {
                                   case 0:
                                           t = (C(cur)+C(m2)*mul)%nd_mod;
                                           if ( t )
                                                   C(cur) = t;
                                           else if ( !prev ) {
                                                   head = NEXT(cur);
                                                   FREENM(cur);
                                                   cur = head;
                                           } else {
                                                   NEXT(prev) = NEXT(cur);
                                                   FREENM(cur);
                                                   cur = NEXT(prev);
                                           }
                                           m2 = NEXT(m2);
                                           break;
                                   case 1:
                                           prev = cur;
                                           cur = NEXT(cur);
                                           break;
                                   case -1:
                                           if ( !prev ) {
                                                   /* cur = head */
                                                   prev = new;
                                                   C(prev) = (C(m2)*mul)%nd_mod;
                                                   NEXT(prev) = head;
                                                   head = prev;
                                           } else {
                                                   C(new) = (C(m2)*mul)%nd_mod;
                                                   NEXT(prev) = new;
                                                   NEXT(new) = cur;
                                                   prev = new;
                                           }
                                           NEWNM(new);
                                           m2 = NEXT(m2);
                                           break;
                           }
                   }
                   FREENM(new);
                   if ( head ) {
                           BDY(p1) = head;
                           p1->sugar = MAX(p1->sugar,p2->sugar+td);
                           return p1;
                   } else {
                           FREEND(p1);
                           return 0;
                   }
   
           }
   }
   
   ND nd_sp(ND_pairs p)
   {
           NM m;
           ND p1,p2,t1,t2;
           unsigned int *lcm;
           int td;
   
           p1 = nps[p->i1];
           p2 = nps[p->i2];
           lcm = p->lcm;
           td = p->td;
           NEWNM(m);
           C(m) = HC(p2); m->td = td-HTD(p1); ndl_sub(lcm,HDL(p1),m->dl); NEXT(m) = 0;
           t1 = nd_mul_nm(p1,m);
           C(m) = nd_mod-HC(p1); m->td = td-HTD(p2); ndl_sub(lcm,HDL(p2),m->dl);
           t2 = nd_mul_nm(p2,m);
           FREENM(m);
           return nd_add(t1,t2);
   }
   
   ND nd_reducer(ND p1,ND p2)
   {
           NM m;
           ND r;
   
   
           NEWNM(m);
           C(m) = ((nd_mod-HC(p1))*invm(HC(p2),nd_mod))%nd_mod;
           m->td = HTD(p1)-HTD(p2);
           ndl_sub(HDL(p1),HDL(p2),m->dl);
           NEXT(m) = 0;
           r = nd_mul_nm(p2,m);
           FREENM(m);
           return r;
   }
   
   ND nd_find_reducer(ND g)
   {
           NM m;
           ND r,p;
           int i;
   
           for ( i = 0; i < nd_psn; i++ ) {
                   p = nps[i];
                   if ( HTD(g) >= HTD(p) && ndl_reducible(HDL(g),HDL(p)) ) {
   #if 1
                           NEWNM(m);
                           C(m) = ((nd_mod-HC(g))*invm(HC(p),nd_mod))%nd_mod;
                           m->td = HTD(g)-HTD(p);
                           ndl_sub(HDL(g),HDL(p),m->dl);
                           NEXT(m) = 0;
                           r = nd_mul_nm(p,m);
                           FREENM(m);
                           r->sugar = m->td + p->sugar;
                           return r;
   #else
                           return p;
   #endif
                   }
           }
           return 0;
   }
   
   ND nd_add(ND p1,ND p2)
   {
           int n,c;
           int t;
           ND r;
           NM m1,m2,mr0,mr,s;
   
           if ( !p1 )
                   return p2;
           else if ( !p2 )
                   return p1;
           else {
                   for ( n = NV(p1), m1 = BDY(p1), m2 = BDY(p2), mr0 = 0; m1 && m2; ) {
                           if ( m1->td > m2->td )
                                   c = 1;
                           else if ( m1->td < m2->td )
                                   c = -1;
                           else
                                   c = ndl_compare(m1->dl,m2->dl);
                           switch ( c ) {
                                   case 0:
                                           t = ((C(m1))+(C(m2))) - nd_mod;
                                           if ( t < 0 )
                                                   t += nd_mod;
                                           s = m1; m1 = NEXT(m1);
                                           if ( t ) {
                                                   NEXTNM2(mr0,mr,s); C(mr) = (t);
                                           } else {
                                                   FREENM(s);
                                           }
                                           s = m2; m2 = NEXT(m2); FREENM(s);
                                           break;
                                   case 1:
                                           s = m1; m1 = NEXT(m1); NEXTNM2(mr0,mr,s);
                                           break;
                                   case -1:
                                           s = m2; m2 = NEXT(m2); NEXTNM2(mr0,mr,s);
                                           break;
                           }
                   }
                   if ( !mr0 )
                           if ( m1 )
                                   mr0 = m1;
                           else if ( m2 )
                                   mr0 = m2;
                           else
                                   return 0;
                   else if ( m1 )
                           NEXT(mr) = m1;
                   else if ( m2 )
                           NEXT(mr) = m2;
                   else
                           NEXT(mr) = 0;
                   BDY(p1) = mr0;
                   p1->sugar = MAX(p1->sugar,p2->sugar);
                   FREEND(p2);
                   return p1;
           }
   }
   
   ND nd_mul_nm(ND p,NM m0)
   {
           NM m,mr,mr0;
           unsigned int *d,*dt,*dm;
           int c,n,td;
           int *pt,*p1,*p2;
           ND r;
   
           if ( !p )
                   return 0;
           else {
                   n = NV(p); m = BDY(p);
                   d = m0->dl; td = m0->td; c = C(m0);
                   mr0 = 0;
                   for ( ; m; m = NEXT(m) ) {
                           NEXTNM(mr0,mr);
                           C(mr) = (C(m)*c)%nd_mod;
                           mr->td = m->td+td;
                           ndl_add(m->dl,d,mr->dl);
                   }
                   NEXT(mr) = 0;
                   MKND(NV(p),mr0,r);
                   r->sugar = p->sugar + td;
                   return r;
           }
   }
   
   #if 1
   ND nd_nf(ND g,int full)
   {
           ND p,d,red;
           NM m,mrd,tail;
           int n,sugar,psugar;
   
           if ( !g )
                   return 0;
           sugar = g->sugar;
           n = NV(g);
           for ( d = 0; g; ) {
                   red = nd_find_reducer(g);
                   if ( red ) {
   #if 1
                           g = nd_add(g,red);
                           sugar = MAX(sugar,red->sugar);
   #else
                           psugar = (HTD(g)-HTD(red))+red->sugar;
                           g = nd_reduce(g,red);
                           sugar = MAX(sugar,psugar);
   #endif
                   } else if ( !full )
                           return g;
                   else {
                           m = BDY(g);
                           if ( NEXT(m) ) {
                                   BDY(g) = NEXT(m); NEXT(m) = 0;
                           } else {
                                   FREEND(g); g = 0;
                           }
                           if ( d ) {
                                   NEXT(tail)=m;
                                   tail=m;
                           } else {
                                   MKND(n,m,d);
                                   tail = BDY(d);
                           }
                   }
           }
           if ( d )
                   d->sugar = sugar;
           return d;
   }
   #else
   
   ND nd_remove_head(ND p)
   {
           NM m;
   
           m = BDY(p);
           if ( !NEXT(m) ) {
                   FREEND(p);
                   p = 0;
           } else
                   BDY(p) = NEXT(m);
           FREENM(m);
           return p;
   }
   
   PGeoBucket create_pbucket()
   {
       PGeoBucket g;
   
           g = CALLOC(1,sizeof(struct oPGeoBucket));
           g->m = -1;
           return g;
   }
   
   void add_pbucket(PGeoBucket g,ND d)
   {
           int l,k,m;
   
           l = nd_length(d);
           for ( k = 0, m = 1; l > m; k++, m <<= 2 );
           /* 4^(k-1) < l <= 4^k */
           d = nd_add(g->body[k],d);
           for ( ; d && nd_length(d) > 1<<(2*k); k++ ) {
                   g->body[k] = 0;
                   d = nd_add(g->body[k+1],d);
           }
           g->body[k] = d;
           g->m = MAX(g->m,k);
   }
   
   int head_pbucket(PGeoBucket g)
   {
           int j,i,c,k,nv,sum;
           unsigned int *di,*dj;
           ND gi,gj;
   
           k = g->m;
           while ( 1 ) {
                   j = -1;
                   for ( i = 0; i <= k; i++ ) {
                           if ( !(gi = g->body[i]) )
                                   continue;
                           if ( j < 0 ) {
                                   j = i;
                                   gj = g->body[j];
                                   dj = HDL(gj);
                                   sum = HC(gj);
                           } else {
                                   di = HDL(gi);
                                   nv = NV(gi);
                                   if ( HTD(gi) > HTD(gj) )
                                           c = 1;
                                   else if ( HTD(gi) < HTD(gj) )
                                           c = -1;
                                   else
                                           c = ndl_compare(di,dj);
                                   if ( c > 0 ) {
                                           if ( sum )
                                                   HC(gj) = sum;
                                           else
                                                   g->body[j] = nd_remove_head(gj);
                                           j = i;
                                           gj = g->body[j];
                                           dj = HDL(gj);
                                           sum = HC(gj);
                                   } else if ( c == 0 ) {
                                           sum = sum+HC(gi)-nd_mod;
                                           if ( sum < 0 )
                                                   sum += nd_mod;
                                           g->body[i] = nd_remove_head(gi);
                                   }
                           }
                   }
                   if ( j < 0 )
                           return -1;
                   else if ( sum ) {
                           HC(gj) = sum;
                           return j;
                   } else
                           g->body[j] = nd_remove_head(gj);
           }
   }
   
   ND normalize_pbucket(PGeoBucket g)
   {
           int i;
           ND r,t;
   
           r = 0;
           for ( i = 0; i <= g->m; i++ )
                   r = nd_add(r,g->body[i]);
           return r;
   }
   
   ND nd_nf(ND g,int full)
   {
           ND u,p,d,red;
           NODE l;
           NM m,mrd;
           int sugar,psugar,n,h_reducible,h;
           PGeoBucket bucket;
   
           if ( !g ) {
                   return 0;
           }
           sugar = g->sugar;
           n = g->nv;
           bucket = create_pbucket();
           add_pbucket(bucket,g);
           d = 0;
           while ( 1 ) {
                   h = head_pbucket(bucket);
                   if ( h < 0 ) {
                           if ( d )
                                   d->sugar = sugar;
                           return d;
                   }
                   g = bucket->body[h];
                   red = nd_find_reducer(g);
                   if ( red ) {
                           bucket->body[h] = nd_remove_head(g);
                           red = nd_remove_head(red);
                           add_pbucket(bucket,red);
                           sugar = MAX(sugar,red->sugar);
                   } else if ( !full ) {
                           g = normalize_pbucket(bucket);
                           if ( g )
                                   g->sugar = sugar;
                           return g;
                   } else {
                           m = BDY(g);
                           if ( NEXT(m) ) {
                                   BDY(g) = NEXT(m); NEXT(m) = 0;
                           } else {
                                   FREEND(g); g = 0;
                           }
                           bucket->body[h] = g;
                           NEXT(m) = 0;
                           if ( d ) {
                                   for ( mrd = BDY(d); NEXT(mrd); mrd = NEXT(mrd) );
                                   NEXT(mrd) = m;
                           } else {
                                   MKND(n,m,d);
                           }
                   }
           }
   }
   #endif
   
   NODE nd_gb(NODE f)
   {
           int i,nh;
           NODE r,g,gall;
           ND_pairs d;
           ND_pairs l;
           ND h,nf;
   
           for ( gall = g = 0, d = 0, r = f; r; r = NEXT(r) ) {
                   i = (int)BDY(r);
                   d = update_pairs(d,g,i);
                   g = update_base(g,i);
                   gall = append_one(gall,i);
           }
           while ( d ) {
   #if 0
                   ndp_print(d);
   #endif
                   l = nd_minp(d,&d);
                   h = nd_sp(l);
                   nf = nd_nf(h,!Top);
                   if ( nf ) {
                           printf("+"); fflush(stdout);
   #if 0
                           ndl_print(HDL(nf)); fflush(stdout);
   #endif
                           nh = nd_newps(nf);
                           d = update_pairs(d,g,nh);
                           g = update_base(g,nh);
                           gall = append_one(gall,nh);
                   } else {
                           printf("."); fflush(stdout);
                   }
           }
           return g;
   }
   
   ND_pairs update_pairs( ND_pairs d, NODE /* of index */ g, int t)
   {
           ND_pairs d1,nd,cur,head,prev;
   
           if ( !g ) return d;
           d = crit_B(d,t);
           d1 = nd_newpairs(g,t);
           d1 = crit_M(d1);
           d1 = crit_F(d1);
           prev = 0; cur = head = d1;
           while ( cur ) {
                   if ( crit_2( cur->i1,cur->i2 ) ) {
                           if ( !prev ) {
                                   head = cur = NEXT(cur);
                           } else {
                                   cur = NEXT(prev) = NEXT(cur);
                           }
                   } else {
                           prev = cur;
                           cur = NEXT(cur);
                   }
           }
           if ( !d )
                   return head;
           else {
                   nd = d;
                   while ( NEXT(nd) )
                           nd = NEXT(nd);
                   NEXT(nd) = head;
                   return d;
           }
   }
   
   ND_pairs nd_newpairs( NODE g, int t )
   {
           NODE h;
           unsigned int *dl;
           int td,ts,s;
           ND_pairs r,r0;
   
           dl = HDL(nps[t]);
           td = HTD(nps[t]);
           ts = nps[t]->sugar - td;
           for ( r0 = 0, h = g; h; h = NEXT(h) ) {
                   NEXTND_pairs(r0,r);
                   r->i1 = (int)BDY(h);
                   r->i2 = t;
                   ndl_lcm(HDL(nps[r->i1]),dl,r->lcm);
                   r->td = ndl_td(r->lcm);
                   s = nps[r->i1]->sugar-HTD(nps[r->i1]);
                   r->sugar = MAX(s,ts) + r->td;
           }
           NEXT(r) = 0;
           return r0;
   }
   
   ND_pairs crit_B( ND_pairs d, int s )
   {
           ND_pairs cur,head,prev;
           unsigned int *t,*tl,*lcm;
           int td,tdl;
   
           if ( !d ) return 0;
           t = HDL(nps[s]);
           prev = 0;
           head = cur = d;
           lcm = (unsigned int *)ALLOCA(nd_wpd*sizeof(unsigned int));
           while ( cur ) {
                   tl = cur->lcm;
                   if ( ndl_reducible(tl,t)
                           && (ndl_lcm(HDL(nps[cur->i1]),t,lcm),!ndl_equal(lcm,tl))
                           && (ndl_lcm(HDL(nps[cur->i2]),t,lcm),!ndl_equal(lcm,tl)) ) {
                           if ( !prev ) {
                                   head = cur = NEXT(cur);
                           } else {
                                   cur = NEXT(prev) = NEXT(cur);
                           }
                   } else {
                           prev = cur;
                           cur = NEXT(cur);
                   }
           }
           return head;
   }
   
   ND_pairs crit_M( ND_pairs d1 )
   {
           ND_pairs e,d2,d3,dd,p;
           unsigned int *id,*jd;
           int itd,jtd;
   
           for ( dd = 0, e = d1; e; e = d3 ) {
                   if ( !(d2 = NEXT(e)) ) {
                           NEXT(e) = dd;
                           return e;
                   }
                   id = e->lcm;
                   itd = e->td;
                   for ( d3 = 0; d2; d2 = p ) {
                           p = NEXT(d2),
                           jd = d2->lcm;
                           jtd = d2->td;
                           if ( jtd == itd  )
                                   if ( id == jd );
                                   else if ( ndl_reducible(jd,id) ) continue;
                                   else if ( ndl_reducible(id,jd) ) goto delit;
                                   else ;
                           else if ( jtd > itd )
                                   if ( ndl_reducible(jd,id) ) continue;
                                   else ;
                           else if ( ndl_reducible(id,jd ) ) goto delit;
                           NEXT(d2) = d3;
                           d3 = d2;
                   }
                   NEXT(e) = dd;
                   dd = e;
                   continue;
                   /**/
           delit:  NEXT(d2) = d3;
                   d3 = d2;
                   for ( ; p; p = d2 ) {
                           d2 = NEXT(p);
                           NEXT(p) = d3;
                           d3 = p;
                   }
           }
           return dd;
   }
   
   ND_pairs crit_F( ND_pairs d1 )
   {
           ND_pairs rest, head;
           ND_pairs last, p, r, w;
           int s;
   
           for ( head = last = 0, p = d1; NEXT(p); ) {
                   r = w = equivalent_pairs(p,&rest);
                   s = r->sugar;
                   while ( w = NEXT(w) )
                           if ( crit_2(w->i1,w->i2) ) {
                                   r = w;
                                   break;
                           } else if ( w->sugar < s ) {
                                   r = w;
                                   s = r->sugar;
                           }
                   if ( last ) NEXT(last) = r;
                   else head = r;
                   NEXT(last = r) = 0;
                   p = rest;
                   if ( !p ) return head;
           }
           if ( !last ) return p;
           NEXT(last) = p;
           return head;
   }
   
   int crit_2( int dp1, int dp2 )
   {
           return ndl_disjoint(HDL(nps[dp1]),HDL(nps[dp2]));
   }
   
   static ND_pairs equivalent_pairs( ND_pairs d1, ND_pairs *prest )
   {
           ND_pairs w,p,r,s;
           unsigned int *d;
           int td;
   
           w = d1;
           d = w->lcm;
           td = w->td;
           s = NEXT(w);
           NEXT(w) = 0;
           for ( r = 0; s; s = p ) {
                   p = NEXT(s);
                   if ( td == s->td && ndl_equal(d,s->lcm) ) {
                           NEXT(s) = w;
                           w = s;
                   } else {
                           NEXT(s) = r;
                           r = s;
                   }
           }
           *prest = r;
           return w;
   }
   
   NODE update_base(NODE nd,int ndp)
   {
           unsigned int *dl, *dln;
           NODE last, p, head;
           int td,tdn;
   
           dl = HDL(nps[ndp]);
           td = HTD(nps[ndp]);
           for ( head = last = 0, p = nd; p; ) {
                   dln = HDL(nps[(int)BDY(p)]);
                   tdn = HTD(nps[(int)BDY(p)]);
                   if ( tdn >= td && ndl_reducible( dln, dl ) ) {
                           p = NEXT(p);
                           if ( last ) NEXT(last) = p;
                   } else {
                           if ( !last ) head = p;
                           p = NEXT(last = p);
                   }
           }
           head = append_one(head,ndp);
           return head;
   }
   
   ND_pairs nd_minp( ND_pairs d, ND_pairs *prest )
   {
           ND_pairs m,ml,p,l;
           unsigned int *lcm;
           int s,td,len,tlen,c;
   
           if ( !(p = NEXT(m = d)) ) {
                   *prest = p;
                   NEXT(m) = 0;
                   return m;
           }
           lcm = m->lcm;
           s = m->sugar;
           td = m->td;
           len = nd_length(nps[m->i1])+nd_length(nps[m->i2]);
           for ( ml = 0, l = m; p; p = NEXT(l = p) ) {
                   if (p->sugar < s)
                           goto find;
                   else if ( p->sugar == s ) {
                           if ( p->td < td )
                                   goto find;
                           else if ( p->td == td ) {
                                   c = ndl_compare(p->lcm,lcm);
                                   if ( c < 0 )
                                           goto find;
                                   else if ( c == 0 ) {
                                           tlen = nd_length(nps[p->i1])+nd_length(nps[p->i2]);
                                           if ( tlen < len )
                                                   goto find;
                                   }
                           }
                   }
                   continue;
   find:
                   ml = l;
                   m = p;
                   lcm = m->lcm;
                   s = m->sugar;
                   td = m->td;
                   len = tlen;
           }
           if ( !ml ) *prest = NEXT(m);
           else {
                   NEXT(ml) = NEXT(m);
                   *prest = d;
           }
           NEXT(m) = 0;
           return m;
   }
   
   int nd_newps(ND a)
   {
           if ( nd_psn == nd_pslen ) {
                   nd_pslen *= 2;
                   nps = (ND *)REALLOC((char *)nps,nd_pslen*sizeof(ND));
           }
           nd_monic(a);
           nps[nd_psn] = a;
           return nd_psn++;
   }
   
   NODE NODE_sortb(NODE f,int);
   ND dptond(DP);
   DP ndtodp(ND);
   
   NODE nd_setup(NODE f)
   {
           int i;
           NODE s,s0,f0;
   
   #if 0
           f0 = f = NODE_sortb(f,1);
   #endif
           nd_psn = length(f); nd_pslen = 2*nd_psn;
           nps = (ND *)MALLOC(nd_pslen*sizeof(ND));
           nd_bpe = 4;
           nd_epw = (sizeof(unsigned int)*8)/nd_bpe;
           nd_wpd = nd_nvar/nd_epw+(nd_nvar%nd_epw?1:0);
           nd_mask0 = (1<<nd_bpe)-1;
           bzero(nd_mask,sizeof(nd_mask));
           for ( i = 0; i < nd_epw; i++ )
                   nd_mask[nd_epw-i-1] = (nd_mask0<<(i*nd_bpe));
           nd_free_private_storage();
           for ( i = 0; i < nd_psn; i++, f = NEXT(f) ) {
                   nps[i] = dptond((DP)BDY(f));
                   nd_monic(nps[i]);
           }
           for ( s0 = 0, i = 0; i < nd_psn; i++ ) {
                   NEXTNODE(s0,s); BDY(s) = (pointer)i;
           }
           if ( s0 ) NEXT(s) = 0;
           return s0;
   }
   
   void nd_gr(LIST f,LIST v,int m,struct order_spec *ord,LIST *rp)
   {
           struct order_spec ord1;
           VL fv,vv,vc;
           NODE fd,fd0,r,r0,t,x,s,xx;
           DP a,b,c;
   
           get_vars((Obj)f,&fv); pltovl(v,&vv);
           nd_nvar = length(vv);
           if ( ord->id )
                   error("nd_gr : unsupported order");
           switch ( ord->ord.simple ) {
                   case 0:
                           is_rlex = 1;
                           break;
                   case 1:
                           is_rlex = 0;
                           break;
                   default:
                           error("nd_gr : unsupported order");
           }
           initd(ord);
           nd_mod = m;
           for ( fd0 = 0, t = BDY(f); t; t = NEXT(t) ) {
                   ptod(CO,vv,(P)BDY(t),&b);
                   _dp_mod(b,m,0,&c);
                   if ( c ) {
                           NEXTNODE(fd0,fd); BDY(fd) = (pointer)c;
                   }
           }
           if ( fd0 ) NEXT(fd) = 0;
           s = nd_setup(fd0);
           x = nd_gb(s);
   #if 0
           x = nd_reduceall(x,m);
   #endif
           for ( r0 = 0; x; x = NEXT(x) ) {
                   NEXTNODE(r0,r);
                   a = ndtodp(nps[(int)BDY(x)]);
                   _dtop_mod(CO,vv,a,(P *)&BDY(r));
           }
           if ( r0 ) NEXT(r) = 0;
           MKLIST(*rp,r0);
   }
   
   void dltondl(int n,DL dl,unsigned int *r)
   {
           unsigned int *d;
           int i;
   
           d = dl->d;
           bzero(r,nd_wpd*sizeof(unsigned int));
           if ( is_rlex )
                   for ( i = 0; i < n; i++ )
                           r[(n-1-i)/nd_epw] |= (d[i]<<((nd_epw-((n-1-i)%nd_epw)-1)*nd_bpe));
           else
                   for ( i = 0; i < n; i++ )
                           r[i/nd_epw] |= d[i]<<((nd_epw-(i%nd_epw)-1)*nd_bpe);
   }
   
   DL ndltodl(int n,int td,unsigned int *ndl)
   {
           DL dl;
           int *d;
           int i;
   
           NEWDL(dl,n);
           dl->td = td;
           d = dl->d;
           if ( is_rlex )
                   for ( i = 0; i < n; i++ )
                           d[i] = (ndl[(n-1-i)/nd_epw]>>((nd_epw-((n-1-i)%nd_epw)-1)*nd_bpe))
                                   &((1<<nd_bpe)-1);
           else
                   for ( i = 0; i < n; i++ )
                           d[i] = (ndl[i/nd_epw]>>((nd_epw-(i%nd_epw)-1)*nd_bpe))
                                   &((1<<nd_bpe)-1);
           return dl;
   }
   
   ND dptond(DP p)
   {
           ND d;
           NM m0,m;
           MP t;
           int n;
   
           if ( !p )
                   return 0;
           n = NV(p);
           m0 = 0;
           for ( t = BDY(p); t; t = NEXT(t) ) {
                   NEXTNM(m0,m);
                   m->c = ITOS(t->c);
                   m->td = t->dl->td;
                   dltondl(n,t->dl,m->dl);
           }
           NEXT(m) = 0;
           MKND(n,m0,d);
           d->nv = n;
           d->sugar = p->sugar;
           return d;
   }
   
   DP ndtodp(ND p)
   {
           DP d;
           MP m0,m;
           NM t;
           int n;
   
           if ( !p )
                   return 0;
           n = NV(p);
           m0 = 0;
           for ( t = BDY(p); t; t = NEXT(t) ) {
                   NEXTMP(m0,m);
                   m->c = STOI(t->c);
                   m->dl = ndltodl(n,t->td,t->dl);
           }
           NEXT(m) = 0;
           MKDP(n,m0,d);
           d->sugar = p->sugar;
           return d;
   }
   
   void ndl_print(unsigned int *dl)
   {
           int n;
           int i;
   
           n = nd_nvar;
           printf("<<");
           if ( is_rlex )
                   for ( i = 0; i < n; i++ )
                           printf(i==n-1?"%d":"%d,",
                                   (dl[(n-1-i)/nd_epw]>>((nd_epw-((n-1-i)%nd_epw)-1)*nd_bpe))
                                           &((1<<nd_bpe)-1));
           else
                   for ( i = 0; i < n; i++ )
                           printf(i==n-1?"%d":"%d,",
                                   (dl[i/nd_epw]>>((nd_epw-(i%nd_epw)-1)*nd_bpe))
                                           &((1<<nd_bpe)-1));
           printf(">>");
   }
   
   void nd_print(ND p)
   {
           NM m;
   
           if ( !p )
                   printf("0\n");
           else {
                   for ( m = BDY(p); m; m = NEXT(m) ) {
                           printf("+%d*",m->c);
                           ndl_print(m->dl);
                   }
                   printf("\n");
           }
   }
   
   void ndp_print(ND_pairs d)
   {
           ND_pairs t;
   
           for ( t = d; t; t = NEXT(t) ) {
                   printf("%d,%d ",t->i1,t->i2);
           }
           printf("\n");
   }
   
   void nd_monic(ND p)
   {
           int mul;
           NM m;
   
           if ( !p )
                   return;
           mul = invm(HC(p),nd_mod);
           for ( m = BDY(p); m; m = NEXT(m) )
                   C(m) = (C(m)*mul)%nd_mod;
 }  }

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.12

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>