/*******************************************************************/
/*******************************************************************/
/*                                                                 */
/*                OPERATIONS DANS LES CORPS DE NOMBRES             */
/*                                                                 */
/*******************************************************************/
/*******************************************************************/
/* $Id: base3.c,v 2.0.0.2 1997/12/14 20:11:49 karim Exp karim $ */
#include "genpari.h"

/*******************************************************************/
/*                                                                 */
/*                OPERATIONS OVER NUMBER FIELD ELEMENTS.           */
/*     These are always represented as column vectors over the     */
/*     integral basis nf[7]                                        */
/*                                                                 */
/*******************************************************************/

int
isnfscalar(GEN x)
{
  long lx=lg(x),i;

  for (i=2; i<lx; i++)
    if (!gcmp0((GEN)x[i])) return 0;
  return 1;
}

static GEN
checknfelt_mod(GEN nf, GEN x)
{
  if (gegal((GEN)x[1],(GEN)nf[1])) return (GEN) x[2];
  err(talker,"not the same polynomial in number field operation");
  return NULL; /* not reached */
}

static GEN
scal_mul(GEN nf, GEN x, GEN y, long ty)
{
  long av=avma, tetpil;
  GEN p1;

  if (!is_extscalar_t(ty))
  {
    if (ty!=t_COL) err(typeer,"nfmul");
    y = gmul((GEN)nf[7],y);
  }
  p1 = gmul(x,y); tetpil=avma;
  return gerepile(av,tetpil,algtobasis(nf,p1));
}

/* product of x and y in nf */
GEN
element_mul(GEN nf, GEN x, GEN y)
{
  long av,i,j,k,N,tx=typ(x),ty=typ(y);
  GEN s,v,c,p1;

  nf=checknf(nf); N=lgef(nf[1])-3;
  if (tx==t_POLMOD) x=checknfelt_mod(nf,x);
  if (ty==t_POLMOD) y=checknfelt_mod(nf,y);
  if (is_extscalar_t(tx)) return scal_mul(nf,x,y,ty);
  if (is_extscalar_t(ty)) return scal_mul(nf,y,x,tx);
  if (isnfscalar(x)) return gmul((GEN)x[1],y);
  if (isnfscalar(y)) return gmul((GEN)y[1],x);

  v=cgetg(N+1,t_COL); av=avma;
  for (k=1; k<=N; k++)
  {
    s=gzero;
    for (i=1; i<=N; i++)
    {
      c=gcoeff(nf[9],k,(i-1)*N+i);
      if (signe(c))
      {
        p1 = gmul((GEN)x[i],(GEN)y[i]);
	if (!gcmp1(c)) p1 = gmul(p1,c);
	s = gadd(s, p1);
      }
      for (j=i+1; j<=N; j++)
      {
	c=gcoeff((GEN)nf[9],k,(i-1)*N+j);
	if (signe(c))
	{
          p1 = gadd(gmul((GEN)x[i],(GEN)y[j]),
                    gmul((GEN)x[j],(GEN)y[i]));
	  if (!gcmp1(c)) p1 = gmul(p1,c);
          s = gadd(s, p1);
	}
      }
    }
    v[k]=(long)gerepileupto(av,s); av=avma;
  }
  return v;
}

/* inverse of x in nf */
GEN
element_inv(GEN nf, GEN x)
{
  long av=avma,tetpil,flx,i,N,tx=typ(x);
  GEN p1,p,unmod;

  nf=checknf(nf); N=lgef(nf[1])-3;
  if (is_extscalar_t(tx))
  {
    if (tx==t_POLMOD) checknfelt_mod(nf,x);
    else if (tx==t_POL) x=gmodulcp(x,(GEN)nf[1]);
    p1=ginv(x); tetpil=avma;
    return gerepile(av,tetpil,algtobasis(nf,p1));
  }
  if (isnfscalar(x))
  {
    p1=cgetg(N+1,t_COL); p1[1]=linv((GEN)x[1]);
    for (i=2; i<=N; i++) p1[i]=lcopy((GEN)x[i]);
    return p1;
  }
  flx=1;
  for (i=1; i<=N; i++)
    if (typ(x[i])==t_INTMOD)
    { 
      p=gmael(x,i,1); x=lift(x);
      flx=0; break;
    }
  p1 = lift_intern( ginv(gmodulcp(gmul((GEN)nf[7],x),(GEN)nf[1])) );
  p1 = algtobasis_intern(nf,p1,gzero);

  if (flx) return gerepileupto(av,p1);
  unmod=gmodulsg(1,p); tetpil=avma;
  return gerepile(av,tetpil,gmul(unmod,p1));
}

/* quotient of x and y in nf */
GEN
element_div(GEN nf, GEN x, GEN y)
{
  long av=avma,tetpil,flx,i,N,tx=typ(x),ty=typ(y);
  GEN p1,p,unmod;

  nf=checknf(nf); N=lgef(nf[1])-3;
  if (tx==t_POLMOD) checknfelt_mod(nf,x);
  else if (tx==t_POL) x=gmodulcp(x,(GEN)nf[1]);

  if (ty==t_POLMOD) checknfelt_mod(nf,y);
  else if (ty==t_POL) y=gmodulcp(y,(GEN)nf[1]);

  if (is_extscalar_t(tx))
  {
    if (is_extscalar_t(ty)) p1=gdiv(x,y);
    else
    {
      if (ty!=t_COL) err(typeer,"nfdiv");
      p1=gdiv(x,gmodulcp(gmul((GEN)nf[7],y),(GEN)nf[1]));
    }
    tetpil=avma; return gerepile(av,tetpil,algtobasis(nf,p1));
  }
  if (is_extscalar_t(ty))
  {
    if (tx!=t_COL) err(typeer,"nfdiv");
    p1=gdiv(gmodulcp(gmul((GEN)nf[7],x),(GEN)nf[1]),y);
    tetpil=avma; return gerepile(av,tetpil,algtobasis(nf,p1));
  }

  if (isnfscalar(y)) return gdiv(x,(GEN)y[1]);
  if (isnfscalar(x))
  {
    p1=element_inv(nf,y); tetpil=avma;
    return gerepile(av,tetpil,gmul((GEN)x[1],p1));
  }

  flx=1;
  for (i=1; i<=N; i++)
    if (typ(x[i])==t_INTMOD)
    { 
      p=gmael(x,i,1); x=lift(x);
      flx=0; break;
    }
  for (i=1; i<=N; i++)
    if (typ(y[i])==t_INTMOD)
    { 
      p=gmael(y,i,1); y=lift(y);
      flx=0; break;
    }

  p1=lift_intern(gdiv(gmodulcp(gmul((GEN)nf[7],x),(GEN)nf[1]),
	              gmodulcp(gmul((GEN)nf[7],y),(GEN)nf[1])));
  p1 = algtobasis_intern(nf,p1,gzero);
  if (flx) return gerepileupto(av,p1);
  unmod=gmodulsg(1,p); tetpil=avma;
  return gerepile(av,tetpil,gmul(unmod,p1));
}

/* product of INTEGERS (i.e vectors with integral coeffs) x and y in nf */
GEN
element_muli(GEN nf, GEN x, GEN y)
{
  long av,i,j,k,N=lgef(nf[1])-3;
  GEN p1,s,v,c;

  v=cgetg(N+1,t_COL); av=avma;
  for (k=1; k<=N; k++)
  {
    s=gzero;
    for (i=1; i<=N; i++)
    {
      c=gcoeff(nf[9],k,(i-1)*N+i);
      if (signe(c))
      {
        p1 = mulii((GEN)x[i],(GEN)y[i]);
        if (!gcmp1(c)) p1 = mulii(p1,c);
	s = addii(s,p1);
      }
      for (j=i+1; j<=N; j++)
      {
	c=gcoeff(nf[9],k,(i-1)*N+j);
	if (signe(c))
	{
          p1 = addii(mulii((GEN)x[i],(GEN)y[j]), 
                     mulii((GEN)x[j],(GEN)y[i]));
          if (!gcmp1(c)) p1 = mulii(p1,c);
	  s = addii(s,p1);
	}
      }
    }
    v[k]=(long) gerepileupto(av,s); av=avma;
  }
  return v;
}

/* As element_muli, but output only part of the product */
GEN
element_mulh(GEN nf, long limi, long limj, GEN x, GEN y)
{
  long av,i,j,k,N=lgef(nf[1])-3;
  GEN p1,s,v,c;

  if (limi<limj) { i=limi; limi=limj; limj=i; s=x; x=y; y=s; }
  v=cgetg(N+1,t_COL); av=avma;
  for (k=1; k<=N; k++)
  {
    s=gzero;
    for (i=1; i<=limj; i++)
    {
      c=gcoeff(nf[9],k,(i-1)*N+i);
      if (signe(c))
      {
        p1 = mulii((GEN)x[i],(GEN)y[i]);
        if (!gcmp1(c)) p1 = mulii(p1,c);
	s = addii(s,p1);
      }
      for (j=i+1; j<=limj; j++)
      {
	c=gcoeff(nf[9],k,(i-1)*N+j);
	if (signe(c))
	{
          p1 = addii(mulii((GEN)x[i],(GEN)y[j]),
                     mulii((GEN)x[j],(GEN)y[i]));
	  if (!gcmp1(c)) p1 = mulii(p1,c);
          s = addii(s,p1);
	}
      }
    }
    for (i=limj+1; i<=limi; i++)
    {
      for (j=1; j<=limj; j++)
      {
	c=gcoeff(nf[9],k,(i-1)*N+j);
	if (signe(c))
	{
          p1 = mulii((GEN)x[i],(GEN)y[j]);
	  if (!gcmp1(c)) p1 = mulii(c,p1);
          s = addii(s,p1);
	}
      }
    }
    v[k]=(long)gerepileupto(av,s); av=avma;
  }
  return v;
}

/* square of x in nf */
GEN
element_sqr(GEN nf, GEN x)
{
  long av,i,j,k,N=lgef(nf[1])-3;
  GEN p1,s,v,c;

  if (isnfscalar(x))
  {
    s=cgetg(N+1,t_COL); s[1]=lsqr((GEN)x[1]);
    for (i=2; i<=N; i++) s[i]=lcopy((GEN)x[i]);
    return s;
  }
  v=cgetg(N+1,t_COL); av=avma;
  for (k=1; k<=N; k++)
  {
    s=gzero;
    for (i=1; i<=N; i++)
    {
      c=gcoeff(nf[9],k,(i-1)*N+i);
      if (signe(c))
      {
        p1 = gsqr((GEN)x[i]);
	if (!gcmp1(c)) p1 = gmul(p1,c);
        s = gadd(s,p1);
      }
      for (j=i+1; j<=N; j++)
      {
	c=gcoeff(nf[9],k,(i-1)*N+j);
	if (signe(c))
	{
          p1 = gmul((GEN)x[i],(GEN)x[j]);
	  p1 = gcmp1(c)? gmul2n(p1,1): gmul(p1,shifti(c,1));
	  s = gadd(s,p1);
	}
      }
    }
    v[k]=(long)gerepileupto(av,s); av=avma;
  }
  return v;
}

/* Compute x^k in nf */
GEN
element_pow(GEN nf, GEN x, GEN k)
{
  long s,av=avma,N;
  GEN y,z;

  if (typ(k)!=t_INT) err(talker,"not an integer exponent in nfpow");
  nf=checknf(nf); N=lgef(nf[1])-3;
  s=signe(k); if (!s) return gscalcol_i(gun,N);
  if (typ(x)!=t_COL) x=algtobasis(nf,x); 
  y=gscalcol_i(gun,N);
  if (isnfscalar(x)) { y[1]=lpui((GEN)x[1],k,0); return y; }
  if (s<0) k=negi(k); 
  z=x;
  for(;;)
  {
    if (mpodd(k)) y=element_mul(nf,z,y);
    k=shifti(k,-1);
    if (signe(k)) z=element_sqr(nf,z);
    else
    {
      cgiv(k); if (s<0) y = element_inv(nf,y);
      return gerepileupto(av,y);
    }
  }
}

/* Outputs x.w_i, where w_i is the i-th elt of the integral basis */
GEN
element_mulid_intern(GEN nf, GEN x, long i, GEN myzero)
{
  long av,tetpil,j,k, N = lgef(nf[1])-3, u = (i-1)*N;
  GEN s,v,c,p1;

  v=cgetg(N+1,t_COL); av=tetpil=avma;
  for (k=1; k<=N; k++)
  {
    s=myzero;
    for (j=1; j<=N; j++)
    {
      c=gcoeff(nf[9],k,u+j); p1=(GEN)x[j];
      if (signe(c) && !gcmp0(p1))
      {
        if (!gcmp1(c)) p1 = gmul(p1,c);
	tetpil=avma; s = gadd(s,p1);
      }
    }
    v[k]=lpile(av,tetpil,s); av=tetpil=avma;
  }
  return v;
}

GEN
element_mulid(GEN nf, GEN x, long i)
{
  return element_mulid_intern(nf,x,i,gzero);
}

long
int_elt_val(GEN nf, GEN x, GEN p, GEN bp, long w, long v, long N)
{
  long i;
  GEN r;

  for(; w<=v; w++)
  {
    x=element_muli(nf,x,bp);
    for (i=N; i; i--)
    {
      x[i]=ldvmdii((GEN)x[i],p,&r);
      if (signe(r)) return w;
    }
  }
  return w;
}

long
element_val(GEN nf, GEN x, GEN vp)
{
  long av = avma,N,w,vd,v,e;
  GEN denx,p=(GEN)vp[1],d;

  nf=checknf(nf); checkprimeid(vp);
  N=lgef(nf[1])-3; e=itos((GEN)vp[3]);
  switch(typ(x))
  {
    case t_INT: case t_FRAC: case t_FRACN:
      return ggval(x,p)*e;
    case t_POL:
      d=gabs(subres(x,(GEN)nf[1]),0);
      x=(GEN)principalideal(nf,x)[1]; break;
    case t_POLMOD:
      d=gabs(subres((GEN)x[2],(GEN)nf[1]),0);
      x=(GEN)principalideal(nf,x)[1]; break;
    case t_COL:
      if (lg(x)==N+1)
      { 
	d=gabs(subres(gmul((GEN)nf[7],x),(GEN)nf[1]),0);
	break;
      }
    default: err(typeer,"element_val");
  }
  if (isnfscalar(x)) return ggval((GEN)x[1],p)*e;

  denx=denom(x);
  if (!gcmp1(denx)) { x=gmul(denx,x); vd=ggval(denx,p); } else vd=0;
  v = ggval(d,p); w = -vd*e; if (v == -N*vd) return w;
  v = int_elt_val(nf,x,p,(GEN)vp[5],w, v - w,N);
  avma=av; return v;
}

/* a usage interne, pas de verifs. d = a multiple of norm(x) */
long
element_val2(GEN nf, GEN x, GEN d, GEN vp)
{
  GEN p = (GEN)vp[1];
  long av,N, v = ggval(d,p);

  if (!v) return 0;
  av=avma; N=lgef(nf[1])-3;
  v = int_elt_val(nf,x,p,(GEN)vp[5],0,v,N);
  avma=av; return v;
}

/* polegal without comparing variables */
long
polegal_spec(GEN x, GEN y)
{
  long i = lgef(x);

  if (i != lgef(y)) return 0;
  for (i--; i > 1; i--)
    if (!gegal((GEN)x[i],(GEN)y[i])) return 0;
  return 1;
}

GEN
basistoalg(GEN nf, GEN x)
{
  long tx=typ(x),lx=lg(x),i;
  GEN z;

  nf=checknf(nf);
  switch(tx)
  {
    case t_COL:
      for (i=1; i<lx; i++)
      {
        long t = typ(x[i]);
	if (is_matvec_t(t)) break;
      }
      if (i==lx)
      {
        z = cgetg(3,t_POLMOD); z[1] = lcopy((GEN)nf[1]);
	z[2] = lmul((GEN)nf[7],x); return z;
      }
      /* fall through */

    case t_VEC: case t_MAT: z=cgetg(lx,tx);
      for (i=1; i<lx; i++) z[i]=(long)basistoalg(nf,(GEN)x[i]);
      return z;

    case t_POLMOD:
      if (!polegal_spec((GEN)nf[1],(GEN)x[1]))
	err(talker,"not the same number field in basistoalg");
      return gcopy(x);
    default: z=cgetg(3,t_POLMOD); z[1]=lcopy((GEN)nf[1]);
      z[2]=lmul(x,polun[varn(nf[1])]); return z;
  }
}

/* valid for scalars and polynomial, degree less than N. 
 * No garbage collecting. No check (SEGV for vectors).
 */
GEN
algtobasis_intern(GEN nf,GEN x,GEN myzero)
{
  long i,l,tx=typ(x),N=lgef(nf[1])-3;
  GEN z=cgetg(N+1,t_COL);

  if (tx==t_POLMOD) { x=(GEN)x[2]; tx=typ(x); }
  if (tx==t_POL)
  {
    if (lgef(x)-3 >= N) x=gres(x,(GEN)nf[1]);
    l=lgef(x)-1; x++;
    for (i=1; i<l ; i++) z[i]=x[i];
    for (   ; i<=N; i++) z[i]=(long)myzero;
    return gmul((GEN)nf[8],z);
  }
  z[1]=lcopy(x); for (i=2; i<=N; i++) z[i]=(long)myzero;
  return z;
}

GEN
algtobasis(GEN nf, GEN x)
{
  long tx=typ(x),lx=lg(x),av=avma,i,N;
  GEN z;

  nf=checknf(nf);
  switch(tx)
  {
    case t_VEC: case t_COL: case t_MAT:
      z=cgetg(lx,tx);
      for (i=1; i<lx; i++) z[i]=(long)algtobasis(nf,(GEN)x[i]);
      return z;
    case t_POLMOD:
      if (!polegal_spec((GEN)nf[1],(GEN)x[1]))
	err(talker,"not the same number field in algtobasis");
      x = (GEN)x[2]; /* fall through */
    case t_POL:
      return gerepileupto(av,algtobasis_intern(nf,x,gzero));

    default: N=lgef(nf[1])-3; return gscalcol(x,N);
  }
}

/* Given a and b in nf, gives an algebraic integer y in nf such that a-b.y
 * is "small"
 */
GEN
nfdiveuc(GEN nf, GEN a, GEN b)
{
  long av=avma, tetpil;
  a = element_div(nf,a,b); tetpil=avma;
  return gerepile(av,tetpil,ground(a));
}

/* Given a and b in nf, gives a "small" algebraic integer r in nf
 * of the form a-b.y
 */
GEN
nfmod(GEN nf, GEN a, GEN b)
{
  long av=avma,tetpil;
  GEN p1=gneg(element_mul(nf,b,ground(element_div(nf,a,b))));
  tetpil=avma; return gerepile(av,tetpil,gadd(a,p1));
}

/* Given a and b in nf, gives a two-component vector [y,r] in nf such
 * that r=a-b.y is "small".
 */
GEN
nfdivres(GEN nf, GEN a, GEN b)
{
  long av=avma,tetpil;
  GEN p1,z, y = ground(element_div(nf,a,b));

  p1=gneg(element_mul(nf,b,y)); tetpil=avma;
  z=cgetg(3,t_VEC); z[1]=lcopy(y); z[2]=ladd(a,p1);
  return gerepile(av,tetpil,z);
}

/*************************************************************************/
/**									**/
/**			      (Z_K/I)^*					**/
/**									**/
/*************************************************************************/

/* return (column) vector of R1 signatures of x (coeff modulo 2)
 * if arch = NULL, assume arch = [0,..0]
 */
GEN
zsigne(GEN nf,GEN x,GEN arch)
{
  long i,j,l,_0mod2,_1mod2;
  GEN vecsign,rac;

  if (!arch) return cgetg(1,t_COL);
  switch(typ(x))
  {
    case t_COL: x = gmul((GEN)nf[7],x); break;
    case t_POLMOD: x = (GEN)x[2];
  }
  if (gcmp0(x)) err(talker,"zero element in zsigne");
  _0mod2=(long)gmodulss(0,2);
  _1mod2=(long)gmodulss(1,2);

  rac=(GEN)nf[6]; l=lg(arch);
  j=1; vecsign = cgetg(l,t_COL);
  for (i=1; i<l; i++)
    if (signe(arch[i]))
      vecsign[j++] = (gsigne(poleval(x,(GEN)rac[i])) > 0)? _0mod2: _1mod2;
  setlg(vecsign,j); return vecsign;
}

/* For internal use. Reduce x modulo ideal. We want a non-zero result */
GEN
nfreducemodideal(GEN nf,GEN x,GEN ideal)
{
  long N = lg(x)-1, do_copy = 1, i;
  GEN p1,q;
  
  ideal=idealhermite(nf,ideal);
  for (i=N; i>=1; i--)
  {
    p1=gcoeff(ideal,i,i); q=gdivround((GEN)x[i],p1);
    if (signe(q)) { x=gsub(x,gmul(q,(GEN)ideal[i])); do_copy=0; }
  }
  if (gcmp0(x)) return (GEN) ideal[1];
  return do_copy? gcopy(x) : x;
}

/* Reduction de la colonne x modulo la matrice y en HNF */
static GEN
colreducemodmat(GEN x,GEN y)
{
  long N = lg(x)-1, av = avma, i;
  GEN q;

  for (i=N; i>=1; i--)
  {
    q = gdivround((GEN)x[i], gcoeff(y,i,i));
    if (signe(q)) { q = gneg(q); x = gadd(x, gmul(q,(GEN)y[i])); }
  }
  return avma==av? gcopy(x): gerepileupto(av,x);
}

/* a usage interne...Reduction de la colonne x modulo la matrice y inversible
   utilisant LLL */
GEN
lllreducemodmatrix(GEN x,GEN y)
{
  long av=avma,tetpil;
  GEN p1;

  y=gmul(y,lllint(y)); p1=gmul(y,ground(gauss(y,x)));
  tetpil=avma; return gerepile(av,tetpil,gsub(x,p1));
}

/* a usage interne...Reduction de la matrice x modulo la matrice y */
GEN
reducemodmatrix(GEN x, GEN y)
{
  long i, lx = lg(x);
  GEN z = cgetg(lx,t_MAT);

  if (DEBUGLEVEL>=8)
  {
    fprintferr("entree dans reducemodmatrix; avma-bot = %ld\n",avma-bot); 
    flusherr();
  }  
  y=hnfmod(y,detint(y));
  if (DEBUGLEVEL>=8)
  {
    fprintferr("hnf(y); avma-bot = %ld\n",avma-bot);
    fprintferr("%ld colreduce a faire\n",lx-1);
  }
  for (i=1; i<lx; i++)
  {
    if(DEBUGLEVEL>=8) { fprintferr("%ld ",i); flusherr(); }
    z[i]=(long)colreducemodmat((GEN)x[i],y);
  }
  if(DEBUGLEVEL>=8) { fprintferr("\n"); flusherr(); }
  return z;
}

/* un element g etant donne, calcule un element congru a g modulo l'ideal
   ideal et de meme signature aux places de arch */
GEN
nfreducemodidele(GEN nf,GEN g,GEN idele,GEN structarch)
{
  long nba,i;
  GEN p1,p2,ideal,arch,generator;

  if (gcmp0(g)) return gcopy(g);
  if (typ(idele)==t_VEC && lg(idele)==3)
  {
    ideal=(GEN)idele[1]; arch=(GEN)idele[2];
    p1=nfreducemodideal(nf,g,ideal);
    generator=(GEN)structarch[2];
    p2=lift_intern(gmul((GEN)structarch[3],
                        gadd(zsigne(nf,p1,arch),zsigne(nf,g,arch))));
    nba = lg(structarch[1]); 
    for (i=1; i<nba; i++)
      if (signe(p2[i])) p1=element_mul(nf,p1,(GEN)generator[i]);
    if (gcmp(gnorml2(p1),gnorml2(g)) > 0) return g;
    return p1;
  }
  return nfreducemodideal(nf,g,idele);
}

GEN
element_powmodideal(GEN nf,GEN x,GEN k,GEN ideal)
{
  long i,N;
  GEN k1,y,z;

  N=lgef(nf[1])-3; k1=k; z=x;
  y=cgetg(N+1,t_COL); y[1]=un; for (i=2; i<=N; i++) y[i]=zero;
  for(;;)
  {
    if (mpodd(k1)) y=element_mulmodideal(nf,z,y,ideal);
    k1=shifti(k1,-1);
    if (!signe(k1)) return y;
    z = element_sqrmodideal(nf,z,ideal);
  }
}

GEN
element_powmodidele(GEN nf,GEN x,GEN k,GEN idele,GEN structarch)
{
  long i,N;
  GEN k1,y,z;

  N=lgef(nf[1])-3; k1=k; z=x;
  y=cgetg(N+1,t_COL); y[1]=un; for (i=2; i<=N; i++) y[i]=zero;
  for(;;)
  {
    if (mpodd(k1)) y=element_mulmodidele(nf,z,y,idele,structarch);
    k1=shifti(k1,-1);
    if (!signe(k1)) return y;
    z = element_sqrmodidele(nf,z,idele,structarch);
  }
}

/* given 2 integral ideals x, y in HNF s.t x|y|x^2, compute the quotient
   (1+x)/(1+y) in the form [[cyc],[gen],ux^-1]. */
static GEN
zidealij(GEN x, GEN y)
{
  GEN p1,p2,p3,p4,d,z,x1;
  long j,N,c;

  if(DEBUGLEVEL>=6)
    {fprintferr("entree dans zidealij; avma-bot = %ld\n",avma-bot); flusherr();}
  x1 = ginv(x);
  if(DEBUGLEVEL>=6)
    {fprintferr("x1 = 1/x; avma-bot = %ld\n",avma-bot); flusherr();}
  p1 = gmul(x1,y);
  if(DEBUGLEVEL>=6)
    {fprintferr("p1 = y/x; avma-bot = %ld\n",avma-bot); flusherr();}
  p2 = smith2(p1);
  if(DEBUGLEVEL>=6)
    {fprintferr("p2 = smith2(p1); avma-bot = %ld\n",avma-bot); flusherr();}
  p3 = ginv((GEN)p2[1]);
  if(DEBUGLEVEL>=6)
    {fprintferr("p3 = 1/p2[1]; avma-bot = %ld\n",avma-bot); flusherr();}
  p3 = reducemodmatrix(p3,p1);
  if(DEBUGLEVEL>=6)
    {fprintferr("p3 = p3 mod p1; avma-bot = %ld\n",avma-bot); flusherr();}
  p3 = gmul(x,p3); N=lg(p3)-1;
  if(DEBUGLEVEL>=6)
    {fprintferr("p3 = x.p3; avma-bot = %ld\n",avma-bot); flusherr();}
  for (j=1; j<=N; j++) coeff(p3,1,j)=laddsi(1,gcoeff(p3,1,j));
  p4 = smithclean(p2); d=(GEN)p4[3];
  if(DEBUGLEVEL>=6) {fprintferr("p4 = smithclean(p2)\n"); flusherr();}  

  z=cgetg(4,t_VEC); c=lg(d); p1=cgetg(c,t_VEC);
  /* transform p3 in a vector (gen) */
  p3[0] = evaltyp(t_VEC) | evallg(c);
  /* get cyc. from diagonal */
  for (j=1; j<c; j++) p1[j] = coeff(d,j,j);
  z[1]=(long)p1;
  z[2]=(long)p3;
  z[3] = lmul((GEN)p4[1],x1); return z;
}

/* un element g generateur d'un p^k divisant x etant donne, calcule
   un element congru a g modulo p^k et a 1 modulo x/p^k et de plus
   positif aux places de arch */
GEN
zconvert(GEN nf,GEN uv,GEN x,GEN arch,GEN structarch,GEN g)
{
  long i,nba;
  GEN p1,p2,generator;

  p1=nfreducemodideal(nf,gadd((GEN)uv[1],element_mul(nf,g,(GEN)uv[2])),x);
  nba=lg(structarch[1])-1; generator=(GEN)structarch[2];
  p2=lift_intern(zsigne(nf,p1,arch));
  for (i=1; i<=nba; i++)
    if (signe(p2[i])) p1=element_mul(nf,p1,(GEN)generator[i]);
  return p1;
}

/* calcule le prhall associe a pr necessaire pour faire des reductions modulo
   pr meme pour des non entiers algebriques */
GEN
compute_prhall(GEN nf,GEN pr)
{
  long N,i,epr;
  GEN res,betae,p1,p2,id,p;

  N=lgef(nf[1])-3; epr=itos((GEN)pr[3]); p=(GEN)pr[1];
  betae = element_pow(nf, (GEN)pr[5], (GEN)pr[3]);
  betae = gmod(gdiv(betae,gpuigs(p,epr-1)), p);
  p1=cgetg(N+N+1,t_MAT); id=gscalmat(p,N);
  for(i=1; i<=N; i++)
  {
    p1[i] = id[i];
    p1[i+N] = (long)element_mulid(nf,betae,i);
  }
  p2 = gpuigs(p, N - epr*itos((GEN)pr[4]));
  p1 = hnfmod(p1,p2); res=cgetg(3,t_VEC);
  res[1]=(long)prime_to_ideal(nf,pr);
  res[2]=idealaddtoone(nf,pr,p1)[2]; return res;
}

/* rend l'indice de x dans la table t, sinon 0 */
static long
nfsearch(GEN t,GEN x)
{
  long l=1,u=lg(t)-1,i,s;

  while (u>=l)
  {
    i=(l+u)>>1; s=lexcmp(x,(GEN)t[i]);
    if (!s) return i;
    if (s<0) u=i-1; else l=i+1;
  }
  return 0;
}

/* rend le plus petit entier positif n tel que g0^n=x modulo pr */
GEN
nfshanks(GEN nf,GEN x,GEN g0,GEN pr,GEN prhall)
{
  long av=avma,tetpil,i,lbaby,k;
  GEN pf1,pfqr,p1,smalltable,giant,perm,v,g0inv;

  pf1=addsi(-1,gpui((GEN)pr[1],(GEN)pr[4],0));
  i=2; while (i<lg(x) && gcmp0((GEN)x[i])) i++;
  if (i==lg(x) && gcmp_1((GEN)x[1]))
  {
    if (cmpis((GEN)pr[1],2))
    { 
      tetpil=avma;
      return gerepile(av,tetpil,gmul2n(pf1,-1));
    }
    avma=av; return gzero;
  }
  pfqr=racine(pf1); 
  if (cmpis(pfqr,65535)>=0) err(talker,"module too large in nfshanks");
  p1=lift(x); g0inv=element_invmodpr(nf,g0,prhall);
  lbaby=itos(pfqr); smalltable=cgetg(lbaby+2,t_VEC); i=0;
  for(;;)
  {
    GEN p3,p2 = lift_intern(p1);
    
    p3=(GEN)p2[1]; p2[1]=laddsi(-1,p3);
    if (gcmp0(p2) || element_val(nf,p2,pr)) { avma=av; return stoi(i); }

    p2[1]=(long)p3; smalltable[++i]=(long)p2;
    if (i>lbaby) break;
    p1=element_mulmodpr(nf,p1,g0inv,prhall);
  }
  giant=element_divmodpr(nf,x,p1,prhall);
  perm = sindexlexsort(smalltable); p1=cgetg(lbaby+2,t_VEC);
  for (i=1; i<=lbaby+1; i++) p1[i]=smalltable[perm[i]];
  smalltable=p1; p1=giant;
  for (k=1;;k++)
  {
    i=nfsearch(smalltable,lift_intern(p1));
    if (i)
    {
      v=addis(mulss(lbaby,k),perm[i]); tetpil=avma;
      return gerepile(av,tetpil,addsi(-1,v));
    }
    p1=element_mulmodpr(nf,p1,giant,prhall);
  }
}

GEN
dethnf(GEN mat)
{
  long av,i,l = lg(mat);
  GEN s;

  if (l<2) return gun;
  av = avma; s = gcoeff(mat,1,1);
  for (i=2; i<l; i++) s = gmul(s,gcoeff(mat,i,i));
  return av==avma? gcopy(s): gerepileupto(av,s);
}

static GEN
makeprimetoideal(GEN nf,GEN id,GEN uv,GEN x)
{
  GEN p1 = gadd((GEN)uv[1], element_mul(nf,x,(GEN)uv[2]));
  return nfreducemodideal(nf,p1,id);
}

static GEN
makeprimetoidealvec(GEN nf,GEN ideal,GEN uv,GEN listgen)
{
  long i, lx = lg(listgen);
  GEN y = cgetg(lx,t_VEC);

  for (i=1; i<lx; i++) 
    y[i] = (long)makeprimetoideal(nf,ideal,uv,(GEN)listgen[i]);
  return y;
}

/* Given an ideal pr^ep, and an integral ideal x (in HNF form) compute a list
 * of vectors, each with 5 components as follows :
 * [[clh],[gen1],[gen2],[signat2],U.X^-1]. Each component corresponds to
 * d_i,g_i,g'_i,s_i.  Generators g_i are not necessarily prime to x, the
 * generators g'_i are. signat2 is the (horizontal) vector made of the
 * signatures (column vectors) of the g'_i. If x = NULL, the original ideal
 * was a prime power
 */
static GEN
zprimestar(GEN nf,GEN pr,GEN ep,GEN x,GEN arch)
{
  long av=avma,av1,N,f,nbp,psim,j,n,m,tetpil,i,e,a,b;
  GEN prh,p,pefm1,fa,list,v,prhall,p1,p2,p3,p4,prk,uv,g0,newgen,pra,prb;
  GEN *gptr[2];

  if(DEBUGLEVEL>=4)
    { fprintferr("on traite pr = %Z ^ %Z\n",(long)pr,(long)ep); flusherr(); }
  prh=prime_to_ideal(nf,pr); N=lg(prh)-1;
  f=itos((GEN)pr[4]); p=(GEN)pr[1];
  pefm1 = gaddgs(gpuigs(p,f), -1);
  if(DEBUGLEVEL>=4) {fprintferr("prh etc... calcule\n");flusherr();}
  v=cgetg(N+1,t_COL); for (j=1; j<=N; j++) v[j]=zero; 
  psim=itos(p);
  if (f==1) v[1]=gener(p)[2];
  else
  {
    fa=factor(pefm1); list=(GEN)fa[1]; nbp=lg(list)-1;
    prhall=cgetg(3,t_VEC); prhall[1]=(long)prh; prhall[2]=zero;
    for (n=psim; ; n++)
    {
      m=n;
      for (i=1; i<=N; i++)
	if (!gcmp1(gcoeff(prh,i,i))) { v[i]=lstoi(m%psim); m/=psim; }
      for (j=1; j<=nbp; j++)
      {
        p1 = divii(pefm1,(GEN)list[j]);
	p1 = lift_intern(element_powmodpr(nf,v,p1,prhall));
	p1[1]=laddsi(-1,(GEN)p1[1]);
	if (gcmp0(p1) || element_val(nf,p1,pr)) break;
      }
      if (j>nbp) break;
    }
  }
  /* v generates  (Z_K / pr)^* */
  if(DEBUGLEVEL>=4) {fprintferr("v calcule\n");flusherr();}
  e = itos(ep); prk=(e==1)? pr: idealpow(nf,pr,ep); 
  if(DEBUGLEVEL>=4) {fprintferr("prk calcule\n");flusherr();}
  g0 = v;
  if (x)
  {
    uv = idealaddtoone(nf,prk,idealdivexact(nf,x,prk));
    g0 = makeprimetoideal(nf,x,uv,v);
  }
  if(DEBUGLEVEL>=4) {fprintferr("g0 calcule\n");flusherr();}

  list=cgetg(2,t_VEC);
  p1=cgetg(6,t_VEC); list[1]=(long)p1; p1[5]=un;
  p2=cgetg(2,t_VEC); p1[1]=(long)p2; p2[1]=(long)pefm1;
  p2=cgetg(2,t_VEC); p1[2]=(long)p2; p2[1]=(long)v;
  p2=cgetg(2,t_VEC); p1[3]=(long)p2; p2[1]=(long)g0;
  p2=cgetg(2,t_VEC); p1[4]=(long)p2; p2[1]=(long)zsigne(nf,g0,arch);
  if (e==1)
  { 
    tetpil=avma; return gerepile(av,tetpil,gcopy(list));
  }

  a=1; b=2; av1=avma;
  pra = prh; prb = (e==2)? prk: idealpow(nf,pr,gdeux);
  for(;;)
  {
    if(DEBUGLEVEL>=4)
      {fprintferr("on traite a = %ld, b = %ld\n",a,b); flusherr();}
    p1 = zidealij(pra,prb); 
    newgen = dummycopy((GEN)p1[2]);
    p3 = cgetg(lg(newgen),t_VEC);
    if(DEBUGLEVEL>=4) {fprintferr("zidealij fait\n"); flusherr();}
    for (i=1; i<lg(newgen); i++)
    {
      if (x) newgen[i]=(long)makeprimetoideal(nf,x,uv,(GEN)newgen[i]);
      p3[i]=(long)zsigne(nf,(GEN)newgen[i],arch);
    } 
    p2=cgetg(2,t_VEC); p4=cgetg(6,t_VEC); p2[1]=(long)p4; 
    p4[1] = p1[1]; 
    p4[2] = p1[2];
    p4[3] = (long)newgen;
    p4[4] = (long)p3;
    p4[5] = p1[3];
    
    a=b; b=min(e,b<<1); tetpil = avma;
    list = concat(list,p2);
    if (a==b) return gerepile(av,tetpil,list);

    pra = gcopy(prb);
    gptr[0]=&pra; gptr[1]=&list;
    gerepilemanysp(av1,tetpil,gptr,2);
    prb = (b==(a<<1))? idealpow(nf,pra,gdeux): prk;
  }
}

/* x ideal, compute elements in 1+x whose sign matrix is invertible */
GEN
zarchstar(GEN nf,GEN x,GEN arch,long nba)
{
  long av,av1,tetpil,N,i,r,rr,limr,k,kk,lgmat,lambda;
  GEN p1,y,bas,genarch,alpha,mat;

  if (!nba)
  {
    y=cgetg(4,t_VEC);
    y[1]=lgetg(1,t_VEC);
    y[2]=lgetg(1,t_VEC);
    y[3]=lgetg(1,t_MAT); return y;
  }
  N=lgef(nf[1])-3;
  if (N==1)
  {
    y=cgetg(4,t_VEC);
    y[1]=lgetg(2,t_VEC); mael(y,1,1) = deux;
    y[2]=lgetg(2,t_VEC);
    p1 = subsi(1, shifti(gcoeff(x,1,1),1));
    p1 = gmul(p1, polun[varn(nf[1])]);
    mael(y,2,1) = (long)p1;
    p1=cgetg(2,t_MAT); p1[1]=lgetg(2,t_COL); coeff(p1,1,1)=un;
    y[3]=(long)p1; return y;
  }
  av = avma; x = gmul(x,lllintpartial(x));
  genarch = cgetg(nba+1,t_VEC);
  mat = cgetg(nba+1,t_MAT); lgmat = 1;
  bas = gmul((GEN)nf[7],x);
  for (r=1, rr=3; ; r<<=1, rr=(r<<1)+1)
  {
    p1 = gpuigs(stoi(rr),N);
    limr = (cmpis(p1,BIGINT) > 0)? BIGINT: itos(p1);
    limr = (limr-1)>>1;
    for (k=rr; k<=limr; k++)
    {
      av1=avma; alpha=gun; kk=k;
      for (i=1; i<=N; i++)
      {
        lambda =(kk+r)%rr - r; kk/=rr;
	alpha = gadd(alpha, gmulsg(lambda,(GEN)bas[i]));
      }
      mat[lgmat] = (long)zsigne(nf,alpha,arch); 
      setlg(mat,lgmat+1); 
      if (rank(mat) < lgmat) avma = av1;
      else
      { /* new vector indep. of previous ones */
	genarch[lgmat++] = (long)algtobasis_intern(nf,alpha,gzero);
	if (lgmat > nba) /* we are done */
	{
	  mat=ginv(mat); tetpil=avma;
	  y=cgetg(4,t_VEC); y[1]=zero; /* dummy */
	  y[2]=lcopy(genarch); 
          y[3]=llift(mat); y = gerepile(av,tetpil,y);
          p1=cgetg(lgmat,t_VEC); for (i=1; i<lgmat; i++) p1[i]=deux;
          y[1]=(long)p1; return y;
	}
      }
    }
  }
}

/* Retourne la decomposition de a sur les nbgen generateurs successifs
 * contenus dans list_set et si index !=0 on ne fait ce calcul que pour
 * l'ideal premier correspondant a cet index en mettant a 0 les autres
 * composantes
 */
static GEN
zinternallog(GEN nf,GEN list_set,long nbgen,GEN arch,GEN fa,GEN a,long index)
{
  GEN prlist,ep,y,ainit,list,pr,prk,cyc,gen,psigne,p1,p2,p3;
  long av,nbp,cp,i,j,k;

  y = cgetg(nbgen+1,t_COL); cp=0; av=avma;
  prlist=(GEN)fa[1]; ep=(GEN)fa[2]; nbp=lg(ep)-1;
  i=typ(a); if (is_extscalar_t(i)) a = algtobasis(nf,a);
  if (DEBUGLEVEL>=4)
  { 
    fprintferr("entree dans zinternallog\n"); flusherr(); 
    if (DEBUGLEVEL>=6) { fprintferr("avec a = "); outerr(a); }
  }
  ainit = a; psigne = zsigne(nf,ainit,arch);
  for (k=1; k<=nbp; k++)
  {
    list=(GEN)list_set[k];
    if (index && index!=k)
    {
      for (j=1; j<lg(list); j++)
      {
        cyc = gmael(list,j,1);
        for (i=1; i<lg(cyc); i++) y[++cp]=zero;
      }
      continue;
    }
    pr=(GEN)prlist[k]; prk=idealpow(nf,pr,(GEN)ep[k]);
    for (j=1; j<lg(list); j++)
    {
      p1 = (GEN)list[j]; cyc=(GEN)p1[1]; gen=(GEN)p1[2];
      if (j==1)
      {
        if (DEBUGLEVEL>=6) { fprintferr("do nfshanks\n"); flusherr(); }
        a=ainit; p3=compute_prhall(nf,pr);
        p3 = nfshanks(nf,a,(GEN)gen[1],pr,p3);
      }
      else
      {
        p3 = (GEN)a[1]; a[1] = laddsi(-1,(GEN)a[1]);
        p2 = gmul((GEN)p1[5],a); a[1] = (long)p3;
        if (lg(p2)!=lg(cyc)) err(bugparier,"zinternallog");
        p3 = (GEN)p2[1];
      }
      for(i=1;;)
      {
        p3 = modii(negi(p3), (GEN)cyc[i]);
        y[++cp] = lnegi(p3);
        if (signe(p3))
        {
          if (mpodd((GEN)y[cp])) psigne = gadd(psigne,gmael(p1,4,i));
          if (DEBUGLEVEL>=6) fprintferr("do element_powmodideal\n"); 
          p3 = element_powmodideal(nf,(GEN)gen[i],p3,prk);
          a = element_mulmodideal(nf,a,p3,prk);
        }
        i++; if (i==lg(cyc)) break;
        p3 = (GEN)p2[i];
      }
    }
  }
  p1=lift_intern(gmul(gmael(list_set,nbp+1,3), psigne));
  avma=av; for (i=1; i<lg(p1); i++) y[++cp] = p1[i];
  if (DEBUGLEVEL>=6) { fprintferr("sortie de zinternallog\n"); flusherr(); }
  for (i=1; i<=nbgen; i++) y[i] = licopy((GEN)y[i]);
  return y;
}

/* Calcule [[ideal,arch],[h,[cyc],[gen]],idealfact,[liste],U]
   gen n'est pas calcule si compute_gen=0 */
GEN
zidealstarinitall(GEN nf, GEN ideal,long compute_gen)
{
  long av=avma,tetpil,i,j,nba,nbp,N,c,s,R1,nbgen,cp,jj;
  GEN p1,p2,p3,p3plus,p3moins,p4,p5,p6,y,h,clh,met,u1,basecl,mot,generator;
  GEN fa,fa2,ep,x,arch,allgenerator,list,structarch,u1u2,unnf;

  y=cgetg(6,t_VEC); nf=checknf(nf);
  N=lgef(nf[1])-3; R1=itos(gmael(nf,2,1));
  if (typ(ideal)==t_VEC && lg(ideal)==3)
  {
    arch=(GEN)ideal[2]; ideal = (GEN)ideal[1];
    i = typ(arch); nba = 0; 
    if (!is_vec_t(i) || lg(arch) != R1+1)
      err(talker,"incorrect archimedean component in zidealstarinit");
    for (i=1; i<=R1; i++)
      if (signe(arch[i])) nba++;
  }
  else
  {
    arch=cgetg(R1+1,t_VEC); nba=0;
    for (i=1; i<=R1; i++) arch[i]=zero;
  }
  x = idealhermite(nf,ideal);
  if (!gcmp1(denom(x)))
  {
    fprintferr(" x = "); outerr(x);
    err(talker,"zidealstarinit needs an integral ideal");
  }
  p1=cgetg(3,t_VEC); ideal=p1;
  p1[1]=(long)x; 
  p1[2]=(long)arch;

  fa=idealfactor(nf,x); list=(GEN)fa[1]; ep=(GEN)fa[2];
  nbp=lg(list)-1; fa2=cgetg(nbp+2,t_VEC);
  y[1]=(long)ideal;
  y[3]=(long)fa;
  y[4]=(long)fa2;
  structarch = zarchstar(nf,x,arch,nba);
  allgenerator = cgetg(1,t_VEC);
  p2 = (nbp==1)? (GEN)NULL: x;
  for (i=1; i<=nbp; i++)
  {
    p1 = zprimestar(nf,(GEN)list[i],(GEN)ep[i],p2,arch);
    fa2[i]=(long)p1;
    for (j=1; j<lg(p1); j++)
      allgenerator = concatsp(allgenerator,gmael(p1,j,3));
  }
  fa2[nbp+1]=(long)structarch;
  generator=(GEN)structarch[2];
  allgenerator = concatsp(allgenerator,generator);
  nbgen = lg(allgenerator)-1;
  h=cgetg(nbgen+1,t_MAT); cp=0;
  for (i=1; i<=nbp; i++)
  {
    list=(GEN)fa2[i];
    for (j=1; j<lg(list); j++)
    {
      p1=(GEN)list[j]; p2=(GEN)p1[1]; p3=(GEN)p1[3];
      for (jj=1; jj<lg(p2); jj++)
      {
	if (DEBUGLEVEL>=6) 
          { fprintferr("entree dans element_powmodidele\n"); flusherr(); }
	p5=element_powmodidele(nf,(GEN)p3[jj],(GEN)p2[jj],ideal,structarch);
	h[++cp] = lneg(zinternallog(nf,fa2,nbgen,arch,fa,p5,i));
	coeff(h,cp,cp) = p2[jj];
      }
    }
  }
  for (j=1; j<=nba; j++) 
    { h[++cp]=(long)zerocol(nbgen); coeff(h,cp,cp)=deux; }
  if (cp!=nbgen) err(talker,"bug in zidealstarinit");
  if (nbgen)
  {
    u1u2=smith2(h);
    if (compute_gen)
      u1 = reducemodmatrix(ginv((GEN)u1u2[1]),h);
    u1u2=smithclean(u1u2);
    met=(GEN)u1u2[3]; y[5]=u1u2[1];
    clh=dethnf(met); c=lg(met)-1;
  }
  else
  { 
    clh=gun; met=cgetg(1,t_MAT); 
    u1=cgetg(1,t_MAT); y[5]=(long)u1; c=0;
  } 

  if (compute_gen)
  {
    basecl=cgetg(c+1,t_VEC); unnf=gscalcol_i(gun,N);
    for (j=1; j<=c; j++)
    {
      p3plus = p3moins = unnf;
      for (i=1; i<=nbgen; i++)
      {
	p1=gcoeff(u1,i,j); s=signe(p1);
	if (s)
	{
	  if (s>0)
	    p3plus = element_mulmodidele(nf,p3plus,element_powmodidele(nf,(GEN)allgenerator[i],p1,ideal,structarch),ideal,structarch);
	  else
	    p3moins = element_mulmodidele(nf,p3moins,element_powmodidele(nf,(GEN)allgenerator[i],negi(p1),ideal,structarch),ideal,structarch);
	}
      }
      if (nbp)
      {
	p6=idealaddtoone(nf,p3moins,x);
	/* p4 = p3moins^(-1) modulo x */
	p4=element_div(nf,(GEN)p6[1],p3moins);
	p3=element_mulmodideal(nf,p3plus,p4,x);
      }
      else p3=unnf;

      /* on corrige pour que p3 ait la meme signature que p3plus/p3moins */
      generator=(GEN)structarch[2];
      p5=gadd(gadd(zsigne(nf,p3,arch),zsigne(nf,p3plus,arch)),
              zsigne(nf,p3moins,arch));
      p2=lift_intern(gmul((GEN)structarch[3],p5));
      for (i=1; i<=nba; i++)
	if (signe(p2[i])) p3=element_mul(nf,p3,(GEN)generator[i]);
      basecl[j]=(long)p3;
    } 
    p1=cgetg(4,t_VEC); p1[3]=(long)basecl;
  }
  else p1=cgetg(3,t_VEC);

  y[2]=(long)p1;
  p1[1]=(long)clh; mot=cgetg(c+1,t_VEC);
  p1[2]=(long)mot; for (i=1; i<=c; i++) mot[i]=coeff(met,i,i);
  tetpil=avma; return gerepile(av,tetpil,gcopy(y));
}

GEN
zidealstarinitgen(GEN nf, GEN ideal)
{
  return zidealstarinitall(nf,ideal,1);
}

GEN
zidealstarinit(GEN nf, GEN ideal)
{
  return zidealstarinitall(nf,ideal,0);
}

GEN
zidealstar(GEN nf, GEN ideal)
{
  long av = avma,tetpil;
  GEN y = zidealstarinitall(nf,ideal,1);
  tetpil=avma; return gerepile(av,tetpil,gcopy((GEN)y[2]));
}

GEN
idealstar0(GEN nf, GEN ideal,long flag)
{
  switch(flag)
  {
    case 0: return zidealstar(nf,ideal);
    case 1: return zidealstarinit(nf,ideal);
    case 2: return zidealstarinitgen(nf,ideal);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}

long ideal_is_zk(GEN ideal,long N);

/*  x is not integral, but we assume v_p(x)=0 for all prime divisors of the
 *  ideal (we check) We need x = a/b with integral a and b, prime to ideal
 *  denmat = den * id.
 */
static GEN
rat_zinternallog(GEN nf, GEN x, GEN bigideal, GEN denmat)
{
  long nbp,i,v,k, N = lgef(nf[1])-3;
  GEN den,fa,list,ep,pr,p1,p2,p3,x1,dinv,ideal;

  ideal = (GEN)bigideal[1];
  if (lg(ideal) == 3) ideal = (GEN)ideal[1];
  fa=(GEN)bigideal[3]; list=(GEN)fa[1]; ep=(GEN)fa[2];
  den=gmael(denmat,1,1); k=1; nbp=lg(list)-1;
  for (i=1; i<=nbp; i++)
  {
    pr=(GEN)list[i];
    v = (ggval(den,(GEN)pr[1])*itos((GEN)pr[3])) / itos((GEN)ep[i]) + 1;
    if (v>k) k=v;
  }
  p3=idealpow(nf,ideal,stoi(k));
  p1=idealadd(nf,denmat,p3); dinv=idealinv(nf,p1);
  p2=idealmullll(nf,denmat,dinv);
  p3=idealmullll(nf,p3,dinv);
  x1=(GEN)idealaddtoone(nf,p2,p3)[1];
  if (gcmp0(x1)) x1 = (GEN)denmat[1];
  /* on a trouve x=a/b comme on veut, avec a=x1*x, b=x1 */
  p1=element_mul(nf,x1,x);
  /* x1 est necessairement premier a l'ideal, mais il faut verifier
     que x1*x l'est aussi */
  p2=idealadd(nf,p1,ideal);
  if (! ideal_is_zk(p2,N))
    err(talker,"element is not coprime to ideal in zideallog");
  p1=zideallog(nf,p1,bigideal);
  p2=zideallog(nf,x1,bigideal);
  return gsub(p1,p2);
}

/* etant donne un element x eventuellement non entier, et un idele ou ideal
 * entier au format zidealstarinit, calcule le vecteur des composantes sur
 * les generateurs donnes dans bid[2]
 */
GEN
zideallog(GEN nf, GEN x, GEN bid)
{
  long av,l,i,N,c;
  GEN fa,fa2,ideal,arch,den,p1,cyc,y;

  nf=checknf(nf); checkbid(bid);
  cyc=gmael(bid,2,2); c=lg(cyc);
  y=cgetg(c,t_COL); av=avma;
  N = lgef(nf[1])-3; ideal = (GEN) bid[1];
  if (typ(ideal)==t_VEC && lg(ideal)==3)
    arch = (GEN)ideal[2];
  else
    arch = NULL;
  switch(typ(x))
  {
    case t_INT: case t_FRAC: case t_FRACN:
      x = gscalcol_i(x,N); break;
    case t_POLMOD: case t_POL:
      x = algtobasis(nf,x); break;
    case t_COL: break;
    default: err(talker,"not an element in zideallog");
  }
  if (lg(x) != N+1) err(talker,"not an element in zideallog");

  den=denom(x);
  if (!gcmp1(den))
    p1 = rat_zinternallog(nf,x,bid, gscalmat(den,N));
  else
  {
    l=lg(bid[5])-1; fa=(GEN)bid[3]; fa2=(GEN)bid[4];
    p1 = zinternallog(nf,fa2,l,arch,fa,x,0);
    p1 = gmul((GEN)bid[5],p1); /* apply smith */
  }
  if (lg(p1)!=c) err(bugparier,"zideallog");
  for (i=1; i<c; i++)
    y[i] = lmodii((GEN)p1[i],(GEN)cyc[i]);
  avma=av; /* following line does a gerepile ! */
  for (i=1; i<c; i++)
    y[i] = (long)icopy((GEN)y[i]);
  return y;
}

/* Etant donnes bid1, bid2 resultats de zidealstarinit pour deux modules m1
 * et m2 premiers entre eux sans partie archimedienne, calcule le
 * zidealstarinit [[ideal,arch],[h,[cyc],[gen]],idealfact,[liste],U] du
 * produit
 */
static GEN
zidealstarinitjoinall(GEN nf, GEN bid1, GEN bid2, long compute_gen)
{
  long av=avma,tetpil,i,j,nbp,N,c,s,nbgen,lx1,lx2,llx1,llx2,lx,llx;
  GEN module1,module2,struct1,struct2,fact1,fact2,liste1,liste2,U1,U2;
  GEN module,liste,fact,U,cyc,ex1,ex2,uv;
  GEN p1,p2,p3,p3plus,p3moins,p4,p6,y,clh,met,u1,basecl,mot;
  GEN fa1,fa2,x,allgenerator,u1u2,unnf;

  nf=checknf(nf); N=lgef(nf[1])-3; checkbid(bid1); checkbid(bid2);
  module1=(GEN)bid1[1]; struct1=(GEN)bid1[2]; fact1=(GEN)bid1[3];
  module2=(GEN)bid2[1]; struct2=(GEN)bid2[2]; fact2=(GEN)bid2[3];
  module=cgetg(3,t_VEC);
  module[1]=(long)idealmul(nf,(GEN)module1[1],(GEN)module2[1]);
  module[2]=ladd((GEN)module1[2],(GEN)module2[2]);
  x=(GEN)module[1];
  if (gcmpgs(vecmax((GEN)module[2]),1)>=0)
    err(talker,"nontrivial Archimedian components in zidealstarinitjoin");

  fa1=(GEN)fact1[1]; ex1=(GEN)fact1[2];
  fa2=(GEN)fact2[1]; ex2=(GEN)fact2[2];
  fact=cgetg(3,t_MAT);
  fact[1]=lconcat(fa1,fa2); lx1=lg(fa1);
  fact[2]=lconcat(ex1,ex2); lx2=lg(fa2);
  nbp=lx1+lx2-2;
  for (i=1; i<lx1; i++)
    if (isinvector(fa2,(GEN)fa1[i],lx2-1))
      err(talker,"noncoprime ideals in zidealstarinitjoin");

  liste1=(GEN)bid1[4]; lx1=lg(liste1);
  liste2=(GEN)bid2[4]; lx2=lg(liste2);
  lx=lx1+lx2-2; liste=cgetg(lx,t_VEC);
  for (i=1; i<lx1-1; i++) liste[i]=liste1[i];
  for (   ; i<lx; i++) liste[i]=liste2[i-lx1+2];
  y=cgetg(6,t_VEC);
  y[1]=(long)module;
  y[3]=(long)fact;
  y[4]=(long)liste;
  U1=(GEN)bid1[5]; lx1=lg(U1);
  U2=(GEN)bid2[5]; lx2=lg(U2);
  lx=lx1+lx2-1;
  llx1=lg(struct1[2]);
  llx2=lg(struct2[2]);
  llx=llx1+llx2-1; nbgen=llx-1;
  if (nbgen)
  {
    cyc=diagonal(concatsp((GEN)struct1[2],(GEN)struct2[2]));
    u1u2=smith2(cyc); u1=(GEN)u1u2[1];
    u1u2=smithclean(u1u2); met=(GEN)u1u2[3]; clh=dethnf(met); c=lg(met)-1;
    U=cgetg(lx,t_MAT);
    for (j=1; j<lx1; j++)
    {
      p1=cgetg(llx,t_COL); p2=(GEN)U1[j]; U[j]=(long)p1;
      for (i=1; i<llx1; i++) p1[i]=p2[i];
      for (   ; i<llx; i++) p1[i]=zero;
    }
    for (  ; j<lx; j++)
    {
      p1=cgetg(llx,t_COL); p2=(GEN)U2[j-lx1+1]; U[j]=(long)p1;
      for (i=1; i<llx1; i++) p1[i]=zero;
      for (   ; i<llx; i++) p1[i]=p2[i-llx1+1];
    }
    y[5]=lmul((GEN)u1u2[1],U);
  }
  else
  {
    clh=gun; met=cgetg(1,t_MAT);
    U=cgetg(lx,t_MAT); for (j=1; j<lx; j++) U[j]=lgetg(1,t_COL);
    y[5]=(long)U; c=0;
  }

  if (compute_gen)
  {
    if (lg(struct1)<=3 || lg(struct2)<=3)
      err(talker,"please apply idealstar(,,2) and not idealstar(,,1)");
    if (nbgen) u1=reducemodmatrix(ginv(u1),cyc); 
    uv = idealaddtoone(nf,(GEN)module1[1],(GEN)module2[1]);
    p1 = makeprimetoidealvec(nf,(GEN)module[1],uv,(GEN)struct1[3]);
    p2=(GEN)uv[1]; uv[1]=uv[2]; uv[2]=(long)p2;
    p2 = makeprimetoidealvec(nf,(GEN)module[1],uv,(GEN)struct2[3]);
    allgenerator=concatsp(p1,p2);

    basecl=cgetg(c+1,t_VEC); unnf=gscalcol_i(gun,N);
    for (j=1; j<=c; j++)
    {
      p3plus=unnf; p3moins=unnf;
      for (i=1; i<=nbgen; i++)
      {
	p1=gcoeff(u1,i,j); s=signe(p1);
	if (s)
	{
	  if (s>0)
	    p3plus = element_mul(nf,p3plus,(GEN)element_pow(nf,(GEN)allgenerator[i],p1));
	  else
	    p3moins = element_mul(nf,p3moins,(GEN)element_pow(nf,(GEN)allgenerator[i],negi(p1)));
	}
      }
      if (nbp)
      {
	p6=idealaddtoone(nf,p3moins,x);
	/* p4 = p3moins^(-1) modulo x */
	p4=element_div(nf,(GEN)p6[1],p3moins);
	p3=element_mulmodideal(nf,p3plus,p4,x);
      }
      else p3=unnf;
      basecl[j]=(long)p3;
    }
    p1=cgetg(4,t_VEC); p1[3]=(long)basecl;
  }
  else p1=cgetg(3,t_VEC);

  y[2]=(long)p1;
  p1[1]=(long)clh; mot=cgetg(c+1,t_VEC); p1[2]=(long)mot;
  for (i=1; i<=c; i++) mot[i]=coeff(met,i,i);
  tetpil=avma; return gerepile(av,tetpil,gcopy(y));
}

GEN
zidealstarinitjoin(GEN nf, GEN bid1, GEN bid2)
{
  return zidealstarinitjoinall(nf,bid1,bid2,0);
}

GEN
zidealstarinitjoingen(GEN nf, GEN bid1, GEN bid2)
{
  return zidealstarinitjoinall(nf,bid1,bid2,1);
}

/* Etant donnes bid1 resultat de zidealstarinit pour un module m1 sans partie
 * archimedienne et une partie archimedienne arch, calcule le zidealstarinit
 * [[ideal,arch],[h,[cyc],[gen]],idealfact,[liste],U] du produit
 */
static GEN
zidealstarinitjoinarchall(GEN nf, GEN bid1, GEN arch, long nba, long compute_gen)
{
  long av=avma,tetpil,i,j,nbp,N,c,s,nbgen,lx1,lx,llx1,llx;
  GEN module1,struct1,fact1,liste1,U1;
  GEN module,liste,h;
  GEN p1,p2,p3,p3plus,p3moins,p4,p5,p6,y,clh,met,u1,basecl,mot,generator;
  GEN x,allgenerator,structarch,u1u2;
  GEN unnf;

  nf=checknf(nf); N=lgef(nf[1])-3;
  checkbid(bid1);
  module1=(GEN)bid1[1]; struct1=(GEN)bid1[2]; fact1=(GEN)bid1[3];
  nbp=lg((GEN)fact1[1])-1;
  x=(GEN)module1[1];
  structarch = zarchstar(nf,x,arch,nba);
  module=cgetg(3,t_VEC); module[1]=module1[1]; module[2]=(long)arch;
  if (gcmpgs(vecmax((GEN)module1[2]),1)>=0)
    err(talker,"nontrivial Archimedian components in zidealstarinitjoinarchall");
  liste1=(GEN)bid1[4]; lx=lg(liste1);
  liste=cgetg(lx,t_VEC); for (i=1; i<lx-1; i++) liste[i]=liste1[i];
  liste[lx-1]=(long)structarch;
  U1=(GEN)bid1[5]; lx1=lg(U1);
  lx=lx1+nba; llx1=lg(struct1[2]); llx=llx1+nba; nbgen=llx-1;
  y=cgetg(6,t_VEC); 
  y[1]=(long)module;
  y[3]=(long)fact1;
  y[4]=(long)liste;
  if (nbgen)
  {
    h=diagonal(concatsp((GEN)struct1[2],(GEN)structarch[1]));
    u1u2=smith2(h);
    if (compute_gen)
      u1 = reducemodmatrix(ginv((GEN)u1u2[1]),h);
    u1u2=smithclean(u1u2);
    met=(GEN)u1u2[3]; y[5]=u1u2[1];
    clh=dethnf(met); c=lg(met)-1;
  }
  else
  { 
    clh=gun; met=cgetg(1,t_MAT);
    u1=cgetg(1,t_MAT); y[5]=(long)u1; c=0;
  }

  if (compute_gen)
  {
    if (lg(struct1)<=3)
      err(talker,"please apply idealstar(,,2) and not idealstar(,,1)");
    allgenerator=concatsp((GEN)struct1[3],(GEN)structarch[2]);

    basecl=cgetg(c+1,t_VEC); unnf=gscalcol_i(gun,N);
    for (j=1; j<=c; j++)
    {
      p3plus = p3moins = unnf;
      for (i=1; i<=nbgen; i++)
      {
	p1=gcoeff(u1,i,j); s=signe(p1);
	if (s)
	{
	  if (s>0)
	    p3plus = element_mul(nf,p3plus,(GEN)element_pow(nf,(GEN)allgenerator[i],p1));
	  else
	    p3moins = element_mul(nf,p3moins,(GEN)element_pow(nf,(GEN)allgenerator[i],negi(p1)));
	}
      }
      if (nbp)
      {
	p6=idealaddtoone(nf,p3moins,x);
	/* p4 = p3moins^(-1) modulo x */
	p4=element_div(nf,(GEN)p6[1],p3moins);
	p3=element_mulmodideal(nf,p3plus,p4,x);
      }
      else p3=unnf;

      /* on corrige pour que p3 ait la meme signature que p3plus/p3moins */
      generator=(GEN)structarch[2];
      p5=gadd(gadd(zsigne(nf,p3,arch),zsigne(nf,p3plus,arch)),
              zsigne(nf,p3moins,arch));
      p2=lift_intern(gmul((GEN)structarch[3],p5));
      for (i=1; i<=nba; i++)
	if (signe(p2[i])) p3=element_mul(nf,p3,(GEN)generator[i]);
      basecl[j]=(long)p3;
    }
    p1=cgetg(4,t_VEC); p1[3]=(long)basecl;
  }
  else p1=cgetg(3,t_VEC);

  y[2]=(long)p1;
  p1[1]=(long)clh; mot=cgetg(c+1,t_VEC); p1[2]=(long)mot;
  for (i=1; i<=c; i++) mot[i]=coeff(met,i,i);
  tetpil=avma; return gerepile(av,tetpil,gcopy(y));
}

GEN
zidealstarinitjoinarch(GEN nf, GEN bid1, GEN arch, long nba)
{
  return zidealstarinitjoinarchall(nf,bid1,arch,nba,0);
}

GEN
zidealstarinitjoinarchgen(GEN nf, GEN bid1, GEN arch, long nba)
{
  return zidealstarinitjoinarchall(nf,bid1,arch,nba,1);
}

/* calcule la matrice des zinternallog des unites */
GEN
logunitmatrix(GEN nf,GEN funits,GEN racunit,GEN bid)
{
  long R,j,sizeh;
  GEN m,fa2,fa,arch;

  R=lg(funits)-1; m=cgetg(R+2,t_MAT);
  fa2=(GEN)bid[4]; sizeh=lg(bid[5])-1; arch=gmael(bid,1,2);
  fa=(GEN)bid[3];
  m[1]=(long)zinternallog(nf,fa2,sizeh,arch,fa,racunit,0);
  for (j=2; j<=R+1; j++)
    m[j]=(long)zinternallog(nf,fa2,sizeh,arch,fa,(GEN)funits[j-1],0);
  return m;
}

/* calcule la matrice des zinternallog des unites */
static GEN
logunitmatrixarch(GEN nf,GEN funits,GEN racunit,GEN bid)
{
  long R,j;
  GEN m,liste,structarch,arch;

  R=lg(funits)-1; m=cgetg(R+2,t_MAT); arch=gmael(bid,1,2);
  liste=(GEN)bid[4]; structarch=(GEN)liste[lg(liste)-1];
  m[1]=(long)zsigne(nf,racunit,arch);
  for (j=2; j<=R+1; j++)
    m[j]=(long)zsigne(nf,(GEN)funits[j-1],arch);
  return lift_intern(gmul((GEN)structarch[3],m));
}

/* concatenation verticale de Q1 et Q2. Ne cree pas le resultat. */
GEN
vconcat(GEN Q1, GEN Q2)
{
  long lc,lr,lx1,lx2,i,j;
  GEN m,p1,p2,p3;

  lc=lg(Q1); if (lc==1) return Q1;
  lx1=lg(Q1[1]); lx2=lg(Q2[1]); lr=lx1+lx2-1;
  m=cgetg(lc,t_MAT);
  for (j=1; j<lc; j++)
  {
    p1=cgetg(lr,t_COL); m[j]=(long)p1; p2=(GEN)Q1[j]; p3=(GEN)Q2[j];
    for (i=1; i<lx1; i++) p1[i]=p2[i];
    for (   ; i<lr; i++) p1[i]=p3[i-lx1+1];
  }
  return m;
}

static void
init_units(GEN bnf, GEN *funits, GEN *racunit)
{
  GEN p1;
  checkbnf(bnf); p1=(GEN)bnf[8]; 
  if (lg(p1)==5) *funits=(GEN)buchfu(bnf)[1];
  else
  {
    if (lg(p1)!=7) err(talker,"incorrect big number field");
    *funits=(GEN)p1[5];
  }
  *racunit=gmael(p1,4,2);
}

/*  flag &1 : generateurs, sinon non
 *  flag &2 : unites, sinon pas.
 *  flag &4 : ideaux, sinon zidealstar.
 */
static GEN
ideallistzstarall(GEN bnf,long bound,long flag)
{
  byteptr ptdif=diffptr;
  long lim,av0=avma,av,tetpil,i,j,k,l,p2s,lp1;
  long do_gen = flag & 1, do_units = flag & 2, big_id = !(flag & 4);
  ulong q;
  GEN y,nf,p,z,z2,p1,p2,p3,fa,pr,ideal,bidp,lu,lu2,funits,racunit,embunit;

  nf=checknf(bnf); z=cgetg(bound+1,t_VEC); z2=cgetg(bound+1,t_VEC);
  for (i=1; i<=bound; i++) z[i]=lgetg(1,t_VEC);
  if (do_units)
  {
    init_units(bnf,&funits,&racunit);
    lu=cgetg(bound+1,t_VEC); lu2=cgetg(bound+1,t_VEC);
    for (i=1; i<=bound; i++) lu[i]=lgetg(1,t_VEC);
  }
  p1=cgetg(2,t_VEC); z[1]=(long)p1;
  p1[1]=(long)idmat(lgef(nf[1])-3);
  if (big_id) p1[1]=(long)zidealstarinitall(nf,(GEN)p1[1],do_gen);
  if (do_units)
  {
    p2=cgetg(2,t_VEC); lu[1]=(long)p2;
    p2[1]=(long)logunitmatrix(nf,funits,racunit,(GEN)p1[1]);
  }
  p=cgeti(3); p[1]=evalsigne(1)+evallgefint(3);
  av=avma; lim=(bot+av)>>1;
  for (p[2]=0; p[2]<=bound; )
  {
    if (!*ptdif) err(primer1);
    p[2] += *ptdif++;
    if (DEBUGLEVEL>=2) { fprintferr("%ld ",p[2]); flusherr(); }
    fa=primedec(nf,p);
    for (j=1; j<lg(fa); j++)
    {
      pr=(GEN)fa[j]; p1=gpui(p,(GEN)pr[4],0); q = p1[2];
      if (lgefint(p1)==3 && q < HIGHBIT && q <= bound)
      {
	p2s=q; ideal=pr; z2=dummycopy(z); 
        if (do_units) lu2=dummycopy(lu);
        for (l=2; ;l++)
	{
	  if (big_id) bidp=zidealstarinitall(nf,ideal,do_gen);
	  if (do_units) embunit=logunitmatrix(nf,funits,racunit,bidp);
	  for (i=q; i<=bound; i+=q)
	  {
	    p1=(GEN)z[i/q]; lp1=lg(p1);
	    if (lp1>1)
	    {
	      p2=cgetg(lp1,t_VEC);
	      for (k=1; k<lp1; k++)
		if (big_id)
		  p2[k]=(long)zidealstarinitjoinall(nf,(GEN)p1[k],bidp,do_gen);
		else
		  p2[k]=(long)idealmul(nf,(GEN)p1[k],ideal);
	      z2[i]=(long)concatsp((GEN)z2[i],p2);
              if (do_units)
              {
                p1=(GEN)lu[i/q]; p2=cgetg(lp1,t_VEC);
                for (k=1; k<lp1; k++)
                  p2[k]=(long)vconcat((GEN)p1[k],embunit);
                lu2[i] = (long)concatsp((GEN)lu2[i],p2);
              }
	    }
	  }
	  q *= p2s; if ((ulong)q > (ulong)bound) break;
          ideal = idealpows(nf,pr,l);
	}
	z=z2; if (do_units) lu=lu2;
      }
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      GEN *gptr[2];
      if(DEBUGMEM>1) err(warnmem,"ideallistzstarall");
      if (do_units) { gptr[1]=&lu; i=2; } else i=1;
      gptr[0]=&z; gerepilemany(av,gptr,i);
    }
  }
  tetpil=avma; 
  if (!do_units) return gerepile(av0,tetpil,gcopy(z));
  y=cgetg(3,t_VEC); y[1]=lcopy(z); lu2=cgetg(lg(z),t_VEC);
  for (i=1; i<lg(z); i++)
  {
    p1=(GEN)z[i]; p2=(GEN)lu[i]; lp1=lg(p1);
    p3=cgetg(lp1,t_VEC); lu2[i]=(long)p3;
    for (j=1; j<lp1; j++) p3[j] = lmul(gmael(p1,j,5),(GEN)p2[j]);
  }
  y[2]=(long)lu2; return gerepile(av0,tetpil,y);
}

GEN
ideallist0(GEN bnf,long bound, long flag)
{
  if (flag<0 || flag>4) err(flagerr);
  return ideallistzstarall(bnf,bound,flag);
}

GEN
ideallistzstar(GEN nf,long bound)
{
  return ideallistzstarall(nf,bound,0);
}

GEN
ideallistzstargen(GEN nf,long bound)
{
  return ideallistzstarall(nf,bound,1);
}

GEN
ideallistunit(GEN nf,long bound)
{
  return ideallistzstarall(nf,bound,2);
}

GEN
ideallistunitgen(GEN nf,long bound)
{
  return ideallistzstarall(nf,bound,3);
}

GEN
ideallist(GEN bnf,long bound)
{
  return ideallistzstarall(bnf,bound,4);
}

static GEN
ideallist_arch(GEN nf,GEN list,GEN arch,long flun)
{
  long nba,i,j,lx,ly;
  GEN p1,z,p2;

  nba=0; for (i=1; i<lg(arch); i++) if (signe(arch[i])) nba++;
  lx=lg(list); z=cgetg(lx,t_VEC);
  for (i=1; i<lx; i++)
  {
    p2=(GEN)list[i]; ly=lg(p2); p1=cgetg(ly,t_VEC); z[i]=(long)p1;
    for (j=1; j<ly; j++)
      p1[j]=(long)zidealstarinitjoinarchall(nf,(GEN)p2[j],arch,nba,flun);
  }
  return z;
}

static GEN
ideallistarchall(GEN bnf,GEN list,GEN arch,long flag)
{
  long av,tetpil,i,j,lp1;
  long do_units = flag & 2;
  GEN nf,p1,p2,p3,racunit,funits,lu2,lu,embunit,z,y;

  nf=checknf(bnf); y=cgetg(3,t_VEC);
  z = ideallist_arch(nf,(GEN)list[1],arch, flag & 1);
  if (!do_units) return z;
  y[1]=(long)z; av=avma;
  init_units(bnf,&funits,&racunit);
  lu=(GEN)list[2]; lu2=cgetg(lg(z),t_VEC);
  for (i=1; i<lg(z); i++)
  {
    p1=(GEN)z[i]; p2=(GEN)lu[i]; lp1=lg(p1);
    p3=cgetg(lp1,t_VEC); lu2[i]=(long)p3;
    for (j=1; j<lp1; j++)
    {
      embunit = logunitmatrixarch(nf,funits,racunit,(GEN)p1[j]);
      p3[j] = lmul(gmael(p1,j,5), vconcat((GEN)p2[j],embunit));
    }
  }
  tetpil=avma; y[2]=lpile(av,tetpil,gcopy(lu2)); return y;
}

GEN
ideallistarch(GEN nf, GEN list, GEN arch)
{
  return ideallistarchall(nf,list,arch,0);
}

GEN
ideallistarchgen(GEN nf, GEN list, GEN arch)
{
  return ideallistarchall(nf,list,arch,1);
}

GEN
ideallistunitarch(GEN bnf,GEN list,GEN arch)
{
  return ideallistarchall(bnf,list,arch,2);
}

GEN
ideallistunitarchgen(GEN bnf,GEN list,GEN arch)
{
  return ideallistarchall(bnf,list,arch,3);
}

GEN
ideallistarch0(GEN nf, GEN list, GEN arch,long flag)
{
  if (!arch) arch=cgetg(1,t_VEC);
  if (flag<0 || flag>3) err(flagerr);
  return ideallistarchall(nf,list,arch,flag);
}
