[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.5 and 1.11

version 1.5, 2000/08/21 08:31:27 version 1.11, 2003/07/18 10:13:13
Line 23 
Line 23 
  * shall be made on your publication or presentation in any form of the   * shall be made on your publication or presentation in any form of the
  * results obtained by use of the SOFTWARE.   * results obtained by use of the SOFTWARE.
  * (4) In the event that you modify the SOFTWARE, you shall notify FLL by   * (4) In the event that you modify the SOFTWARE, you shall notify FLL by
  * e-mail at risa-admin@flab.fujitsu.co.jp of the detailed specification   * e-mail at risa-admin@sec.flab.fujitsu.co.jp of the detailed specification
  * for such modification or the source code of the modified part of the   * for such modification or the source code of the modified part of the
  * SOFTWARE.   * SOFTWARE.
  *   *
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.4 2000/07/13 05:09:01 noro Exp $   * $OpenXM: OpenXM_contrib2/asir2000/engine/distm.c,v 1.10 2002/01/28 00:54:43 noro Exp $
 */  */
 #include "ca.h"  #include "ca.h"
 #include "inline.h"  #include "inline.h"
   
 #define NV(p) ((p)->nv)  
 #define C(p) ((p)->c)  
 #if 0  
 #define ITOS(p) (((unsigned int)(p))>>1)  
 #define STOI(i) ((P)((((unsigned int)(i))<<1)|1))  
 #else  
 #define ITOS(p) (((unsigned int)(p))&0x7fffffff)  
 #define STOI(i) ((P)((unsigned int)(i)|0x80000000))  
 #endif  
   
 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 _comm_mulmd();  
 void _weyl_mulmd();  
 void _weyl_mulmmm();  
 void _weyl_mulmdm();  
   
 void ptomd(vl,mod,dvl,p,pr)  
 VL vl,dvl;  
 int mod;  
 P p;  
 DP *pr;  
 {  {
         P t;          P t;
   
Line 84  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 118  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 128  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 156  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 217  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 231  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 249  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 260  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 299  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 333  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 365  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 402  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 437  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 451  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 476  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 505  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 528  DP *pr;
Line 460  DP *pr;
         }          }
 }  }
   
 void _mdtop(vl,mod,dvl,p,pr)  void _dtop_mod(VL vl,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;
         MP m;          MP m;
         P r,s,t,u,w;          P r,s,t,u,w;
         Q q;          Q q;
         MQ tq;  
         VL tvl;          VL tvl;
   
         if ( !p )          if ( !p )
                 *pr = 0;                  *pr = 0;
         else {          else {
                 for ( n = p->nv, m = BDY(p), s = 0; m; m = NEXT(m) ) {                  for ( n = p->nv, m = BDY(p), s = 0; m; m = NEXT(m) ) {
                         STOMQ(ITOS(C(m)),tq); t = (P)tq;                          i = ITOS(m->c); STOQ(i,q); t = (P)q;
                         for ( i = 0, d = m->dl, tvl = dvl;                          for ( i = 0, d = m->dl, tvl = dvl;
                                 i < n; tvl = NEXT(tvl), i++ ) {                                  i < n; tvl = NEXT(tvl), i++ ) {
                                 MKV(tvl->v,r); STOQ(d->d[i],q); pwrmp(vl,mod,r,q,&u);                                  MKV(tvl->v,r); STOQ(d->d[i],q); pwrp(vl,r,q,&u);
                                 mulmp(vl,mod,t,u,&w); t = w;                                  mulp(vl,t,u,&w); t = w;
                         }                          }
                         addmp(vl,mod,s,t,&u); s = u;                          addp(vl,s,t,&u); s = u;
                 }                  }
                 mptop(s,pr);                  *pr = s;
         }          }
 }  }
   
 void _addmd(vl,mod,p1,p2,pr)  void _dp_mod(DP p,int mod,NODE subst,DP *rp)
 VL vl;  
 int mod;  
 DP p1,p2,*pr;  
 {  {
           MP m,mr,mr0;
           P t,s;
           NODE tn;
   
           if ( !p )
                   *rp = 0;
           else {
                   for ( mr0 = 0, m = BDY(p); m; m = NEXT(m) ) {
                           for ( tn = subst, s = m->c; tn; tn = NEXT(NEXT(tn)) ) {
                                   substp(CO,s,BDY(tn),BDY(NEXT(tn)),&t);
                                   s = t;
                           }
                           ptomp(mod,s,&t);
                           if ( t ) {
                                   NEXTMP(mr0,mr); mr->c = STOI(CONT((MQ)t)); mr->dl = m->dl;
                           }
                   }
                   if ( mr0 ) {
                           NEXT(mr) = 0; MKDP(p->nv,mr0,*rp); (*rp)->sugar = p->sugar;
                   } else
                           *rp = 0;
           }
   }
   
   void _dp_monic(DP p,int mod,DP *rp)
   {
           MP m,mr,mr0;
           int c,c1;
   
           if ( !p )
                   *rp = 0;
           else {
                   c = invm(ITOS(BDY(p)->c),mod);
                   for ( mr0 = 0, m = BDY(p); m; m = NEXT(m) ) {
                           c1 = dmar(ITOS(m->c),c,0,mod);
                           NEXTMP(mr0,mr); mr->c = STOI(c1); mr->dl = m->dl;
                   }
                   NEXT(mr) = 0; MKDP(p->nv,mr0,*rp); (*rp)->sugar = p->sugar;
           }
   }
   
   void _printdp(DP d)
   {
           int n,i;
           MP m;
           DL dl;
   
           if ( !d ) {
                   printf("0"); return;
           }
           for ( n = d->nv, m = BDY(d); m; m = NEXT(m) ) {
                   printf("%d*<<",ITOS(m->c));
                   for ( i = 0, dl = m->dl; i < n-1; i++ )
                           printf("%d,",dl->d[i]);
                   printf("%d",dl->d[i]);
                   printf(">>");
                   if ( NEXT(m) )
                           printf("+");
           }
   }
   
   /* merge p1 and p2 into pr */
   
   void addmd_destructive(int mod,DP p1,DP p2,DP *pr)
   {
         int n;          int n;
         MP m1,m2,mr,mr0;          MP m1,m2,mr,mr0,s;
         int t;          int t;
   
         if ( !p1 )          if ( !p1 )
Line 578  DP p1,p2,*pr;
Line 567  DP p1,p2,*pr;
                                         t = (ITOS(C(m1))+ITOS(C(m2))) - mod;                                          t = (ITOS(C(m1))+ITOS(C(m2))) - mod;
                                         if ( t < 0 )                                          if ( t < 0 )
                                                 t += mod;                                                  t += mod;
                                           s = m1; m1 = NEXT(m1);
                                         if ( t ) {                                          if ( t ) {
                                                 NEXTMP(mr0,mr); mr->dl = m1->dl; C(mr) = STOI(t);                                                  NEXTMP2(mr0,mr,s); C(mr) = STOI(t);
                                         }                                          }
                                         m1 = NEXT(m1); m2 = NEXT(m2); break;                                          s = m2; m2 = NEXT(m2);
                                           break;
                                 case 1:                                  case 1:
                                         NEXTMP(mr0,mr); mr->dl = m1->dl; C(mr) = C(m1);                                          s = m1; m1 = NEXT(m1); NEXTMP2(mr0,mr,s);
                                         m1 = NEXT(m1); break;                                          break;
                                 case -1:                                  case -1:
                                         NEXTMP(mr0,mr); mr->dl = m2->dl; C(mr) = C(m2);                                          s = m2; m2 = NEXT(m2); NEXTMP2(mr0,mr,s);
                                         m2 = NEXT(m2); break;                                          break;
                         }                          }
                 if ( !mr0 )                  if ( !mr0 )
                         if ( m1 )                          if ( m1 )
Line 610  DP p1,p2,*pr;
Line 601  DP p1,p2,*pr;
         }          }
 }  }
   
 void _submd(vl,mod,p1,p2,pr)  void mulmd_dup(int mod,DP p1,DP p2,DP *pr)
 VL vl;  
 int mod;  
 DP p1,p2,*pr;  
 {  {
         DP t;  
   
         if ( !p2 )  
                 *pr = p1;  
         else {  
                 _chsgnmd(mod,p2,&t); _addmd(vl,mod,p1,t,pr);  
         }  
 }  
   
 void _chsgnmd(mod,p,pr)  
 int mod;  
 DP p,*pr;  
 {  
         MP m,mr,mr0;  
   
         if ( !p )  
                 *pr = 0;  
         else {  
                 for ( mr0 = 0, m = BDY(p); m; m = NEXT(m) ) {  
                         NEXTMP(mr0,mr); C(mr) = STOI(mod - ITOS(C(m))); mr->dl = m->dl;  
                 }  
                 NEXT(mr) = 0; MKDP(NV(p),mr0,*pr);  
                 if ( *pr )  
                         (*pr)->sugar = p->sugar;  
         }  
 }  
   
 void _mulmd(vl,mod,p1,p2,pr)  
 VL vl;  
 int mod;  
 DP p1,p2,*pr;  
 {  
         if ( !do_weyl )          if ( !do_weyl )
                 _comm_mulmd(vl,mod,p1,p2,pr);                  comm_mulmd_dup(mod,p1,p2,pr);
         else          else
                 _weyl_mulmd(vl,mod,p1,p2,pr);                  weyl_mulmd_dup(mod,p1,p2,pr);
 }  }
   
 void _comm_mulmd(vl,mod,p1,p2,pr)  void comm_mulmd_dup(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 681  DP p1,p2,*pr;
Line 634  DP p1,p2,*pr;
                 for ( m = BDY(p2), i = 0; i < l; m = NEXT(m), i++ )                  for ( m = BDY(p2), i = 0; i < l; m = NEXT(m), i++ )
                         w[i] = m;                          w[i] = m;
                 for ( s = 0, i = l-1; i >= 0; i-- ) {                  for ( s = 0, i = l-1; i >= 0; i-- ) {
                         _mulmdm(vl,mod,p1,w[i],&t); _addmd(vl,mod,s,t,&u); s = u;                          mulmdm_dup(mod,p1,w[i],&t); addmd_destructive(mod,s,t,&u); s = u;
                 }                  }
                 bzero(w,l*sizeof(MP));                  bzero(w,l*sizeof(MP));
                 *pr = s;                  *pr = s;
         }          }
 }  }
   
 void _weyl_mulmd(vl,mod,p1,p2,pr)  void weyl_mulmd_dup(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;
   
         if ( !p1 || !p2 )          if ( !p1 || !p2 )
                 *pr = 0;                  *pr = 0;
         else {          else {
                 for ( m = BDY(p2), l = 0; m; m = NEXT(m), l++ );                  for ( m = BDY(p1), l = 0; m; m = NEXT(m), l++ );
                 if ( l > wlen ) {                  if ( l > wlen ) {
                         if ( w ) GC_free(w);                          if ( w ) GC_free(w);
                         w = (MP *)MALLOC(l*sizeof(MP));                          w = (MP *)MALLOC(l*sizeof(MP));
                         wlen = l;                          wlen = l;
                 }                  }
                 for ( m = BDY(p2), i = 0; i < l; m = NEXT(m), i++ )                  for ( m = BDY(p1), i = 0; i < l; m = NEXT(m), i++ )
                         w[i] = m;                          w[i] = m;
                 for ( s = 0, i = l-1; i >= 0; i-- ) {                  for ( s = 0, i = l-1; i >= 0; i-- ) {
                         _weyl_mulmdm(vl,mod,p1,w[i],&t); _addmd(vl,mod,s,t,&u); s = u;                          weyl_mulmdm_dup(mod,w[i],p2,&t); addmd_destructive(mod,s,t,&u); s = u;
                 }                  }
                 bzero(w,l*sizeof(MP));                  bzero(w,l*sizeof(MP));
                 *pr = s;                  *pr = s;
         }          }
 }  }
   
 void _mulmdm(vl,mod,p,m0,pr)  void mulmdm_dup(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;
         DL d;          DL d,dt,dm;
         int c,n,r;          int c,n,i;
           int *pt,*p1,*p2;
   
         if ( !p )          if ( !p )
                 *pr = 0;                  *pr = 0;
Line 736  DP *pr;
Line 682  DP *pr;
                         m; m = NEXT(m) ) {                          m; m = NEXT(m) ) {
                         NEXTMP(mr0,mr);                          NEXTMP(mr0,mr);
                         C(mr) = STOI(dmar(ITOS(C(m)),c,0,mod));                          C(mr) = STOI(dmar(ITOS(C(m)),c,0,mod));
                         adddl(n,m->dl,d,&mr->dl);                          NEWDL_NOINIT(dt,n); mr->dl = dt;
                           dm = m->dl;
                           dt->td = d->td + dm->td;
                           for ( i = 0, pt = dt->d, p1=d->d, p2 = dm->d; i < n; i++ )
                                   *pt++ = *p1++ + *p2++;
                 }                  }
                 NEXT(mr) = 0; MKDP(NV(p),mr0,*pr);                  NEXT(mr) = 0; MKDP(NV(p),mr0,*pr);
                 if ( *pr )                  if ( *pr )
Line 744  DP *pr;
Line 694  DP *pr;
         }          }
 }  }
   
 void _weyl_mulmdm(vl,mod,p,m0,pr)  void weyl_mulmdm_dup(int mod,MP m0,DP p,DP *pr)
 VL vl;  
 int mod;  
 DP p;  
 MP m0;  
 DP *pr;  
 {  {
         DP r,t,t1;          DP r,t,t1;
         MP m;          MP m;
         int n,l,i;          DL d0;
         static MP *w;          int n,n2,l,i,j,tlen;
           static MP *w,*psum;
           static struct cdlm *tab;
         static int wlen;          static int wlen;
           static int rtlen;
   
         if ( !p )          if ( !p )
                 *pr = 0;                  *pr = 0;
Line 768  DP *pr;
Line 716  DP *pr;
                 }                  }
                 for ( m = BDY(p), i = 0; i < l; m = NEXT(m), i++ )                  for ( m = BDY(p), i = 0; i < l; m = NEXT(m), i++ )
                         w[i] = m;                          w[i] = m;
                 for ( r = 0, i = l-1, n = NV(p); i >= 0; i-- ) {                  n = NV(p); n2 = n>>1;
                         _weyl_mulmmm(vl,mod,w[i],m0,n,&t);                  d0 = m0->dl;
                         _addmd(vl,mod,r,t,&t1); r = t1;  
                   for ( i = 0, tlen = 1; i < n2; i++ )
                           tlen *= d0->d[n2+i]+1;
                   if ( tlen > rtlen ) {
                           if ( tab ) GC_free(tab);
                           if ( psum ) GC_free(psum);
                           rtlen = tlen;
                           tab = (struct cdlm *)MALLOC(rtlen*sizeof(struct cdlm));
                           psum = (MP *)MALLOC(rtlen*sizeof(MP));
                 }                  }
                 bzero(w,l*sizeof(MP));                  bzero(psum,tlen*sizeof(MP));
                   for ( i = l-1; i >= 0; i-- ) {
                           bzero(tab,tlen*sizeof(struct cdlm));
                           weyl_mulmmm_dup(mod,m0,w[i],n,tab,tlen);
                           for ( j = 0; j < tlen; j++ ) {
                                   if ( tab[j].c ) {
                                           NEWMP(m); m->dl = tab[j].d;
                                           C(m) = STOI(tab[j].c); NEXT(m) = psum[j];
                                           psum[j] = m;
                                   }
                           }
                   }
                   for ( j = tlen-1, r = 0; j >= 0; j-- )
                           if ( psum[j] ) {
                                   MKDP(n,psum[j],t); addmd_destructive(mod,r,t,&t1); r = t1;
                           }
                 if ( r )                  if ( r )
                         r->sugar = p->sugar + m0->dl->td;                          r->sugar = p->sugar + m0->dl->td;
                 *pr = r;                  *pr = r;
Line 781  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(vl,mod,m0,m1,n,pr)  void weyl_mulmmm_dup(int mod,MP m0,MP m1,int n,struct cdlm *rtab,int rtablen)
 VL vl;  
 int mod;  
 MP m0,m1;  
 int n;  
 DP *pr;  
 {  {
         MP m,mr,mr0;          int c,c0,c1;
         DP r,t,t1;          DL d,d0,d1,dt;
         int c,c0,c1,cc;          int i,j,a,b,k,l,n2,s,min,curlen;
         DL d,d0,d1;          struct cdlm *p;
         int i,j,a,b,k,l,n2,s,min,h;          static int *ctab;
         static int *tab;          static struct cdlm *tab;
         static int tablen;          static int tablen;
           static struct cdlm *tmptab;
           static int tmptablen;
   
         if ( !m0 || !m1 )          if ( !m0 || !m1 ) {
                 *pr = 0;                  rtab[0].c = 0;
         else {                  rtab[0].d = 0;
                 c0 = ITOS(C(m0)); c1 = ITOS(C(m1));                  return;
                 c = dmar(c0,c1,0,mod);          }
                 d0 = m0->dl; d1 = m1->dl;          c0 = ITOS(C(m0)); c1 = ITOS(C(m1));
                 n2 = n>>1;          c = dmar(c0,c1,0,mod);
           d0 = m0->dl; d1 = m1->dl;
           n2 = n>>1;
           curlen = 1;
   
                 NEWDL(d,n);          NEWDL(d,n);
           if ( n & 1 )
                   /* offset of h-degree */
                   d->td = d->d[n-1] = d0->d[n-1]+d1->d[n-1];
           else
                   d->td = 0;
           rtab[0].c = c;
           rtab[0].d = d;
   
           if ( rtablen > tmptablen ) {
                   if ( tmptab ) GC_free(tmptab);
                   tmptab = (struct cdlm *)MALLOC(rtablen*sizeof(struct cdlm));
                   tmptablen = rtablen;
           }
   
           for ( i = 0; i < n2; i++ ) {
                   a = d0->d[i]; b = d1->d[n2+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 ) {
                           for ( j = 0, p = rtab; j < curlen; j++, p++ ) {
                                   if ( p->c ) {
                                           dt = p->d;
                                           dt->d[i] = a;
                                           dt->d[n2+i] = b;
                                           dt->td += s;
                                   }
                           }
                           curlen *= k+1;
                           continue;
                   }
                   if ( k+1 > tablen ) {
                           if ( tab ) GC_free(tab);
                           if ( ctab ) GC_free(ctab);
                           tablen = k+1;
                           tab = (struct cdlm *)MALLOC(tablen*sizeof(struct cdlm));
                           ctab = (int *)MALLOC(tablen*sizeof(int));
                   }
                   /* compute xi^a*(Di^k*xi^l)*Di^b */
                   min = MIN(k,l);
                   mkwcm(k,l,mod,ctab);
                   bzero(tab,(k+1)*sizeof(struct cdlm));
                   /* n&1 != 0 => homogenized computation; dx-xd=h^2 */
                 if ( n & 1 )                  if ( n & 1 )
                         /* offset of h-degree */                          for ( j = 0; j <= min; j++ ) {
                         d->td = d->d[n-1] = d0->d[n-1]+d1->d[n-1];                                  NEWDL(d,n);
                                   d->d[i] = a-j; d->d[n2+i] = b-j;
                                   d->td = s;
                                   d->d[n-1] = s-(MUL_WEIGHT(a-j,i)+MUL_WEIGHT(b-j,n2+i));
                                   tab[j].d = d;
                                   tab[j].c = ctab[j];
                           }
                 else                  else
                         d->td = 0;                          for ( j = 0; j <= min; j++ ) {
                 NEWMP(mr); mr->c = STOI(c); mr->dl = d; NEXT(mr) = 0;                                  NEWDL(d,n);
                 MKDP(n,mr,r); r->sugar = d->td;                                  d->d[i] = a-j; d->d[n2+i] = b-j;
                                   d->td = MUL_WEIGHT(a-j,i)+MUL_WEIGHT(b-j,n2+i); /* XXX */
                                   tab[j].d = d;
                                   tab[j].c = ctab[j];
                           }
                   comm_mulmd_tab_destructive(mod,n,rtab,curlen,tab,k+1);
                   curlen *= k+1;
           }
   }
   
                 /* homogenized computation; dx-xd=h^2 */  void comm_mulmd_tab_destructive(int mod,int nv,struct cdlm *t,int n,struct cdlm *t1,int n1)
                 for ( i = 0; i < n2; i++ ) {  {
                         a = d0->d[i]; b = d1->d[n2+i];          int i,j;
                         k = d0->d[n2+i]; l = d1->d[i];          struct cdlm *p;
                         /* degree of xi^a*(Di^k*xi^l)*Di^b */          int c;
                         s = a+k+l+b;          DL d;
                         /* compute xi^a*(Di^k*xi^l)*Di^b */  
                         min = MIN(k,l);  
   
                         if ( min+1 > tablen ) {          for ( j = 1, p = t+n; j < n1; j++ ) {
                                 if ( tab ) GC_free(tab);                  c = t1[j].c;
                                 tab = (int *)MALLOC((min+1)*sizeof(int));                  d = t1[j].d;
                                 tablen = min+1;                  if ( !c )
                           break;
                   for ( i = 0; i < n; i++, p++ ) {
                           if ( t[i].c ) {
                                   p->c = dmar(t[i].c,c,0,mod);
                                   adddl_dup(nv,t[i].d,d,&p->d);
                         }                          }
                         mkwcm(k,l,mod,tab);  
                         if ( n & 1 )  
                                 for ( mr0 = 0, j = 0; j <= min; j++ ) {  
                                         NEXTMP(mr0,mr); NEWDL(d,n);  
                                         d->d[i] = l-j+a; d->d[n2+i] = k-j+b;  
                                         d->td = s;  
                                         d->d[n-1] = s-(d->d[i]+d->d[n2+i]);  
                                         mr->c = STOI(tab[j]); mr->dl = d;  
                                 }  
                         else  
                                 for ( mr0 = 0, s = 0, j = 0; j <= min; j++ ) {  
                                         NEXTMP(mr0,mr); NEWDL(d,n);  
                                         d->d[i] = l-j+a; d->d[n2+i] = k-j+b;  
                                         d->td = d->d[i]+d->d[n2+i]; /* XXX */  
                                         s = MAX(s,d->td); /* XXX */  
                                         mr->c = STOI(tab[j]); mr->dl = d;  
                                 }  
                         bzero(tab,(min+1)*sizeof(int));  
                         if ( mr0 )  
                                 NEXT(mr) = 0;  
                         MKDP(n,mr0,t);  
                         if ( t )  
                                 t->sugar = s;  
                         _comm_mulmd(vl,mod,r,t,&t1); r = t1;  
                 }                  }
                 *pr = r;  
         }          }
           c = t1[0].c;
           d = t1[0].d;
           for ( i = 0, p = t; i < n; i++, p++ )
                   if ( t[i].c ) {
                           p->c = dmar(t[i].c,c,0,mod);
                           /* t[i].d += d */
                           adddl_destructive(nv,t[i].d,d);
                   }
 }  }
   
 void _dtop_mod(vl,dvl,p,pr)  void adddl_dup(int n,DL d1,DL d2,DL *dr)
 VL vl,dvl;  
 DP p;  
 P *pr;  
 {  {
         int n,i;          DL dt;
         DL d;          int i;
         MP m;  
         P r,s,t,u,w;  
         Q q;  
         VL tvl;  
   
           NEWDL(dt,n);
           *dr = dt;
           dt->td = d1->td + d2->td;
           for ( i = 0; i < n; 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;
   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_nf(NODE b,ND g,ND *ps,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 < 1024; 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 < 1024; 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 < 1024; 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 )          if ( !p )
                 *pr = 0;                  return 0;
         else {          else {
                 for ( n = p->nv, m = BDY(p), s = 0; m; m = NEXT(m) ) {                  for ( i = 0, m = BDY(p); m; m = NEXT(m), i++ );
                         i = ITOS(m->c); STOQ(i,q); t = (P)q;                  return i;
                         for ( i = 0, d = m->dl, tvl = dvl;          }
                                 i < n; tvl = NEXT(tvl), i++ ) {  }
                                 MKV(tvl->v,r); STOQ(d->d[i],q); pwrp(vl,r,q,&u);  
                                 mulp(vl,t,u,&w); t = w;  INLINE int ndl_reducible(unsigned int *d1,unsigned int *d2)
   {
           unsigned int u1,u2;
           int i;
   
           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;
                         }                          }
                         addp(vl,s,t,&u); s = u;                          return 1;
                 }                          break;
                 *pr = s;                  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:
                           error("ndl_reducible : not implemented yet");
         }          }
 }  }
   
 void _dp_red_mod(p1,p2,mod,rp)  INLINE void ndl_lcm(unsigned int *d1,unsigned *d2,unsigned int *d)
 DP p1,p2;  
 int mod;  
 DP *rp;  
 {  {
         int i,n;          unsigned int t1,t2,u,u1,u2;
         DL d1,d2,d;          int i;
         MP m;  
         DP t,s;  
         int c,c1;  
   
         n = p1->nv; d1 = BDY(p1)->dl; d2 = BDY(p2)->dl;          switch ( nd_bpe ) {
         NEWDL(d,n); d->td = d1->td - d2->td;                  case 4:
         for ( i = 0; i < n; i++ )                          for ( i = 0; i < nd_wpd; i++ ) {
                 d->d[i] = d1->d[i]-d2->d[i];                                  u1 = d1[i]; u2 = d2[i];
         c = invm(ITOS(BDY(p2)->c),mod); c1 = dmar(c,ITOS(BDY(p1)->c),0,mod);                                  t1 = (u1&0xf0000000); t2 = (u2&0xf0000000); u = t1>t2?t1:t2;
         NEWMP(m); m->dl = d; m->c = STOI(mod-c1); NEXT(m) = 0;                                  t1 = (u1&0xf000000); t2 = (u2&0xf000000); u |= t1>t2?t1:t2;
         MKDP(n,m,s); s->sugar = d->td;                                  t1 = (u1&0xf00000); t2 = (u2&0xf00000); u |= t1>t2?t1:t2;
         _mulmd(CO,mod,s,p2,&t); _addmd(CO,mod,p1,t,rp);                                  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:
                           error("ndl_lcm : not implemented yet");
           }
 }  }
   
 void _dp_mod(p,mod,subst,rp)  INLINE int ndl_td(unsigned int *d)
 DP p;  
 int mod;  
 NODE subst;  
 DP *rp;  
 {  {
         MP m,mr,mr0;          unsigned int t,u;
         P t,s;          int i;
         NODE tn;  
   
           switch ( nd_bpe ) {
                   case 4:
                           for ( t = 0, i = 0; i < nd_wpd; i++ ) {
                                   u = d[i];
                                   t += ((u&0xf0000000)>>28)+((u&0xf000000)>>24)
                                           +((u&0xf00000)>>20)+((u&0xf0000)>>16)
                                           +((u&0xf000)>>12)+((u&0xf00)>>8)+((u&0xf0)>>4)+(u&0xf);
                           }
                           break;
                   case 8:
                           for ( t = 0, i = 0; i < nd_wpd; i++ ) {
                                   u = d[i];
                                   t += ((u&0xff000000)>>24)+((u&0xff0000)>>16)
                                           +((u&0xff00)>>8)+(u&0xff);
                           }
                           break;
                   case 16:
                           for ( t = 0, i = 0; i < nd_wpd; i++ ) {
                                   u = d[i];
                                   t += ((u&0xffff0000)>>16)+(u&0xffff);
                           }
                           break;
                   case 32:
                           for ( t = 0, i = 0; i < nd_wpd; i++ )
                                   t += d[i];
                           break;
                   default:
                           error("ndl_td : not implemented yet");
           }
           return t;
   }
   
   INLINE int ndl_compare(unsigned int *d1,unsigned int *d2)
   {
           int i;
   
           for ( i = 0; i < nd_wpd; i++ )
                   if ( d1[i] > d2[i] )
                           return is_rlex ? -1 : 1;
                   else if ( d1[i] < d2[i] )
                           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];
   }
   
   INLINE 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];
   }
   
   INLINE int ndl_disjoint(unsigned int *d1,unsigned int *d2)
   {
           unsigned int t1,t2,u,u1,u2;
           int i;
   
           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:
                           error("ndl_disjoint : not implemented yet");
           }
   }
   
   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;
           }
   }
   
   INLINE 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 )          if ( !p )
                 *rp = 0;                  return 0;
         else {          else {
                 for ( mr0 = 0, m = BDY(p); m; m = NEXT(m) ) {                  n = NV(p); m = BDY(p);
                         for ( tn = subst, s = m->c; tn; tn = NEXT(NEXT(tn)) ) {                  d = m0->dl; td = m0->td; c = C(m0);
                                 substp(CO,s,BDY(tn),BDY(NEXT(tn)),&t);                  mr0 = 0;
                                 s = t;                  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;
           }
   }
   
   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;
                         }                          }
                         ptomp(mod,s,&t);                          if ( cur->td > td2 )
                         if ( t ) {                                  c = 1;
                                 NEXTMP(mr0,mr); mr->c = STOI(CONT((MQ)t)); mr->dl = m->dl;                          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;
                         }                          }
                 }                  }
                 if ( mr0 ) {                  FREENM(new);
                         NEXT(mr) = 0; MKDP(p->nv,mr0,*rp); (*rp)->sugar = p->sugar;                  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;
   }
   
   #if 1
   ND nd_nf(NODE b,ND g,ND *ps,int full)
   {
           ND u,p,d,red;
           NODE l;
           NM m,mrd;
           int sugar,psugar,n,h_reducible;
   
           if ( !g ) {
                   return 0;
           }
           sugar = g->sugar;
           n = g->nv;
           for ( d = 0; g; ) {
                   for ( h_reducible = 0, l = b; l; l = NEXT(l) ) {
                           p = ps[(int)BDY(l)];
                           if ( HTD(g)>=HTD(p) && ndl_reducible(HDL(g),HDL(p)) ) {
                                   h_reducible = 1;
                                   psugar = HTD(g)-HTD(p) + p->sugar;
   #if 0
                                   red = nd_reducer(g,p);
                                   g = nd_add(g,red);
   #else
                                   g = nd_reduce(g,p);
   #endif
                                   sugar = MAX(sugar,psugar);
                                   if ( !g ) {
                                           if ( d )
                                                   d->sugar = sugar;
                                           return d;
                                   }
                                   break;
                           }
                   }
                   if ( !h_reducible ) {
                           /* head term is not reducible */
                           if ( !full ) {
                                   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;
                                   }
                                   if ( d ) {
                                           for ( mrd = BDY(d); NEXT(mrd); mrd = NEXT(mrd) );
                                           NEXT(mrd) = m;
                                   } else {
                                           MKND(n,m,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                  } else
                         *rp = 0;                          g->body[j] = nd_remove_head(gj);
         }          }
 }  }
   
 void _dp_monic(p,mod,rp)  ND normalize_pbucket(PGeoBucket g)
 DP p;  
 int mod;  
 DP *rp;  
 {  {
         MP m,mr,mr0;          int i;
         int c,c1;          ND r,t;
         NODE tn;  
   
         if ( !p )          r = 0;
                 *rp = 0;          for ( i = 0; i <= g->m; i++ )
                   r = nd_add(r,g->body[i]);
           return r;
   }
   
   ND nd_nf(NODE b,ND g,ND *ps,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];
                   for ( h_reducible = 0, l = b; l; l = NEXT(l) ) {
                           p = ps[(int)BDY(l)];
                           if ( ndl_reducible(HDL(g),HDL(p)) ) {
                                   h_reducible = 1;
                                   psugar = HTD(g)-HTD(p) + p->sugar;
                                   red = nd_reducer(g,p);
                                   bucket->body[h] = nd_remove_head(g);
                                   red = nd_remove_head(red);
                                   add_pbucket(bucket,red);
                                   sugar = MAX(sugar,psugar);
                                   break;
                           }
                   }
                   if ( !h_reducible ) {
                           /* head term is not reducible */
                           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(gall,h,nps,!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 {          else {
                 c = invm(ITOS(BDY(p)->c),mod);                  nd = d;
                 for ( mr0 = 0, m = BDY(p); m; m = NEXT(m) ) {                  while ( NEXT(nd) )
                         c1 = dmar(ITOS(m->c),c,0,mod);                          nd = NEXT(nd);
                         NEXTMP(mr0,mr); mr->c = STOI(c1); mr->dl = m->dl;                  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);
                 }                  }
                 NEXT(mr) = 0; MKDP(p->nv,mr0,*rp); (*rp)->sugar = p->sugar;  
         }          }
           return head;
 }  }
   
 void _dp_sp_mod(p1,p2,mod,rp)  ND_pairs crit_M( ND_pairs d1 )
 DP p1,p2;  
 int mod;  
 DP *rp;  
 {  {
         int i,n,td;          ND_pairs e,d2,d3,dd,p;
         int *w;          unsigned int *id,*jd;
         DL d1,d2,d;          int itd,jtd;
         MP m;  
         DP t,s,u;  
   
         n = p1->nv; d1 = BDY(p1)->dl; d2 = BDY(p2)->dl;          for ( dd = 0, e = d1; e; e = d3 ) {
         w = (int *)ALLOCA(n*sizeof(int));                  if ( !(d2 = NEXT(e)) ) {
         for ( i = 0, td = 0; i < n; i++ ) {                          NEXT(e) = dd;
                 w[i] = MAX(d1->d[i],d2->d[i]); td += w[i];                          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;
                   }
         }          }
         NEWDL(d,n); d->td = td - d1->td;          return dd;
         for ( i = 0; i < n; i++ )  
                 d->d[i] = w[i] - d1->d[i];  
         NEWMP(m); m->dl = d; m->c = BDY(p2)->c; NEXT(m) = 0;  
         MKDP(n,m,s); s->sugar = d->td; _mulmd(CO,mod,s,p1,&t);  
         NEWDL(d,n); d->td = td - d2->td;  
         for ( i = 0; i < n; i++ )  
                 d->d[i] = w[i] - d2->d[i];  
         NEWMP(m); m->dl = d; m->c = STOI(mod - ITOS(BDY(p1)->c)); NEXT(m) = 0;  
         MKDP(n,m,s); s->sugar = d->td; _mulmd(CO,mod,s,p2,&u);  
         _addmd(CO,mod,t,u,rp);  
 }  }
   
 void _dp_sp_component_mod(p1,p2,mod,f1,f2)  ND_pairs crit_F( ND_pairs d1 )
 DP p1,p2;  
 int mod;  
 DP *f1,*f2;  
 {  {
         int i,n,td;          ND_pairs rest, head;
         int *w;          ND_pairs last, p, r, w;
         DL d1,d2,d;          int s;
         MP m;  
         DP t,s,u;  
   
         n = p1->nv; d1 = BDY(p1)->dl; d2 = BDY(p2)->dl;          for ( head = last = 0, p = d1; NEXT(p); ) {
         w = (int *)ALLOCA(n*sizeof(int));                  r = w = equivalent_pairs(p,&rest);
         for ( i = 0, td = 0; i < n; i++ ) {                  s = r->sugar;
                 w[i] = MAX(d1->d[i],d2->d[i]); td += w[i];                  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;
         }          }
         NEWDL(d,n); d->td = td - d1->td;          if ( !last ) return p;
         for ( i = 0; i < n; i++ )          NEXT(last) = p;
                 d->d[i] = w[i] - d1->d[i];          return head;
         NEWMP(m); m->dl = d; m->c = BDY(p2)->c; NEXT(m) = 0;  
         MKDP(n,m,s); s->sugar = d->td; _mulmd(CO,mod,s,p1,f1);  
         NEWDL(d,n); d->td = td - d2->td;  
         for ( i = 0; i < n; i++ )  
                 d->d[i] = w[i] - d2->d[i];  
         NEWMP(m); m->dl = d; m->c = BDY(p1)->c; NEXT(m) = 0;  
         MKDP(n,m,s); s->sugar = d->td; _mulmd(CO,mod,s,p2,f2);  
 }  }
   
 void _printdp(d)  int crit_2( int dp1, int dp2 )
 DP d;  
 {  {
         int n,i;          return ndl_disjoint(HDL(nps[dp1]),HDL(nps[dp2]));
         MP m;  }
   
   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_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;
           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;          DL dl;
           int *d;
           int i;
   
         if ( !d ) {          NEWDL(dl,n);
                 printf("0"); return;          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);
         }          }
         for ( n = d->nv, m = BDY(d); m; m = NEXT(m) ) {          NEXT(m) = 0;
                 printf("%d*<<",ITOS(m->c));          MKND(n,m0,d);
                 for ( i = 0, dl = m->dl; i < n-1; i++ )          d->nv = n;
                         printf("%d,",dl->d[i]);          d->sugar = p->sugar;
                 printf("%d",dl->d[i]);          return d;
                 printf(">>");  }
                 if ( NEXT(m) )  
                         printf("+");  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.5  
changed lines
  Added in v.1.11

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