source: git/factory/cf_map_ext.cc @ ec8f57

spielwiese
Last change on this file since ec8f57 was ec8f57, checked in by Hans Schoenemann <hannes@…>, 4 years ago
fix: typo
  • Property mode set to 100644
File size: 17.0 KB
Line 
1// -*- c++ -*-
2//*****************************************************************************
3/** @file cf_map_ext.cc
4 *
5 * This file implements functions to map between extensions of finite fields
6 *
7 * @par Copyright:
8 *   (c) by The SINGULAR Team, see LICENSE file
9 *
10 * @author Martin Lee
11 * @date   16.11.2009
12**/
13//*****************************************************************************
14
15
16#include "config.h"
17
18
19#include "cf_assert.h"
20#include "debug.h"
21
22#include "canonicalform.h"
23#include "cf_util.h"
24#include "imm.h"
25#include "cf_iter.h"
26
27#ifdef HAVE_NTL
28#include "NTLconvert.h"
29#endif
30
31#ifdef HAVE_FLINT
32#include "FLINTconvert.h"
33#endif
34
35// cyclotomoic polys:
36#include "cf_cyclo.h"
37
38#include "cf_map_ext.h"
39
40/// helper function
41int findItem (const CFList& list, const CanonicalForm& item)
42{
43  int result= 1;
44  for (CFListIterator i= list; i.hasItem(); i++, result++)
45  {
46    if (i.getItem() == item)
47      return result;
48  }
49  return 0;
50}
51
52/// helper function
53CanonicalForm getItem (const CFList& list, const int& pos)
54{
55  int j= 1;
56  if ((pos > 0) && (pos <= list.length()))
57  {
58    for (CFListIterator i= list; j <= pos; i++, j++)
59    {
60      if (j == pos)
61        return i.getItem();
62    }
63  }
64  return 0;
65}
66
67/// \f$ F_{p} (\alpha ) \subset F_{p}(\beta ) \f$ and \f$ \alpha \f$ is a
68/// primitive element, returns the image of \f$ \alpha \f$
69static inline
70CanonicalForm mapUp (const Variable& alpha, const Variable& beta)
71{
72  int p= getCharacteristic ();
73  #ifdef HAVE_FLINT
74    // convert mipo1
75    nmod_poly_t mipo1;
76    convertFacCF2nmod_poly_t(mipo1,getMipo(beta));
77    fq_nmod_ctx_t ctx;
78    fq_nmod_ctx_init_modulus(ctx,mipo1,"t");
79    nmod_poly_clear(mipo1);
80    // convert mipo2 (alpah)
81    fq_nmod_poly_t mipo2;
82    convertFacCF2Fq_nmod_poly_t(mipo2,getMipo(alpha),ctx);
83    fq_nmod_poly_factor_t fac;
84    fq_nmod_poly_factor_init(fac,ctx);
85    fq_nmod_poly_roots(fac, mipo2, 0, ctx);
86    // root of first (linear) factor: -absolute Term
87    fq_nmod_t r0;
88    fq_nmod_init(r0, ctx);
89    fq_nmod_poly_get_coeff(r0,fac->poly,0,ctx);
90    fq_nmod_neg(r0, r0, ctx);
91    // convert
92    CanonicalForm r1=convertFq_nmod_t2FacCF(r0,beta,ctx);
93    // cleanup
94    fq_nmod_poly_factor_clear(fac,ctx);
95    fq_nmod_clear(r0, ctx);
96    fq_nmod_poly_clear(mipo2,ctx);
97    fq_nmod_ctx_clear(ctx);
98    return r1;
99  #elif defined(HAVE_NTL)
100  if (fac_NTL_char != p)
101  {
102    fac_NTL_char= p;
103    zz_p::init (p);
104  }
105  zz_pX NTL_mipo= convertFacCF2NTLzzpX (getMipo (beta));
106  zz_pE::init (NTL_mipo);
107  zz_pEX NTL_alpha_mipo= convertFacCF2NTLzz_pEX (getMipo(alpha), NTL_mipo);
108  zz_pE root= FindRoot (NTL_alpha_mipo);
109  return convertNTLzzpE2CF (root, beta);
110  #endif
111}
112
113
114/// the CanonicalForm G is the output of map_up, returns F considered as an
115/// element over \f$ F_{p}(\alpha ) \f$, WARNING: make sure coefficients of F
116/// are really elements of a subfield of \f$ F_{p}(\beta ) \f$ which is
117/// isomorphic to \f$ F_{p}(\alpha ) \f$
118static inline
119CanonicalForm
120mapDown (const CanonicalForm& F, const Variable& alpha, const
121          CanonicalForm& G, CFList& source, CFList& dest)
122{
123  CanonicalForm buf, buf2;
124  int counter= 0;
125  int pos;
126  int p= getCharacteristic();
127  int d= degree(getMipo(alpha));
128  int bound= ipower(p, d);
129  CanonicalForm result= 0;
130  CanonicalForm remainder;
131  CanonicalForm alpha_power;
132  if (degree(F) == 0) return F;
133  if (F.level() < 0 && F.isUnivariate())
134  {
135    buf= F;
136    remainder= mod (buf, G);
137    ASSERT (remainder.isZero(), "alpha is not primitive");
138    pos= findItem (source, buf);
139    if (pos == 0)
140      source.append (buf);
141    buf2= buf;
142    while (degree (buf) != 0 && counter < bound)
143    {
144      buf /= G;
145      counter++;
146      if (buf == buf2) break;
147    }
148    ASSERT (counter >= bound, "alpha is not primitive");
149    if (pos == 0)
150    {
151      alpha_power= power (alpha, counter);
152      dest.append (alpha_power);
153    }
154    else
155      alpha_power= getItem (dest, pos);
156    result = alpha_power;
157    return result;
158  }
159  else
160  {
161    for (CFIterator i= F; i.hasTerms(); i++)
162    {
163      buf= mapDown (i.coeff(), alpha, G, source, dest);
164      result += buf*power(F.mvar(), i.exp());
165    }
166    return result;
167  }
168}
169
170/// helper function
171static inline
172CanonicalForm GF2FalphaHelper (const CanonicalForm& F, const Variable& alpha)
173{
174  if (F.isZero())
175    return 0;
176  int exp;
177  CanonicalForm result= 0;
178  InternalCF* buf;
179  if (F.inBaseDomain())
180  {
181    if (F.isOne()) return 1;
182    buf= F.getval();
183    exp= imm2int(buf);
184    result= power (alpha, exp).mapinto();
185    return result;
186  }
187  for (CFIterator i= F; i.hasTerms(); i++)
188    result += GF2FalphaHelper (i.coeff(), alpha)*power (F.mvar(), i.exp());
189  return result;
190}
191
192CanonicalForm GF2FalphaRep (const CanonicalForm& F, const Variable& alpha)
193{
194  Variable beta= rootOf (gf_mipo);
195  CanonicalForm result= GF2FalphaHelper (F, beta) (alpha, beta);
196  prune (beta);
197  return result;
198}
199
200CanonicalForm Falpha2GFRep (const CanonicalForm& F)
201{
202  CanonicalForm result= 0;
203  InternalCF* buf;
204
205  if (F.inCoeffDomain())
206  {
207    if (F.inBaseDomain())
208      return F.mapinto();
209    else
210    {
211      for (CFIterator i= F; i.hasTerms(); i++)
212      {
213        buf= int2imm_gf (i.exp());
214        result += i.coeff().mapinto()*CanonicalForm (buf);
215      }
216    }
217    return result;
218  }
219  for (CFIterator i= F; i.hasTerms(); i++)
220    result += Falpha2GFRep (i.coeff())*power (F.mvar(), i.exp());
221  return result;
222}
223
224/// GF_map_up helper
225static inline
226CanonicalForm GFPowUp (const CanonicalForm & F, int k)
227{
228  if (F.isOne()) return F;
229  CanonicalForm result= 0;
230  if (F.inBaseDomain())
231    return power(F, k);
232  for (CFIterator i= F; i.hasTerms(); i++)
233    result += GFPowUp (i.coeff(), k)*power (F.mvar(), i.exp());
234  return result;
235}
236
237CanonicalForm GFMapUp (const CanonicalForm & F, int k)
238{
239  int d= getGFDegree();
240  ASSERT (d%k == 0, "multiple of GF degree expected");
241  int p= getCharacteristic();
242  int ext_field_size= ipower (p, d);
243  int field_size= ipower ( p, k);
244  int diff= (ext_field_size - 1)/(field_size - 1);
245  return GFPowUp (F, diff);
246}
247
248/// GFMapDown helper
249static inline
250CanonicalForm GFPowDown (const CanonicalForm & F, int k)
251{
252  if (F.isOne()) return F;
253  CanonicalForm result= 0;
254  int exp;
255  InternalCF* buf;
256  if (F.inBaseDomain())
257  {
258    buf= F.getval();
259    exp= imm2int (buf);
260    if ((exp % k) == 0)
261      exp= exp/k;
262    else
263      return -1;
264
265    buf= int2imm_gf (exp);
266    return CanonicalForm (buf);
267  }
268  for (CFIterator i= F; i.hasTerms(); i++)
269    result += GFPowDown (i.coeff(), k)*power (F.mvar(), i.exp());
270  return result;
271}
272
273CanonicalForm GFMapDown (const CanonicalForm & F, int k)
274{
275  int d= getGFDegree();
276  ASSERT (d % k == 0, "multiple of GF degree expected");
277  int p= getCharacteristic();
278  int ext_field_size= ipower (p, d);
279  int field_size= ipower ( p, k);
280  int diff= (ext_field_size - 1)/(field_size - 1);
281  return GFPowDown (F, diff);
282}
283
284/// map F in \f$ F_{p} (\alpha ) \f$ which is generated by G into some
285/// \f$ F_{p}(\beta ) \f$ which is generated by H
286static inline
287CanonicalForm mapUp (const CanonicalForm& F, const CanonicalForm& G,
288                      const Variable& alpha, const CanonicalForm& H,
289                      CFList& source, CFList& dest)
290{
291  CanonicalForm buf, buf2;
292  int counter= 0;
293  int pos;
294  int p= getCharacteristic();
295  int d= degree (getMipo(alpha));
296  int bound= ipower(p, d);
297  CanonicalForm result= 0;
298  CanonicalForm remainder;
299  CanonicalForm H_power;
300  if (degree(F) <= 0) return F;
301  if (F.level() < 0 && F.isUnivariate())
302  {
303    buf= F;
304    remainder= mod (buf, G);
305    ASSERT (remainder.isZero(), "alpha is not primitive");
306    pos= findItem (source, buf);
307    if (pos == 0)
308      source.append (buf);
309    buf2= buf;
310    while (degree (buf) != 0 && counter < bound)
311    {
312      buf /= G;
313      counter++;
314      if (buf == buf2) break;
315    }
316    ASSERT (counter <= bound, "alpha is not primitive");
317    if (pos == 0)
318    {
319      H_power= buf*power (H, counter);
320      dest.append (H_power);
321    }
322    else
323      H_power= getItem (dest, pos);
324    result = H_power;
325    return result;
326  }
327  else
328  {
329    for (CFIterator i= F; i.hasTerms(); i++)
330    {
331      buf= mapUp (i.coeff(), G, alpha, H, source, dest);
332      result += buf*power(F.mvar(), i.exp());
333    }
334    return result;
335  }
336}
337
338CanonicalForm
339primitiveElement (const Variable& alpha, Variable& beta, bool& fail)
340{
341  bool primitive= false;
342  fail= false;
343  primitive= isPrimitive (alpha, fail);
344  if (fail)
345    return 0;
346  if (primitive)
347  {
348    beta= alpha;
349    return alpha;
350  }
351  CanonicalForm mipo= getMipo (alpha);
352  int d= degree (mipo);
353  int p= getCharacteristic ();
354  #ifdef HAVE_FLINT
355  nmod_poly_t FLINT_mipo;
356  nmod_poly_init(FLINT_mipo,p);
357  #elif defined(HAVE_NTL)
358  if (fac_NTL_char != p)
359  {
360    fac_NTL_char= p;
361    zz_p::init (p);
362  }
363  zz_pX NTL_mipo;
364  #endif
365  CanonicalForm mipo2;
366  primitive= false;
367  fail= false;
368  bool initialized= false;
369  do
370  {
371    #ifdef HAVE_FLINT
372    nmod_poly_randtest_monic_irreducible(FLINT_mipo, FLINTrandom, d+1);
373    mipo2=convertnmod_poly_t2FacCF(FLINT_mipo,Variable(1));
374    #elif defined(HAVE_NTL)
375    BuildIrred (NTL_mipo, d);
376    mipo2= convertNTLzzpX2CF (NTL_mipo, Variable (1));
377    #endif
378    if (!initialized)
379      beta= rootOf (mipo2);
380    else
381      setMipo (beta, mipo2);
382    primitive= isPrimitive (beta, fail);
383    if (primitive)
384      break;
385    if (fail)
386      return 0;
387  } while (1);
388  #ifdef HAVE_FLINT
389  nmod_poly_clear(FLINT_mipo);
390  // convert alpha_mipo
391  nmod_poly_t alpha_mipo;
392  convertFacCF2nmod_poly_t(alpha_mipo,mipo);
393  fq_nmod_ctx_t ctx;
394  fq_nmod_ctx_init_modulus(ctx,alpha_mipo,"t");
395  nmod_poly_clear(alpha_mipo);
396  // convert beta_mipo (mipo2)
397  fq_nmod_poly_t FLINT_beta_mipo;
398  convertFacCF2Fq_nmod_poly_t(FLINT_beta_mipo,mipo2,ctx);
399  fq_nmod_poly_factor_t fac;
400  fq_nmod_poly_factor_init(fac,ctx);
401  fq_nmod_poly_roots(fac, FLINT_beta_mipo, 0, ctx);
402  // root of first (linear) factor: -absolute Term
403  fq_nmod_t r0;
404  fq_nmod_init(r0, ctx);
405  fq_nmod_poly_get_coeff(r0,fac->poly,0,ctx);
406  fq_nmod_neg(r0, r0, ctx);
407  // convert
408  CanonicalForm r1=convertFq_nmod_t2FacCF(r0,alpha,ctx);
409  // cleanup
410  fq_nmod_poly_factor_clear(fac,ctx);
411  fq_nmod_clear(r0, ctx);
412  fq_nmod_poly_clear(FLINT_beta_mipo,ctx);
413  fq_nmod_ctx_clear(ctx);
414  return r1;
415  #elif defined(HAVE_NTL)
416  zz_pX alpha_mipo= convertFacCF2NTLzzpX (mipo);
417  zz_pE::init (alpha_mipo);
418  zz_pEX NTL_beta_mipo= to_zz_pEX (NTL_mipo);
419  zz_pE root= FindRoot (NTL_beta_mipo);
420  return convertNTLzzpE2CF (root, alpha);
421  #endif
422}
423
424CanonicalForm
425mapDown (const CanonicalForm& F, const CanonicalForm& prim_elem, const
426          CanonicalForm& im_prim_elem, const Variable& alpha, CFList& source,
427          CFList& dest)
428{
429  return mapUp (F, im_prim_elem, alpha, prim_elem, dest, source);
430}
431
432CanonicalForm
433mapUp (const CanonicalForm& F, const Variable& alpha, const Variable& /*beta*/,
434        const CanonicalForm& prim_elem, const CanonicalForm& im_prim_elem,
435        CFList& source, CFList& dest)
436{
437  if (prim_elem == alpha)
438    return F (im_prim_elem, alpha);
439  return mapUp (F, prim_elem, alpha, im_prim_elem, source, dest);
440}
441
442CanonicalForm
443mapPrimElem (const CanonicalForm& primElem, const Variable& alpha,
444             const Variable& beta)
445{
446  if (primElem == alpha)
447    return mapUp (alpha, beta);
448  else
449  {
450    CanonicalForm primElemMipo= findMinPoly (primElem, alpha);
451    int p= getCharacteristic ();
452    #ifdef HAVE_FLINT
453    // convert mipo1
454    nmod_poly_t mipo1;
455    convertFacCF2nmod_poly_t(mipo1,getMipo(beta));
456    fq_nmod_ctx_t ctx;
457    fq_nmod_ctx_init_modulus(ctx,mipo1,"t");
458    nmod_poly_clear(mipo1);
459    // convert mipo2 (primElemMipo)
460    fq_nmod_poly_t mipo2;
461    convertFacCF2Fq_nmod_poly_t(mipo2,primElemMipo,ctx);
462    fq_nmod_poly_factor_t fac;
463    fq_nmod_poly_factor_init(fac,ctx);
464    fq_nmod_poly_roots(fac, mipo2, 0, ctx);
465    // root of first (linear) factor: -absolute Term
466    fq_nmod_t r0;
467    fq_nmod_init(r0, ctx);
468    fq_nmod_poly_get_coeff(r0,fac->poly,0,ctx);
469    fq_nmod_neg(r0, r0, ctx);
470    // convert
471    CanonicalForm r1=convertFq_nmod_t2FacCF(r0,beta,ctx);
472    // cleanup
473    fq_nmod_poly_factor_clear(fac,ctx);
474    fq_nmod_clear(r0, ctx);
475    fq_nmod_poly_clear(mipo2,ctx);
476    fq_nmod_ctx_clear(ctx);
477    return r1;
478    #elif defined(HAVE_NTL)
479    if (fac_NTL_char != p)
480    {
481      fac_NTL_char= p;
482      zz_p::init (p);
483    }
484    zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo (beta));
485    zz_pE::init (NTLMipo);
486    zz_pEX NTLPrimElemMipo= convertFacCF2NTLzz_pEX (primElemMipo, NTLMipo);
487    zz_pE root= FindRoot (NTLPrimElemMipo);
488    return convertNTLzzpE2CF (root, beta);
489    #endif
490  }
491}
492
493CanonicalForm
494map (const CanonicalForm& primElem, const Variable& alpha,
495     const CanonicalForm& F, const Variable& beta)
496{
497  CanonicalForm G= F;
498  int order= 0;
499  while (!G.isOne())
500  {
501    G /= primElem;
502    order++;
503  }
504  int p= getCharacteristic ();
505  #ifdef HAVE_FLINT
506  // convert mipo
507  nmod_poly_t mipo1;
508  convertFacCF2nmod_poly_t(mipo1,getMipo(beta));
509  fq_nmod_ctx_t ctx;
510  fq_nmod_ctx_init_modulus(ctx,mipo1,"t");
511  nmod_poly_clear(mipo1);
512  // convert mipo2 (alpha)
513  fq_nmod_poly_t mipo2;
514  convertFacCF2Fq_nmod_poly_t(mipo2,getMipo(alpha),ctx);
515  fq_nmod_poly_factor_t fac;
516  fq_nmod_poly_factor_init(fac,ctx);
517  fq_nmod_poly_roots(fac, mipo2, 0, ctx);
518  // roots in fac, #=fac->num
519  int ind=-1;
520  fq_nmod_t r0,FLINTbeta;
521  fq_nmod_init(r0, ctx);
522  fq_nmod_init(FLINTbeta, ctx);
523  convertFacCF2Fq_nmod_t(FLINTbeta,beta,ctx);
524  fmpz_t FLINTorder;
525  fmpz_set_si(FLINTorder,order);
526  for(int i=0;i< fac->num;i++)
527  {
528    // get the root (-abs.term of linear factor)
529    fq_nmod_poly_get_coeff(r0,fac->poly+i,0,ctx);
530    fq_nmod_neg(r0,r0,ctx);
531    // r^order
532    fq_nmod_pow(r0,r0,FLINTorder,ctx);
533    // ==beta?
534    if (fq_nmod_equal(r0,FLINTbeta,ctx))
535    {
536       ind=i;
537       break;
538    }
539  }
540  fmpz_clear(FLINTorder);
541  // convert
542  fq_nmod_poly_get_coeff(r0,fac->poly+ind,0,ctx);
543  fq_nmod_neg(r0,r0,ctx);
544  CanonicalForm r1=convertFq_nmod_t2FacCF(r0,beta,ctx);
545  // cleanup
546  fq_nmod_poly_factor_clear(fac,ctx);
547  fq_nmod_clear(r0, ctx);
548  fq_nmod_clear(FLINTbeta,ctx);
549  fq_nmod_poly_clear(mipo2,ctx);
550  fq_nmod_ctx_clear(ctx);
551  return r1;
552  #elif defined(HAVE_NTL)
553  if (fac_NTL_char != p)
554  {
555    fac_NTL_char= p;
556    zz_p::init (p);
557  }
558  zz_pX NTL_mipo= convertFacCF2NTLzzpX (getMipo (beta));
559  zz_pE::init (NTL_mipo);
560  zz_pEX NTL_alpha_mipo= convertFacCF2NTLzz_pEX (getMipo(alpha), NTL_mipo);
561  zz_pE NTLBeta= to_zz_pE (convertFacCF2NTLzzpX (beta));
562  vec_zz_pE roots= FindRoots (NTL_alpha_mipo);
563  long ind=-1;
564  for (long i= 0; i < roots.length(); i++)
565  {
566    if (power (roots [i], order)== NTLBeta)
567    {
568      ind= i;
569      break;
570    }
571  }
572  return (convertNTLzzpE2CF (roots[ind], beta));
573  #endif
574}
575
576#ifdef HAVE_FLINT
577/*
578    g is in Fp[x]
579    F is in Fp[t]
580    h is in Fp[t]
581    In the finite field Fp[t]/h(t), find g(x) in Fp[x] such that
582        g(F(t)) = 0 mod h(t)
583    i.e. g is the minpoly of the element F(t) of the finite field.
584*/
585static void minpoly(nmod_poly_t g, const nmod_poly_t F, const nmod_poly_t h)
586{
587    slong i;
588    slong d = nmod_poly_degree(h);
589    mp_limb_t p = h->mod.n;
590    nmod_poly_t Fpow;
591    nmod_berlekamp_massey_t bma;
592
593    nmod_poly_init(Fpow, p);
594    nmod_berlekamp_massey_init(bma, p);
595
596    nmod_poly_one(Fpow);
597    for (i = 0; i < 2*d; i++)
598    {
599        nmod_berlekamp_massey_add_point(bma, nmod_poly_get_coeff_ui(Fpow, 0));
600        nmod_poly_mulmod(Fpow, Fpow, F, h);
601    }
602
603    nmod_berlekamp_massey_reduce(bma);
604
605    /* something went horribly wrong if V does not kill the whole sequence */
606    FLINT_ASSERT(nmod_poly_degree(nmod_berlekamp_massey_R_poly(bma)) <
607                 nmod_poly_degree(nmod_berlekamp_massey_V_poly(bma)));
608
609    nmod_poly_make_monic(g, nmod_berlekamp_massey_V_poly(bma));
610#if WANT_ASSERT
611    {
612        nmod_poly_t z;
613        nmod_poly_init(z, p);
614        nmod_poly_compose_mod(z, g, F, h);
615        FLINT_ASSERT(nmod_poly_is_zero(z));
616        nmod_poly_clear(z);
617    }
618#endif
619    nmod_poly_clear(Fpow);
620    nmod_berlekamp_massey_clear(bma);
621}
622#endif
623
624
625#if defined(HAVE_NTL) || defined(HAVE_FLINT)
626CanonicalForm
627findMinPoly (const CanonicalForm& F, const Variable& alpha)
628{
629  ASSERT (F.isUnivariate() && F.mvar()==alpha,"expected element of F_p(alpha)");
630
631  #if defined(HAVE_NTL) && !defined(HAVE_FLINT)
632  if (fac_NTL_char != getCharacteristic())
633  {
634    fac_NTL_char= getCharacteristic();
635    zz_p::init (getCharacteristic());
636  }
637  zz_pX NTLF= convertFacCF2NTLzzpX (F);
638  int d= degree (getMipo (alpha));
639
640  zz_pX NTLMipo= convertFacCF2NTLzzpX (getMipo(alpha));
641  zz_pE::init (NTLMipo);
642  vec_zz_p pows;
643  pows.SetLength (2*d);
644
645  zz_pE powNTLF;
646  set (powNTLF);
647  zz_pE NTLFE= to_zz_pE (NTLF);
648  zz_pX buf;
649  for (int i= 0; i < 2*d; i++)
650  {
651    buf= rep (powNTLF);
652    buf.rep.SetLength (d);
653    pows [i]= buf.rep[0];
654    powNTLF *= NTLFE;
655  }
656
657  zz_pX NTLMinPoly;
658  MinPolySeq (NTLMinPoly, pows, d);
659
660  return convertNTLzzpX2CF (NTLMinPoly, Variable (1));
661  #elif defined(HAVE_FLINT)
662  nmod_poly_t FLINT_F,FLINT_alpha,g;
663  nmod_poly_init(g,getCharacteristic());
664  convertFacCF2nmod_poly_t(FLINT_F,F);
665  convertFacCF2nmod_poly_t(FLINT_alpha,getMipo(alpha));
666  minpoly(g,FLINT_F,FLINT_alpha);
667  nmod_poly_clear(FLINT_alpha);
668  nmod_poly_clear(FLINT_F);
669  CanonicalForm res=convertnmod_poly_t2FacCF(g,Variable(1));
670  nmod_poly_clear(g);
671  return res;
672  #endif
673}
674#endif
Note: See TracBrowser for help on using the repository browser.