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

File: [local] / OpenXM_contrib2 / asir2018 / engine / F.c (download)

Revision 1.3, Tue Oct 6 06:31:19 2020 UTC (3 years, 5 months ago) by noro
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +3 -2 lines

Removed warnings.

/*
 * Copyright (c) 1994-2000 FUJITSU LABORATORIES LIMITED 
 * All rights reserved.
 * 
 * FUJITSU LABORATORIES LIMITED ("FLL") hereby grants you a limited,
 * non-exclusive and royalty-free license to use, copy, modify and
 * redistribute, solely for non-commercial and non-profit purposes, the
 * computer program, "Risa/Asir" ("SOFTWARE"), subject to the terms and
 * conditions of this Agreement. For the avoidance of doubt, you acquire
 * only a limited right to use the SOFTWARE hereunder, and FLL or any
 * third party developer retains all rights, including but not limited to
 * copyrights, in and to the SOFTWARE.
 * 
 * (1) FLL does not grant you a license in any way for commercial
 * purposes. You may use the SOFTWARE only for non-commercial and
 * non-profit purposes only, such as academic, research and internal
 * business use.
 * (2) The SOFTWARE is protected by the Copyright Law of Japan and
 * international copyright treaties. If you make copies of the SOFTWARE,
 * with or without modification, as permitted hereunder, you shall affix
 * to all such copies of the SOFTWARE the above copyright notice.
 * (3) An explicit reference to this SOFTWARE and its copyright owner
 * shall be made on your publication or presentation in any form of the
 * results obtained by use of the SOFTWARE.
 * (4) In the event that you modify the SOFTWARE, you shall notify FLL by
 * 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
 * SOFTWARE.
 * 
 * THE SOFTWARE IS PROVIDED AS IS WITHOUT ANY WARRANTY OF ANY KIND. FLL
 * MAKES ABSOLUTELY NO WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY, AND
 * EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT OF THIRD PARTIES'
 * RIGHTS. NO FLL DEALER, AGENT, EMPLOYEES IS AUTHORIZED TO MAKE ANY
 * MODIFICATIONS, EXTENSIONS, OR ADDITIONS TO THIS WARRANTY.
 * UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, TORT, CONTRACT,
 * OR OTHERWISE, SHALL FLL BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, PUNITIVE OR CONSEQUENTIAL
 * DAMAGES OF ANY CHARACTER, INCLUDING, WITHOUT LIMITATION, DAMAGES
 * ARISING OUT OF OR RELATING TO THE SOFTWARE OR THIS AGREEMENT, DAMAGES
 * FOR LOSS OF GOODWILL, WORK STOPPAGE, OR LOSS OF DATA, OR FOR ANY
 * DAMAGES, EVEN IF FLL SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF
 * SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. EVEN IF A PART
 * OF THE SOFTWARE HAS BEEN DEVELOPED BY A THIRD PARTY, THE THIRD PARTY
 * DEVELOPER SHALL HAVE NO LIABILITY IN CONNECTION WITH THE USE,
 * PERFORMANCE OR NON-PERFORMANCE OF THE SOFTWARE.
 *
 * $OpenXM: OpenXM_contrib2/asir2018/engine/F.c,v 1.3 2020/10/06 06:31:19 noro Exp $
*/
#include "ca.h"
#include <math.h>

int use_new_hensel;

void fctrp(VL vl,P f,DCP *dcp)
{
  VL nvl;
  DCP dc;

  if ( !f || NUM(f) ) {
    NEWDC(dc); COEF(dc) = f; DEG(dc) = ONE;
    NEXT(dc) = 0; *dcp = dc;
    return;
  } else if ( !qpcheck((Obj)f) )
    error("fctrp : invalid argument");  
  else {
    clctv(vl,f,&nvl);
    if ( !NEXT(nvl) ) 
      ufctr(f,1,dcp);
    else
      mfctr(nvl,f,dcp);
  }
}

void fctr_wrt_v_p(VL vl,P f,V v,DCP *dcp)
{
  VL nvl;
  DCP dc;

  if ( !f || NUM(f) ) {
    NEWDC(dc); COEF(dc) = f; DEG(dc) = ONE;
    NEXT(dc) = 0; *dcp = dc;
    return;
  } else if ( !qpcheck((Obj)f) )
    error("fctrp : invalid argument");  
  else {
    clctv(vl,f,&nvl);
    if ( !NEXT(nvl) ) 
      ufctr(f,1,dcp);
    else
      mfctr_wrt_v(nvl,f,v,dcp);
  }
}

void homfctr(VL vl,P g,DCP *dcp)
{
  P s,t,u,f,h,x;
  Z e;
  int d,d0;
  DCP dc,dct;

  substp(vl,g,vl->v,(P)ONE,&t); fctrp(vl,t,&dc); MKV(vl->v,x);
  for ( dct = dc; dct; dct = NEXT(dct) )
    if ( !NUM(dc->c) ) {
      for ( s = 0, f = dc->c, d = d0 = homdeg(f); f; d = homdeg(f) ) {
        exthp(vl,f,d,&h); STOZ(d0-d,e); pwrp(vl,x,e,&t);
        mulp(vl,t,h,&u); addp(vl,s,u,&t); s = t;
        subp(vl,f,h,&u); f = u;
      }
      dc->c = s;
    }
  *dcp = dc;
}

void mfctr(VL vl,P f,DCP *dcp)
{
  DCP dc,dc0,dct,dcs,dcr;
  P p,pmin,ppmin,cmin,t;
  VL mvl;
  Q c;

  ptozp(f,1,&c,&p);
  NEWDC(dc0); dc = dc0; COEF(dc) = (P)c; DEG(dc) = ONE; NEXT(dc) = 0;
  msqfr(vl,p,&dct);
  for ( ; dct; dct = NEXT(dct) ) {
    mindegp(vl,COEF(dct),&mvl,&pmin); 
#if 0
    minlcdegp(vl,COEF(dct),&mvl,&pmin); 
    min_common_vars_in_coefp(vl,COEF(dct),&mvl,&pmin); 
#endif
    pcp(mvl,pmin,&ppmin,&cmin);
    if ( !NUM(cmin) ) {
      mfctr(mvl,cmin,&dcs);
      for ( dcr = NEXT(dcs); dcr; dcr = NEXT(dcr) ) {
        DEG(dcr) = DEG(dct);
        reorderp(vl,mvl,COEF(dcr),&t); COEF(dcr) = t;
      }
      for ( ; NEXT(dc); dc = NEXT(dc) );
      NEXT(dc) = NEXT(dcs);
    }
    mfctrmain(mvl,ppmin,&dcs);
    for ( dcr = dcs; dcr; dcr = NEXT(dcr) ) {
      DEG(dcr) = DEG(dct);
      reorderp(vl,mvl,COEF(dcr),&t); COEF(dcr) = t;
    }
    for ( ; NEXT(dc); dc = NEXT(dc) );
    NEXT(dc) = dcs;
  }
  adjsgn(f,dc0); *dcp = dc0;
}

void mfctr_wrt_v(VL vl,P f,V v,DCP *dcp)
{
  DCP dc,dc0,dct,dcs,dcr;
  P p,pmin,ppmin,cmin,t;
  VL nvl,mvl;
  Q c;

  ptozp(f,1,&c,&p);
  NEWDC(dc0); dc = dc0; COEF(dc) = (P)c; DEG(dc) = ONE; NEXT(dc) = 0;
  msqfr(vl,p,&dct);
  for ( ; dct; dct = NEXT(dct) ) {
    clctv(vl,COEF(dct),&nvl);
    reordvar(nvl,v,&mvl);
    reorderp(mvl,vl,COEF(dct),&pmin);
    pcp(mvl,pmin,&ppmin,&cmin);
    if ( !NUM(cmin) ) {
      mfctrmain(mvl,cmin,&dcs);
      for ( dcr = dcs; dcr; dcr = NEXT(dcr) ) {
        DEG(dcr) = DEG(dct);
        reorderp(vl,mvl,COEF(dcr),&t); COEF(dcr) = t;
      }
      for ( ; NEXT(dc); dc = NEXT(dc) );
      NEXT(dc) = dcs;
    }
    mfctrmain(mvl,ppmin,&dcs);
    for ( dcr = dcs; dcr; dcr = NEXT(dcr) ) {
      DEG(dcr) = DEG(dct);
      reorderp(vl,mvl,COEF(dcr),&t); COEF(dcr) = t;
    }
    for ( ; NEXT(dc); dc = NEXT(dc) );
    NEXT(dc) = dcs;
  }
  adjsgn(f,dc0); *dcp = dc0;
}

#if 0
void adjsgn(P p,DCP dc)
{
  int sgn;
  DCP dct;
  P c;

  for ( dct = dc, sgn = headsgn(p); dct; dct = NEXT(dct) )
    if ( !EVENN(NM(dct->d)) )
      sgn *= headsgn(COEF(dct));
  if ( sgn < 0 ) {
    chsgnp(COEF(dc),&c); COEF(dc) = c;
  }
}
#else
void adjsgn(P p,DCP dc)
{     
  DCP dct;
  P c;

  if ( headsgn(COEF(dc)) != headsgn(p) ) {
    chsgnp(COEF(dc),&c); COEF(dc) = c;
  }
  for ( dct = NEXT(dc); dct; dct = NEXT(dct) )
    if ( headsgn(COEF(dct)) < 0 ) {
      chsgnp(COEF(dct),&c); COEF(dct) = c;
    }
}
#endif

int headsgn(P p)
{
  if ( !p )
    return 0;
  else {
    while ( !NUM(p) )
      p = COEF(DC(p));
    return sgnq((Q)p);
  }
}

void fctrwithmvp(VL vl,P f,V v,DCP *dcp)
{
  VL nvl;
  DCP dc;

  if ( NUM(f) ) {
    NEWDC(dc); COEF(dc) = f; DEG(dc) = ONE;
    NEXT(dc) = 0; *dcp = dc;
    return;
  }

  clctv(vl,f,&nvl);
  if ( !NEXT(nvl) ) 
    ufctr(f,1,dcp);
  else
    mfctrwithmv(nvl,f,v,dcp);
}

void mfctrwithmv(VL vl,P f,V v,DCP *dcp)
{
  DCP dc,dc0,dct,dcs,dcr;
  P p,pmin,ppmin,cmin,t;
  VL mvl;
  Q c;

  ptozp(f,1,&c,&p);
  NEWDC(dc0); dc = dc0; COEF(dc) = (P)c; DEG(dc) = ONE; NEXT(dc) = 0;
  msqfr(vl,p,&dct);
  for ( ; dct; dct = NEXT(dct) ) {
    if ( !v )
      mindegp(vl,COEF(dct),&mvl,&pmin);
    else {
      reordvar(vl,v,&mvl); reorderp(mvl,vl,COEF(dct),&pmin);
    }
    pcp(mvl,pmin,&ppmin,&cmin);
    if ( !NUM(cmin) ) {
      mfctrmain(mvl,cmin,&dcs);
      for ( dcr = dcs; dcr; dcr = NEXT(dcr) ) {
        DEG(dcr) = DEG(dct);
        reorderp(vl,mvl,COEF(dcr),&t); COEF(dcr) = t;
      }
      for ( ; NEXT(dc); dc = NEXT(dc) );
      NEXT(dc) = dcs;
    }
    mfctrmain(mvl,ppmin,&dcs);
    for ( dcr = dcs; dcr; dcr = NEXT(dcr) ) {
      DEG(dcr) = DEG(dct);
      reorderp(vl,mvl,COEF(dcr),&t); COEF(dcr) = t;
    }
    for ( ; NEXT(dc); dc = NEXT(dc) );
    NEXT(dc) = dcs;
  }
  *dcp = dc0;
}

void ufctr(P f,int hint,DCP *dcp)
{
  P p,c;
  DCP dc,dct,dcs,dcr;

  ptozp(f,sgnq((Q)UCOEF(f)),(Q *)&c,&p);
  NEWDC(dc); COEF(dc) = c; DEG(dc) = ONE; NEXT(dc) = 0;
  usqp(p,&dct);
  for ( *dcp = dc; dct; dct = NEXT(dct) ) {
    ufctrmain(COEF(dct),hint,&dcs);
    for ( dcr = dcs; dcr; dcr = NEXT(dcr) ) 
      DEG(dcr) = DEG(dct);
    for ( ; NEXT(dc); dc = NEXT(dc) );
    NEXT(dc) = dcs;
  }
}

void mfctrmain(VL vl,P p,DCP *dcp)
{
  int i,j,k,*win,np,x;
  VL nvl,tvl;
  VN vn,vnt,vn1;
  P p0,f,g,f0,g0,s,t,lp,m;
  P *fp0,*fpt,*l,*tl;
  DCP dc,dc0,dcl;
  int count,nv;
  int *nonzero;

  if ( !cmpz(DEG(DC(p)),ONE) ) {
    NEWDC(dc); DEG(dc) = ONE; COEF(dc) = p; NEXT(dc) = 0;
    *dcp = dc; return;
  }
  lp = LC(p); fctrp(vl,lp,&dcl); clctv(vl,p,&nvl);
  for ( nv = 0, tvl = nvl; tvl; tvl = NEXT(tvl), nv++);
  W_CALLOC(nv,struct oVN,vn); W_CALLOC(nv,struct oVN,vnt);
  W_CALLOC(nv,struct oVN,vn1);
  W_CALLOC(nv,int,nonzero);

  for ( i = 0, tvl = NEXT(nvl); tvl; tvl = NEXT(tvl), i++ ) 
    vn1[i].v = vn[i].v = tvl->v;
  vn1[i].v = vn[i].v = 0;

  /* determine a heuristic bound of deg(GCD(p,p')) */
  while ( 1 ) {
    for ( i = 0; vn1[i].v; i++ )
      vn1[i].n = ((unsigned int)random())%256+1;
    substvp(nvl,LC(p),vn1,&p0);
    if ( p0 ) {
      substvp(nvl,p,vn1,&p0);
      if ( sqfrchk(p0) ) {
        ufctr(p0,1,&dc0); 
        if ( NEXT(NEXT(dc0)) == 0 ) {
          NEWDC(dc); DEG(dc) = ONE; COEF(dc) = p; NEXT(dc) = 0;
          *dcp = dc;
          return;
        } else {
          for ( dc0 = NEXT(dc0), np = 0; dc0; dc0 = NEXT(dc0), np++ );
          break;
        }
      }
    }
  }
  
  /* determine the position of variables which is not allowed to
     be set to 0 */
  for ( i = 0; vn1[i].v; i++ ) {
    x = vn1[i].n; vn1[i].n = 0;
    substvp(nvl,LC(p),vn1,&p0);
    if ( !p0 )
      vn1[i].n = x;
    else {
      substvp(nvl,p,vn1,&p0);
      if ( !sqfrchk(p0) )
        vn1[i].n = x;
      else {
        ufctr(p0,1,&dc0); 
        for ( dc0 = NEXT(dc0), j = 0; dc0; dc0 = NEXT(dc0), j++ );
        if ( j > np )
          vn1[i].n = x;
      }
    }
  }
  for ( i = 0; vn1[i].v; i++ )
    if (vn1[i].n )
      nonzero[i] = 1;

  count = 0;
  while  ( 1 ) {
    while ( 1 ) {
      count++;
      for ( i = 0, j = 0; vn[i].v; i++ ) 
        if ( vn[i].n )
          vnt[j++].v = (V)((long)i);
      vnt[j].n = 0; mulsgn(vn,vnt,j,vn1);
      for ( i = 0; vn1[i].v; i++ )
        if ( vn1[i].n ) {
          if ( vn1[i].n > 0 )
            vn1[i].n = sprime[vn1[i].n];
          else
            vn1[i].n = -sprime[-vn1[i].n];
        }
      if ( valideval(nvl,dcl,vn1) ) {
        substvp(nvl,p,vn1,&p0);
        if ( sqfrchk(p0) ) {
          ufctr(p0,1,&dc0); 
          if ( NEXT(NEXT(dc0)) == 0 ) {
            NEWDC(dc); DEG(dc) = ONE; COEF(dc) = p; NEXT(dc) = 0;
            *dcp = dc;
            return;
          } else {
            for ( dc = NEXT(dc0), i = 0; dc; dc = NEXT(dc), i++ );
            if ( i <= np )
              goto MAIN;
            if ( i < np )
              np = i;
          }
        }
      }
      if ( nextbin(vnt,j) ) 
        break;
    }
    while ( 1 ) {
      next(vn);
      for ( i = 0; vn[i].v; i++ )
        if ( nonzero[i] && !vn[i].n )
          break;
      if ( !vn[i].v )
        break;
    }
  }
MAIN :
#if 0
  for ( i = 0; vn1[i].v; i++ )
    fprintf(stderr,"%d ",vn1[i].n);
  fprintf(stderr,"\n");
#endif
  for ( np = 0, dc = NEXT(dc0); dc; dc = NEXT(dc), np++ );
  fp0 = (P *)ALLOCA((np + 1)*sizeof(P)); 
  fpt = (P *)ALLOCA((np + 1)*sizeof(P));
  l = tl = (P *)ALLOCA((np + 1)*sizeof(P));
  for ( i = 1, dc = NEXT(dc0); dc; i++, dc = NEXT(dc) ) 
    fp0[i-1] = COEF(dc);
#if 0
  sort_by_deg(np,fp0,fpt);
  sort_by_deg_rev(np-1,fpt+1,fp0+1);
#endif
#if 0
  sort_by_deg_rev(np,fp0,fpt); fp0[0] = fpt[0];
  sort_by_deg(np-1,fpt+1,fp0+1); fp0[np] = 0;
#endif
  fp0[np] = 0;
  win = W_ALLOC(np + 1); f = p; divsp(vl,p0,COEF(dc0),&f0);
  for ( k = 1, win[0] = 1, --np; ; ) {
    P h0,lcg,lch;
    Q c;

    g0 = fp0[win[0]];
    for ( i = 1; i < k; i++ ) {
      mulp(vl,g0,fp0[win[i]],&m); g0 = m;
    }
    mulq((Q)LC(g0),(Q)COEF(dc0),&c); estimatelc(nvl,(Z)c,dcl,vn1,&lcg);
    divsp(nvl,f0,g0,&h0);
    mulq((Q)LC(h0),(Q)COEF(dc0),&c); estimatelc(nvl,(Z)c,dcl,vn1,&lch);
    mfctrhen2(nvl,vn1,f,f0,g0,h0,lcg,lch,&g);    
    if ( g ) {
      *tl++ = g; divsp(vl,f,g,&t); 
      f = t; divsp(vl,f0,g0,&t); ptozp(t,1,(Q *)&s,&f0); 
      for ( i = 0; i < k - 1; i++ ) 
        for ( j = win[i] + 1; j < win[i + 1]; j++ ) 
          fp0[j - i - 1] = fp0[j];
      for ( j = win[k - 1] + 1; j <= np; j++ )   
          fp0[j - k] = fp0[j];
      if ( ( np -= k ) < k ) break;
      if ( np - win[0] + 1 < k ) 
        if ( ++k <= np ) {
          for ( i = 0; i < k; i++ ) win[i] = i + 1;
          continue;
        } else
          break;
      else for ( i = 1; i < k; i++ ) win[i] = win[0] + i;
    } else {
      if ( ncombi(1,np,k,win) == 0 ) {
        if ( k == np ) break;
        else {
          for ( i = 0, ++k; i < k; i++ ) win[i] = i + 1;
        }
      }
    }
  }
  *tl++ = f; *tl = 0;
  for ( dc0 = 0; *l; l++ ) {
    NEXTDC(dc0,dc); DEG(dc) = ONE; COEF(dc) = *l;
  }
  NEXT(dc) = 0; *dcp = dc0;
}

void ufctrmain(P p,int hint,DCP *dcp)
{
  ML list;
  DCP dc;

  if ( NUM(p) || (UDEG(p) == 1) ) {
    NEWDC(dc); DEG(dc) = ONE; COEF(dc) = p; NEXT(dc) = 0;
    *dcp = dc;
  } else if ( iscycm(p) )
    cycm(VR(p),UDEG(p),dcp);
  else if ( iscycp(p) )
    cycp(VR(p),UDEG(p),dcp);
  else {
    if ( use_new_hensel )
      hensel2(5,5,p,&list);
    else
      hensel(5,5,p,&list);
    if ( list->n == 1 ) {
      NEWDC(dc); DEG(dc) = ONE; COEF(dc) = p; NEXT(dc) = 0;
      *dcp = dc;
    } else 
      dtest(p,list,hint,dcp);
  }
}

void cycm(V v,int n,DCP *dcp)
{
  register int i,j;
  struct oMF *mfp;
  DCP dc,dc0;

  if ( n == 1 ) {
    NEWDC(dc); mkssum(v,1,1,-1,&COEF(dc)); DEG(dc) = ONE;
  } else {
    mfp = (struct oMF *) ALLOCA((n+1)*sizeof(struct oMF));
    bzero((char *)mfp,(int)(sizeof(struct oMF)*(n+1)));
    for ( i = 1, j = 0; i <= n; i++ )
      if ( !(n%i) ) mfp[j++].m = i;
    mkssum(v,1,1,-1,&mfp[0].f);
    for ( i = 1; i < j; i++ )
      calcphi(v,i,mfp);
    for ( dc0 = 0, i = 0; i < j; i++ ) {
      NEXTDC(dc0,dc); COEF(dc) = mfp[i].f; DEG(dc) = ONE;
    }
  }
  NEXT(dc) = 0; *dcp = dc0;
}

void cycp(V v,int n,DCP *dcp)
{
  register int i,j;
  int n0;
  struct oMF *mfp;
  DCP dc,dc0;

  if ( n == 1 ) {
    NEWDC(dc); mkssum(v,1,1,1,&COEF(dc)); DEG(dc) = ONE;
  } else {
    n0 = n; n *= 2;
    mfp = (struct oMF *) ALLOCA((n+1)*sizeof(struct oMF));
    bzero((char *)mfp,(int)(sizeof(struct oMF)*(n+1)));
    for ( i = 1, j = 0; i <= n; i++ )
      if ( !(n%i) ) mfp[j++].m = i;
    mkssum(v,1,1,-1,&mfp[0].f);
    for ( i = 1; i < j; i++ )
      calcphi(v,i,mfp);
    for ( dc0 = 0, i = 0; i < j; i++ ) 
      if ( n0 % mfp[i].m ) {
        NEXTDC(dc0,dc); COEF(dc) = mfp[i].f; DEG(dc) = ONE;
      }
  }
  NEXT(dc) = 0; *dcp = dc0;
}

void calcphi(V v,int n,struct oMF *mfp)
{
  register int i,m;
  P t,s,tmp;

  for ( t = (P)ONE, i = 0, m = mfp[n].m; i < n; i++ )
    if ( !(m%mfp[i].m) ) {
      mulp(CO,t,mfp[i].f,&s); t = s;
    }
  mkssum(v,m,1,-1,&s); udivpz(s,t,&mfp[n].f,&tmp);
  if ( tmp ) 
    error("calcphi: cannot happen");
}

void mkssum(V v,int e,int s,int sgn,P *r)
{
  register int i,sgnt;
  DCP dc,dc0;
  Z q;

  for ( dc0 = 0, i = s, sgnt = 1; i >= 0; i--, sgnt *= sgn ) {
    if ( !dc0 ) {
      NEWDC(dc0); dc = dc0;
    } else {
      NEWDC(NEXT(dc)); dc = NEXT(dc);
    }
    STOZ(i*e,DEG(dc)); STOZ(sgnt,q),COEF(dc) = (P)q;
  }
  NEXT(dc) = 0; MKP(v,dc0,*r);
}

int iscycp(P f)
{
  DCP dc;
  dc = DC(f);

  if ( !UNIQ((Q)COEF(dc)) ) 
    return ( 0 );
  dc = NEXT(dc);
  if ( NEXT(dc) || DEG(dc) || !UNIQ((Q)COEF(dc)) ) 
    return ( 0 );
  return ( 1 );  
}

int iscycm(P f)
{
  DCP dc;

  dc = DC(f);
  if ( !UNIQ((Q)COEF(dc)) ) 
    return ( 0 );
  dc = NEXT(dc);
  if ( NEXT(dc) || DEG(dc) || !MUNIQ((Q)COEF(dc)) ) 
    return ( 0 );
  return ( 1 );  
}

void sortfs(DCP *dcp)
{
  int i,k,n,k0,d;
  DCP dc,dct,t;
  DCP *a;

  dc = *dcp;
  for ( n = 0, dct = dc; dct; dct = NEXT(dct), n++ );
  a = (DCP *)ALLOCA((n+1)*(sizeof(DCP)));
  for ( i = 0, dct = dc; dct; dct = NEXT(dct), i++ ) 
    a[i] = dct;
  a[n] = 0;

  for ( i = 0; i < n; i++ ) {
    for ( k0 = k = i, d = UDEG(COEF(a[i])); k < n; k++ ) 
      if ( (int)UDEG(COEF(a[k])) < d ) {
        k0 = k;
        d = UDEG(COEF(a[k]));
      }
    if ( i != k0 ) {
      t = a[i]; a[i] = a[k0]; a[k0] = t;
    }
  }
  for ( *dcp = dct = a[0], i = 1; i < n; i++ )
    dct = NEXT(dct) = a[i];
  NEXT(dct) = 0;
}

void sortfsrev(DCP *dcp)
{
  int i,k,n,k0,d;
  DCP dc,dct,t;
  DCP *a;

  dc = *dcp;
  for ( n = 0, dct = dc; dct; dct = NEXT(dct), n++ );
  a = (DCP *)ALLOCA((n+1)*(sizeof(DCP)));
  for ( i = 0, dct = dc; dct; dct = NEXT(dct), i++ ) 
    a[i] = dct;
  a[n] = 0;

  for ( i = 0; i < n; i++ ) {
    for ( k0 = k = i, d = UDEG(COEF(a[i])); k < n; k++ ) 
      if ( (int)UDEG(COEF(a[k])) > d ) {
        k0 = k;
        d = UDEG(COEF(a[k]));
      }
    if ( i != k0 ) {
      t = a[i]; a[i] = a[k0]; a[k0] = t;
    }
  }
  for ( *dcp = dct = a[0], i = 1; i < n; i++ )
    dct = NEXT(dct) = a[i];
  NEXT(dct) = 0;
}

void nthrootchk(P f,struct oDUM *dc,ML fp,DCP *dcp)
{
  register int i,k;
  int e,n,dr,t;
  unsigned int tmp;
  int *tmpp,**tmppp;
  int **pp,**wpp;
  LUM fpa,tpa,f0l;
  UM wt,wq,ws,dvr,f0,fe;
  Z lc;
  int lcm;
  int m,b;

  m = fp->mod; b = fp->bound; fe = *((UM *)fp->c); 
  e = dc->n; f0 = dc->f; nthrootz((Z)COEF(DC(f)),e,&lc);
  if ( !lc ) {
    *dcp = 0;
    return;
  }
  lcm = remqi((Q)lc,m); W_LUMALLOC(DEG(f0),b,f0l);
  for ( i = DEG(f0), tmppp = COEF(f0l), tmpp = COEF(f0);
    i >= 0; i-- ) 
    *(tmppp[i]) = dmb(m,tmpp[i],lcm,&tmp);
  dtestroot(m,1,f,f0l,dc,dcp);
  if ( *dcp ) 
    return;
  n = UDEG(f); W_LUMALLOC(n,b,fpa); W_LUMALLOC(n,b,tpa);
  ptolum(m,b,f,fpa);
  dvr = W_UMALLOC(n); wq = W_UMALLOC(n); 
  wt = W_UMALLOC(n); ws = W_UMALLOC(n);
  cpyum(fe,dvr); divum(m,dvr,f0,wq);
  t = dmb(m,pwrm(m,lcm,e-1),e,&tmp); DEG(dvr) = DEG(wq);
  for ( k = 0; k <= DEG(wq); k++ ) 
    COEF(dvr)[k] = dmb(m,COEF(wq)[k],t,&tmp);
  for ( i = 1; i < b; i++ ) {
    pwrlum(m,i+1,f0l,e,tpa);
    for ( k = 0, pp = COEF(fpa), wpp = COEF(tpa); 
      k <= n; k++ )
      COEF(wt)[k] = (pp[k][i]-wpp[k][i]+m)%m;
    degum(wt,n); dr = divum(m,wt,dvr,ws);
    if ( dr >= 0 ) {
      *dcp = 0;
      return;
    }
    for ( k = 0, pp = COEF(f0l); k <= DEG(ws); k++ )
      pp[k][i] = COEF(ws)[k];
    dtestroot(m,i+1,f,f0l,dc,dcp);
    if ( *dcp )
      return;
  }
}

void sqfrp(VL vl,P f,DCP *dcp)
{
  P c,p;
  DCP dc,dc0;

  if ( !f || NUM(f) ) {
    NEWDC(dc0); *dcp = dc0; DEG(dc0) = ONE;
    COEF(dc0) = f; NEXT(dc0) = 0;
  } else if ( !qpcheck((Obj)f) )
    error("sqfrp : invalid argument");  
  else {
    NEWDC(dc0); *dcp = dc0; DEG(dc0) = ONE;
    ptozp(f,1,(Q *)&c,&p); msqfr(vl,p,&dc);
    COEF(dc0) = c; NEXT(dc0) = dc;
    adjsgn(f,dc0);
  }
}

/* 
 * f : must be a poly with int coef, ignore int content
 */
void msqfr(VL vl,P f,DCP *dcp)
{
  DCP dc,dct,dcs;
  P c,p,t,s,pc;
  VL mvl;

  ptozp(f,1,(Q *)&c,&t); monomialfctr(vl,t,&p,&dc);
  if ( NUM(p) ) {
    *dcp = dc;
    return;
  }
  mindegp(vl,p,&mvl,&s);
#if 0
  minlcdegp(vl,p,&mvl,&s);
  min_common_vars_in_coefp(vl,p,&mvl,&s);
#endif
  pcp(mvl,s,&p,&pc);
  if ( !NUM(pc) ) {
    msqfr(mvl,pc,&dcs);
    if ( !dc )
      dc = dcs;
    else {
      for ( dct = dc; NEXT(dct); dct = NEXT(dct) );
      NEXT(dct) = dcs;
    }
  }
  msqfrmain(mvl,p,&dcs); 
  for ( dct = dcs; dct; dct = NEXT(dct) ) {
    reorderp(vl,mvl,COEF(dct),&t); COEF(dct) = t;
  }
  if ( !dc )
    *dcp = dcs;
  else {
    for ( dct = dc; NEXT(dct); dct = NEXT(dct) );
    NEXT(dct) = dcs; *dcp = dc;
  }
}

void usqp(P f,DCP *dcp)
{
  int index,nindex;
  P g,c,h;
  DCP dc;

  ptozp(f,1,(Q *)&c,&h); 
  if ( sgnq((Q)LC(h)) < 0 )
    chsgnp(h,&g);
  else
    g = h;
  for ( index = 0, dc = 0; !dc; index = nindex )
    hsq(index,5,g,&nindex,&dc);
  *dcp = dc;
}

void msqfrmain(VL vl,P p,DCP *dcp)
{
  int i,j;
  VL nvl,tvl;
  VN vn,vnt,vn1;
  P gg,tmp,p0,g;
  DCP dc,dc0,dcr,dcr0;
  int nv,d,d1;
  int found;
  VN svn1;
  P sp0;
  DCP sdc0;

  if ( deg(VR(p),p) == 1 ) {
    NEWDC(dc); DEG(dc) = ONE; COEF(dc) = p; NEXT(dc) = 0;
    *dcp = dc;
    return;
  }
  clctv(vl,p,&nvl);
  for ( nv = 0, tvl = nvl; tvl; tvl = NEXT(tvl), nv++);
  if ( nv == 1 ) {
    usqp(p,dcp);
    return;
  }
#if 0
  if ( heusqfrchk(nvl,p) ) {
    NEWDC(dc); DEG(dc) = ONE; COEF(dc) = p; NEXT(dc) = 0;
    *dcp = dc;
    return;
  }
#endif
  W_CALLOC(nv,struct oVN,vn);
  W_CALLOC(nv,struct oVN,vnt);
  W_CALLOC(nv,struct oVN,vn1);
  W_CALLOC(nv,struct oVN,svn1);
  for ( i = 0, tvl = NEXT(nvl); tvl; tvl = NEXT(tvl), i++ ) 
    vn1[i].v = vn[i].v = tvl->v;
  vn1[i].v = vn[i].v = 0;

  /* determine a heuristic bound of deg(GCD(p,p')) */
  while ( 1 ) {
    for ( i = 0; vn1[i].v; i++ )
      vn1[i].n = ((unsigned int)random())%256+1;
    substvp(nvl,LC(p),vn1,&tmp);
    if ( tmp ) {
      substvp(nvl,p,vn1,&p0);
      usqp(p0,&dc0);
      for ( d1 = 0, dc = dc0; dc; dc = NEXT(dc) )
        if ( DEG(dc) )
          d1 += (ZTOS(DEG(dc))-1)*UDEG(COEF(dc));
      if ( d1 == 0 ) {
        /* p is squarefree */
        NEWDC(dc); DEG(dc) = ONE; COEF(dc) = p; NEXT(dc) = 0;
        *dcp = dc;
        return;
      } else {
        d = d1+1; /* XXX : try searching better evaluation */
        found = 0;
        break;
      }
    }
  }

  for  ( dcr0 = 0, g = p; ; ) {
    while ( 1 ) {
      for ( i = 0, j = 0; vn[i].v; i++ ) 
        if ( vn[i].n ) vnt[j++].v = (V)((long)i);
      vnt[j].n = 0;

      mulsgn(vn,vnt,j,vn1);
      substvp(nvl,LC(g),vn1,&tmp);
      if ( tmp ) {
        substvp(nvl,g,vn1,&p0);
        usqp(p0,&dc0);
        for ( d1 = 0, dc = dc0; dc; dc = NEXT(dc) )
          if ( DEG(dc) )
            d1 += (ZTOS(DEG(dc))-1)*UDEG(COEF(dc));

        if ( d1 == 0 ) {
          NEWDC(dc); DEG(dc) = ONE; COEF(dc) = g; NEXT(dc) = 0;
          if ( !dcr0 ) 
            dcr0 = dc;
          else
            NEXT(dcr) = dc;
          *dcp = dcr0;
          return;
        }

        if ( d < d1 )
          goto END;
        if ( d > d1 ) {
          d = d1;
          found = 1;
          bcopy((char *)vn1,(char *)svn1,(int)(sizeof(struct oVN)*nv));
          sp0 = p0; sdc0 = dc0;
          goto END;
        } 
        /* d1 == d */
        if ( found ) {
          found = 0;
#if 0
        if ( d > d1 ) {
          d = d1;
              /*} */
#endif
          msqfrmainmain(nvl,g,svn1,sp0,sdc0,&dc,&gg); g = gg;
          if ( dc ) {
            if ( !dcr0 )
              dcr0 = dc;
            else
              NEXT(dcr) = dc;
            for ( dcr = dc; NEXT(dcr); dcr = NEXT(dcr) );
            if ( NUM(g) ) {
              NEXT(dcr) = 0; *dcp = dcr0;
              return;
            } 
            d = deg(VR(g),g);
          }
        }
      }
END:
      if ( nextbin(vnt,j) ) 
        break;
    }
    next(vn);
  }
}

void msqfrmainmain(VL vl,P p,VN vn,P p0,DCP dc0,DCP *dcp,P *pp)
{
  int i,j,k,np;
  DCP *a;
  DCP dc,dcr,dcr0,dct;
  P g,t,s,u,t0,f,f0,d,d0,g0,h0,x,xx;
  Z q;
  V v;

  for ( np = 0, dc = dc0; dc; dc = NEXT(dc), np++ );
  a = (DCP *)ALLOCA((np + 1)*sizeof(DCP)); 
  for ( i = 0, dc = dc0; dc; i++, dc = NEXT(dc) ) 
    a[np-i-1] = dc;

  for ( i = 0, dcr0 = 0, f = p, f0 = p0, v = VR(p); 
    i < np; i++ ) { 
    if ( (i == (np-1))&&UNIQ(DEG(a[i])) ) {
      NEXTDC(dcr0,dcr);
      DEG(dcr) = DEG(a[i]);
      COEF(dcr) = f;
      f = (P)ONE;
    } else if ( (i == (np-1))&&UNIQ(DEG(DC(COEF(a[i])))) ) {
      diffp(vl,f,v,&s); pcp(vl,s,&t,&u);
      if ( divtpz(vl,f,t,&s) ) {
        NEXTDC(dcr0,dcr);
        DEG(dcr) = DEG(a[i]);
        COEF(dcr) = s;
        f = (P)ONE;
      } else 
        break;
    } else { 
      for ( t = f, t0 = f0,
        j = 0, k = ZTOS(DEG(a[i]))-1; j < k; j++ ) {
        diffp(vl,t,v,&s); t = s;
        diffp(vl,t0,v,&s); t0 = s;
      }
      factorialz(k,&q); 
      divsp(vl,t,(P)q,&s); 
      for ( dct = DC(s); NEXT(dct); dct = NEXT(dct) );
      if ( DEG(dct) ) {
        MKV(VR(s),x); pwrp(vl,x,DEG(dct),&xx); 
        divsp(vl,s,xx,&d); 
      } else {
        xx = (P)ONE; d = s;
      }
      divsp(vl,t0,xx,&t); 
      divsp(vl,t,(P)q,&s); 
      ptozp(s,1,(Q *)&t,&d0); 

      for ( dct = DC(COEF(a[i])); NEXT(dct); dct = NEXT(dct) );
      if ( DEG(dct) )
        divsp(vl,COEF(a[i]),xx,&g0);
      else {
        xx = (P)ONE; g0 = COEF(a[i]);
      }

      pcp(vl,d,&t,&u); d = t;
      ptozp(g0,1,(Q *)&u,&t); g0 = t;

    {
      DCP dca,dcb;

      fctrp(vl,LC(d),&dca);
      for ( dcb = dca, u = (P)ONE; dcb; dcb = NEXT(dcb) ) {
        if ( NUM(COEF(dcb)) ) {
          mulp(vl,u,COEF(dcb),&t); u = t;
        } else {
          Z qq;
          P tt;

          pwrp(vl,COEF(dcb),DEG(a[i]),&s);
          for ( t = LC(f), j = 0; divtpz(vl,t,s,&tt); j++, t = tt );
          STOZ(j,qq);
          if ( cmpz(qq,DEG(dcb)) > 0 )
            qq = DEG(dcb);
          pwrp(vl,COEF(dcb),qq,&t); mulp(vl,u,t,&s); u = s;
        }
      }
      divsp(vl,d0,g0,&h0);
    }
      mfctrhen2(vl,vn,d,d0,g0,h0,u,LC(d),&s); 
      if ( s ) {
        mulp(vl,s,xx,&g); 
        pwrp(vl,g,DEG(a[i]),&t);
        if ( divtpz(vl,f,t,&s) ) {
          NEXTDC(dcr0,dcr);
          DEG(dcr) = DEG(a[i]); COEF(dcr) = g;
          f = s; substvp(vl,f,vn,&f0);
        } else
          break;
      } else 
        break;
    }
  }
  *pp = f;  
  if ( dcr0 ) 
    NEXT(dcr) = 0;
  *dcp = dcr0;
}

void mfctrhen2(VL vl,VN vn,P f,P f0,P g0,P h0,P lcg,P lch,P *gp)
{
  V v;
  P f1,lc,lc0,lcg0,lch0;
  P m,ff0,gg0,hh0,gk,hk,ggg,gggr,hhh,ak,bk,tmp;
  Q bb,s;
  Z qk;
  Q cbd; 
  int dbd;
  int d;

  if ( NUM(g0) ) {
    *gp = (P)ONE;
    return;
  } 

  v = VR(f); d = deg(v,f);
  if ( d == deg(v,g0) ) {
    pcp(vl,f,gp,&tmp); 
    return;
  }    

  mulp(vl,lcg,lch,&lc);
  if ( !divtpz(vl,lc,LC(f),(P *)&s) ) {
    *gp = 0;
    return;
  }
  mulp(vl,(P)s,f,&f1);
  dbd = dbound(VR(f1),f1) + 1; cbound(vl,f1,&cbd);

  substvp(vl,lc,vn,&lc0);
  divq((Q)lc0,(Q)LC(f0),(Q *)&m); mulp(vl,f0,m,&ff0); 
  substvp(vl,lcg,vn,&lcg0);
  divq((Q)lcg0,(Q)LC(g0),(Q *)&m); mulp(vl,g0,m,&gg0); 
  substvp(vl,lch,vn,&lch0);
  divq((Q)lch0,(Q)LC(h0),(Q *)&m); mulp(vl,h0,m,&hh0); 
  addq(cbd,cbd,&bb);
  henzq1(gg0,hh0,bb,&bk,&ak,&qk); gk = gg0; hk = hh0;
  henmv(vl,vn,f1,gk,hk,ak,bk,
    lcg,lch,lcg0,lch0,qk,dbd,&ggg,&hhh); 

  if ( divtpz(vl,f1,ggg,&gggr) )
    pcp(vl,ggg,gp,&tmp);
  else
    *gp = 0;
}

int sqfrchk(P p)
{
  Q c;
  P f;
  DCP dc;

  ptozp(p,sgnq((Q)UCOEF(p)),&c,&f); usqp(f,&dc); 
  if ( NEXT(dc) || !UNIQ(DEG(dc)) ) 
    return ( 0 );
  else 
    return ( 1 );
}

int cycchk(P p)
{
  Q c;
  P f;

  ptozp(p,sgnq((Q)UCOEF(p)),&c,&f);
  if ( iscycp(f) || iscycm(f) )
    return 0;
  else 
    return 1;
}

int zerovpchk(VL vl,P p,VN vn)
{
  P t;

  substvp(vl,p,vn,&t);
  if ( t )
    return ( 0 );
  else
    return ( 1 );
}

int valideval(VL vl,DCP dc,VN vn)
{
  DCP dct;
  Z *a;
  int i,j,n;
  Z q,r;

  for ( dct = NEXT(dc), n = 0; dct; dct = NEXT(dct), n++ );
  W_CALLOC(n,Z,a);
  for ( dct = NEXT(dc), i = 0; dct; dct = NEXT(dct), i++ ) {
    substvp(vl,COEF(dct),vn,(P *)&a[i]);
    if ( !a[i] )
      return ( 0 );

    for ( j = 0; j < i; j++ ) {
      divqrz(a[j],a[i],&q,&r);
      if ( !r )
        return ( 0 );
      divqrz(a[i],a[j],&q,&r);
      if ( !r )
        return ( 0 );
    }
  }
  return ( 1 );
}

void estimatelc(VL vl,Z c,DCP dc,VN vn,P *lcp)
{
  int i;
  DCP dct;
  P r,s,t;
  Z c0,c1,c2;

  for ( dct = dc, r = (P)ONE; dct; dct = NEXT(dct) ) {
    if ( NUM(COEF(dct)) ) {
      mulp(vl,r,COEF(dct),&s); r = s;
    } else {
      substvp(vl,COEF(dct),vn,(P *)&c0);
      for ( i = 0, c1 = c; i < (int)ZTOS(DEG(dct)); i++ ) {
        divz(c1,c0,&c2);
        if ( !INT(c2) )
          break;
        else
          c1 = c2;
      }
      if ( i ) {
        STOZ(i,c1);
        pwrp(vl,COEF(dct),c1,&s); mulp(vl,r,s,&t); r = t;
      }
    }
  }
  *lcp = r;
}

void monomialfctr(VL vl,P p,P *pr,DCP *dcp)
{
  VL nvl,avl;
  Z d;
  P f,t,s;
  DCP dc0,dc;

  clctv(vl,p,&nvl);
  for ( dc0 = 0, avl = nvl, f = p; avl; avl = NEXT(avl) ) {
    getmindeg(avl->v,f,&d);
    if ( d ) {
      MKV(avl->v,t); NEXTDC(dc0,dc); DEG(dc) = d; COEF(dc) = t;
      pwrp(vl,t,d,&s); divsp(vl,f,s,&t); f = t;
    }
  }
  if ( dc0 )
    NEXT(dc) = 0;
  *pr = f; *dcp = dc0;
}

void afctr(VL vl,P p0,P p,DCP *dcp)
{
  DCP dc,dc0,dcr,dct,dcs;
  P t;
  VL nvl;

  if ( VR(p) == VR(p0) ) {
    NEWDC(dc);
    DEG(dc) = ONE;
    COEF(dc) = p;
    NEXT(dc) = 0;
    *dcp = dc;
    return;
  }

  clctv(vl,p,&nvl);
  if ( !NEXT(nvl) ) 
    ufctr(p,1,&dc);
  else {
    sqa(vl,p0,p,&dc);
    for ( dct = dc; dct; dct = NEXT(dct) ) {
      pmonic(vl,p0,COEF(dct),&t); COEF(dct) = t;
    }
  }
  if ( NUM(COEF(dc)) ) 
    dcr = NEXT(dc);
  else
    dcr = dc;
  for ( dc0 = 0; dcr; dcr = NEXT(dcr) ) {
    afctrmain(vl,p0,COEF(dcr),1,&dcs);

    for ( dct = dcs; dct; dct = NEXT(dct) ) 
      DEG(dct) = DEG(dcr);
    if ( !dc0 )
      dc0 = dcs;
    else {
      for ( dct = dc0; NEXT(dct); dct = NEXT(dct) );
      NEXT(dct) = dcs;
    }
  }
  *dcp = dc0;
}

void afctrmain(VL vl,P p0,P p,int init,DCP *dcp)
{
  P x,y,s,m,a,t,u,pt,pt1,res,g;
  Z q;
  DCP dc,dc0,dcsq0,dcr0,dcr,dct,dcs;
  V v,v0;

  if ( !cmpz(DEG(DC(p)),ONE) ) {
    NEWDC(dc); DEG(dc) = ONE; NEXT(dc) = 0;
    pmonic(vl,p0,p,&COEF(dc)); *dcp = dc;
    return;
  }

  v = VR(p); MKV(v,x);
  v0 = VR(p0); MKV(v0,y);
  STOZ(init,q),s = (P)q;
  mulp(vl,s,y,&m); subp(vl,x,m,&t); addp(vl,x,m,&a); 
  substp(vl,p,v,t,&pt); 
  remsdcp(vl,pt,p0,&pt1); 

/*
  if ( ( deg(v0,p0) <= 3 ) || ( TCPQ(p0) <= 2 ) ) 
    resultp(vl,v0,p0,pt1,&res);
  else 
    srcrnorm(vl,v0,pt1,p0,&res);
*/
#if 0
  srcr(vl,v0,pt1,p0,&res);
#endif
  resultp(vl,v0,p0,pt1,&res); 
  usqp(res,&dcsq0); 
  for ( dc0 = 0, dct = dcsq0; dct; dct = NEXT(dct) ) {
    if ( UNIQ(DEG(dct)) ) 
      ufctr(COEF(dct),deg(v0,p0),&dcs);
    else
      ufctr(COEF(dct),1,&dcs);
    for ( dcr = dcs; dcr; dcr = NEXT(dcr) )
      DEG(dcr) = DEG(dct);
    if ( !dc0 ) {
      dc0 = NEXT(dcs);
      dc = dc0;  
    } else {
      for ( ; NEXT(dc); dc = NEXT(dc) );
      NEXT(dc) = NEXT(dcs);
    }
  }
  sortfs(&dc0);

  for ( g = p, dcr = dcr0 = 0, dc = dc0; dc; dc = NEXT(dc) ) {
    if ( !UNIQ(DEG(dc)) ) {
      substp(vl,COEF(dc),v,a,&pt); remsdcp(vl,pt,p0,&s); 
      gcda(vl,p0,s,g,&u); 
      if ( !NUM(u) && (VR(u) == v)) {
        afctrmain(vl,p0,u,init+1,&dct);
        for ( dcs = dct, t = (P)ONE; dcs; dcs = NEXT(dcs) ) {
          mulp(vl,t,COEF(dcs),&s); remsdcp(vl,s,p0,&t);
        }
        pdiva(vl,p0,g,t,&s); g = s;
        if ( !dcr0 )
          dcr0 = dct;
        else 
          NEXT(dcr) = dct;
        for ( dcr = dct; NEXT(dcr); dcr = NEXT(dcr) );
      }
    } else {
      substp(vl,COEF(dc),v,a,&pt); remsdcp(vl,pt,p0,&s); 
      gcda(vl,p0,s,g,&u); 
      if ( !NUM(u) && (VR(u) == v)) {
        NEXTDC(dcr0,dcr);
        DEG(dcr) = ONE;
        COEF(dcr) = u;
        pdiva(vl,p0,g,u,&t); g = t;
      } 
    }
  }
  if ( dcr0 )
    NEXT(dcr) = 0;
  *dcp = dcr0;
}