示例#1
0
文件: nffactor.c 项目: BENGMN/soen490
static GEN
nf_LLL_cmbf(nfcmbf_t *T, GEN p, long k, long rec)
{
  nflift_t *L = T->L;
  GEN pk = L->pk, PRK = L->prk, PRKinv = L->iprk, GSmin = L->GSmin;
  GEN Tpk = L->Tpk;

  GEN famod = T->fact, nf = T->nf, ZC = T->ZC, Br = T->Br;
  GEN Pbase = T->polbase, P = T->pol, dn = T->dn;
  GEN nfT = gel(nf,1);
  GEN Btra;
  long dnf = degpol(nfT), dP = degpol(P);

  double BitPerFactor = 0.5; /* nb bits / modular factor */
  long i, C, tmax, n0;
  GEN lP, Bnorm, Tra, T2, TT, CM_L, m, list, ZERO;
  double Bhigh;
  pari_sp av, av2, lim;
  long ti_LLL = 0, ti_CF = 0;
  pari_timer ti2, TI;

  lP = absi(leading_term(P));
  if (is_pm1(lP)) lP = NULL;

  n0 = lg(famod) - 1;
 /* Lattice: (S PRK), small vector (vS vP). To find k bound for the image,
  * write S = S1 q + S0, P = P1 q + P0
  * |S1 vS + P1 vP|^2 <= Bhigh for all (vS,vP) assoc. to true factors */
  Btra = mulrr(ZC, mulsr(dP*dP, normlp(Br, 2, dnf)));
  Bhigh = get_Bhigh(n0, dnf);
  C = (long)ceil(sqrt(Bhigh/n0)) + 1; /* C^2 n0 ~ Bhigh */
  Bnorm = dbltor( n0 * C * C + Bhigh );
  ZERO = zeromat(n0, dnf);

  av = avma; lim = stack_lim(av, 1);
  TT = cgetg(n0+1, t_VEC);
  Tra  = cgetg(n0+1, t_MAT);
  for (i=1; i<=n0; i++) TT[i] = 0;
  CM_L = gscalsmat(C, n0);
  /* tmax = current number of traces used (and computed so far) */
  for(tmax = 0;; tmax++)
  {
    long a, b, bmin, bgood, delta, tnew = tmax + 1, r = lg(CM_L)-1;
    GEN oldCM_L, M_L, q, S1, P1, VV;
    int first = 1;

    /* bound for f . S_k(genuine factor) = ZC * bound for T_2(S_tnew) */
    Btra = mulrr(ZC, mulsr(dP*dP, normlp(Br, 2*tnew, dnf)));
    bmin = logint(ceil_safe(sqrtr(Btra)), gen_2, NULL);
    if (DEBUGLEVEL>2)
      fprintferr("\nLLL_cmbf: %ld potential factors (tmax = %ld, bmin = %ld)\n",
                 r, tmax, bmin);

    /* compute Newton sums (possibly relifting first) */
    if (gcmp(GSmin, Btra) < 0)
    {
      nflift_t L1;
      GEN polred;

      bestlift_init(k<<1, nf, T->pr, Btra, &L1);
      polred = ZqX_normalize(Pbase, lP, &L1);
      k      = L1.k;
      pk     = L1.pk;
      PRK    = L1.prk;
      PRKinv = L1.iprk;
      GSmin  = L1.GSmin;
      Tpk    = L1.Tpk;
      famod = hensel_lift_fact(polred, famod, Tpk, p, pk, k);
      for (i=1; i<=n0; i++) TT[i] = 0;
    }
    for (i=1; i<=n0; i++)
    {
      GEN h, lPpow = lP? gpowgs(lP, tnew): NULL;
      GEN z = polsym_gen(gel(famod,i), gel(TT,i), tnew, Tpk, pk);
      gel(TT,i) = z;
      h = gel(z,tnew+1);
      /* make Newton sums integral */
      lPpow = mul_content(lPpow, dn);
      if (lPpow) h = FpX_red(gmul(h,lPpow), pk);
      gel(Tra,i) = nf_bestlift(h, NULL, L); /* S_tnew(famod) */
    }

    /* compute truncation parameter */
    if (DEBUGLEVEL>2) { TIMERstart(&ti2); TIMERstart(&TI); }
    oldCM_L = CM_L;
    av2 = avma;
    b = delta = 0; /* -Wall */
AGAIN:
    M_L = Q_div_to_int(CM_L, utoipos(C));
    VV = get_V(Tra, M_L, PRK, PRKinv, pk, &a);
    if (first)
    { /* initialize lattice, using few p-adic digits for traces */
      bgood = (long)(a - max(32, BitPerFactor * r));
      b = max(bmin, bgood);
      delta = a - b;
    }
    else
    { /* add more p-adic digits and continue reduction */
      if (a < b) b = a;
      b = max(b-delta, bmin);
      if (b - delta/2 < bmin) b = bmin; /* near there. Go all the way */
    }

    /* restart with truncated entries */
    q = int2n(b);
    P1 = gdivround(PRK, q);
    S1 = gdivround(Tra, q);
    T2 = gsub(gmul(S1, M_L), gmul(P1, VV));
    m = vconcat( CM_L, T2 );
    if (first)
    {
      first = 0;
      m = shallowconcat( m, vconcat(ZERO, P1) );
      /*     [ C M_L   0  ]
       * m = [            ]   square matrix
       *     [  T2'   PRK ]   T2' = Tra * M_L  truncated
       */
    }
    CM_L = LLL_check_progress(Bnorm, n0, m, b == bmin, /*dbg:*/ &ti_LLL);
    if (DEBUGLEVEL>2)
      fprintferr("LLL_cmbf: (a,b) =%4ld,%4ld; r =%3ld -->%3ld, time = %ld\n",
                 a,b, lg(m)-1, CM_L? lg(CM_L)-1: 1, TIMER(&TI));
    if (!CM_L) { list = mkcol(QXQX_normalize(P,nfT)); break; }
    if (b > bmin)
    {
      CM_L = gerepilecopy(av2, CM_L);
      goto AGAIN;
    }
    if (DEBUGLEVEL>2) msgTIMER(&ti2, "for this trace");

    i = lg(CM_L) - 1;
    if (i == r && gequal(CM_L, oldCM_L))
    {
      CM_L = oldCM_L;
      avma = av2; continue;
    }

    if (i <= r && i*rec < n0)
    {
      pari_timer ti;
      if (DEBUGLEVEL>2) TIMERstart(&ti);
      list = nf_chk_factors(T, P, Q_div_to_int(CM_L,utoipos(C)), famod, pk);
      if (DEBUGLEVEL>2) ti_CF += TIMER(&ti);
      if (list) break;
      CM_L = gerepilecopy(av2, CM_L);
    }
    if (low_stack(lim, stack_lim(av,1)))
    {
      if(DEBUGMEM>1) pari_warn(warnmem,"nf_LLL_cmbf");
      gerepileall(av, Tpk? 9: 8,
                      &CM_L,&TT,&Tra,&famod,&pk,&GSmin,&PRK,&PRKinv,&Tpk);
    }
  }
  if (DEBUGLEVEL>2)
    fprintferr("* Time LLL: %ld\n* Time Check Factor: %ld\n",ti_LLL,ti_CF);
  return list;
}
engine_RawRingElementArrayOrNull rawRoots(const RingElement *p, long prec,
                                          int unique) {
  const Ring *R = p->get_ring();
  const PolynomialRing *P = R->cast_to_PolynomialRing();
  if (P == 0) {
    ERROR("expected a polynomial ring");
    return NULL;
  }
  const int n = P->n_vars();
  if (n != 1) {
    ERROR("expected a univariate polynomial ring");
    return NULL;
  }
  const Ring *K = P->getCoefficients();
  int degree = 0;
  for (Nterm *t = p->get_value(); t != NULL; t = t->next) {
    degree = max(degree, abs(*(t->monom)));
  }
  if (prec == -1) {
    prec = (K->get_precision() == 0 ? 53 : K->get_precision());
  }

  engine_RawRingElementArrayOrNull result = nullptr;

  /* Start PARI computations. */
  pari_CATCH(e_STACK) {
#ifdef NDEBUG
    /*
     * Every time the stack is changed PARI writes a message to the file pari_errfile
     * which by default is /dev/stderr. To avoid showing this message to the user we
     * redirect to /dev/null before the PARI's stack is modified.
     */
    FILE *tmp, *dev_null = fopen("/dev/null", "w");
    if (dev_null != NULL) {
      tmp = pari_errfile;
      pari_errfile = dev_null;
    }
#endif
  allocatemem(0); // passing 0 will double the current stack size.
#ifdef NDEBUG
    /*
     * We set pari_errfile back to the default value just in case PARI crashes.
     */
    if (dev_null != NULL) {
      pari_errfile = tmp;
      fclose(dev_null);
    }
#endif
  } pari_RETRY {
    const pari_sp av = avma;

    GEN q = cgetg(2 + degree + 1, t_POL);
    setsigne(q, 1);
    setvarn(q, 0);
    for (int i = 0; i < degree + 1; ++i) {
      gel(q, 2 + i) = gen_0;
    }

    switch (K->ringID()) {
    case M2::ring_ZZ:
    ZZ_GMP:
      for (Nterm *t = p->get_value(); t != NULL; t = t->next) {
        gel(q, 2 + abs(*(t->monom))) =
            mpz_get_GEN(reinterpret_cast<const mpz_ptr>(t->coeff.poly_val));
      }
      break;
    case M2::ring_QQ:
      for (Nterm *t = p->get_value(); t != NULL; t = t->next) {
        gel(q, 2 + abs(*(t->monom))) =
            mpq_get_GEN(reinterpret_cast<const mpq_ptr>(t->coeff.poly_val));
      }
      break;
    case M2::ring_RR:
      pari_CATCH(e_OVERFLOW) {
        ERROR("coefficient is NaN or Infinity");
        avma = av;
        return NULL;
      }
      pari_TRY {
        for (Nterm *t = p->get_value(); t != NULL; t = t->next) {
          gel(q, 2 + abs(*(t->monom))) =
              dbltor(*reinterpret_cast<double *>(t->coeff.poly_val));
        }
      }
      pari_ENDCATCH
      break;
    case M2::ring_CC:
      pari_CATCH(e_OVERFLOW) {
        ERROR("coefficient is NaN or Infinity");
        avma = av;
        return NULL;
      }
      pari_TRY {
        for (Nterm *t = p->get_value(); t != NULL; t = t->next) {
          GEN z = cgetg(3, t_COMPLEX);
          gel(z, 1) = dbltor(reinterpret_cast<complex *>(t->coeff.poly_val)->re);
          gel(z, 2) = dbltor(reinterpret_cast<complex *>(t->coeff.poly_val)->im);
          gel(q, 2 + abs(*(t->monom))) = z;
        }
      }
      pari_ENDCATCH
      break;
    case M2::ring_RRR:
      for (Nterm *t = p->get_value(); t != NULL; t = t->next) {
        gel(q, 2 + abs(*(t->monom))) =
            mpfr_get_GEN(reinterpret_cast<const mpfr_ptr>(t->coeff.poly_val));
      }
      break;
    case M2::ring_CCC:
      for (Nterm *t = p->get_value(); t != NULL; t = t->next) {
        gel(q, 2 + abs(*(t->monom))) =
            mpc_get_GEN(reinterpret_cast<const mpc_ptr>(t->coeff.poly_val));
      }
      break;
    case M2::ring_old:
      if (K->is_ZZ()) {
        goto ZZ_GMP;
      }
    default:
      ERROR("expected coefficient ring of the form ZZ, QQ, RR or CC");
      return NULL;
    }

    if (unique) {
      q = RgX_div(q, RgX_gcd_simple(q, RgX_deriv(q)));
    }

    GEN roots = cleanroots(q, nbits2prec(prec));

    const size_t num_roots = lg(roots) - 1;
    result = getmemarraytype(engine_RawRingElementArray, num_roots);
    result->len = static_cast<int>(num_roots);

    ring_elem m2_root;
    if (prec <= 53) {
      const RingCC *CC = dynamic_cast<const RingCC *>(IM2_Ring_CCC(prec));

      for (int i = 0; i < num_roots; ++i) {
        const pari_sp av2 = avma;

        GEN pari_root = gel(roots, 1 + i);
        const complex root = {rtodbl(greal(pari_root)),
                              rtodbl(gimag(pari_root))};
        CC->ring().to_ring_elem(m2_root, root);
        result->array[i] = RingElement::make_raw(CC, m2_root);

        avma = av2;
      }
    } else {
      const RingCCC *CCC = dynamic_cast<const RingCCC *>(IM2_Ring_CCC(prec));

      for (int i = 0; i < num_roots; ++i) {
        const pari_sp av2 = avma;

        mpc_t root;
        auto root1 = reinterpret_cast<mpfc_t*>(&root);
        pari_mpc_init_set_GEN(root, gel(roots, 1 + i), GMP_RNDN);
        //        CCC->ring().to_ring_elem(m2_root, **reinterpret_cast<mpfc_t*>(&root));
        CCC->ring().to_ring_elem(m2_root, **root1);
        result->array[i] = RingElement::make_raw(CCC, m2_root);

        avma = av2;
      }
    }

    /* End PARI computations. */
    avma = av;
  }
  pari_ENDCATCH

  return result;
}