Path: blob/master/src/sage/rings/fraction_field_FpT.pyx
8817 views
12import sys34include "sage/ext/cdefs.pxi"5include "sage/ext/gmp.pxi"6include "sage/ext/interrupt.pxi"7include "sage/ext/stdsage.pxi"89from sage.rings.all import GF10from sage.libs.flint.nmod_poly cimport *11from sage.libs.flint.ulong_extras cimport n_jacobi12from sage.structure.element cimport Element, ModuleElement, RingElement13from sage.rings.integer_ring import ZZ14from sage.rings.fraction_field import FractionField_generic, FractionField_1poly_field15from sage.rings.finite_rings.integer_mod cimport IntegerMod_int16from sage.rings.integer cimport Integer17from sage.rings.polynomial.polynomial_zmod_flint cimport Polynomial_zmod_flint, get_cparent18import sage.algebras.algebra1920from sage.rings.finite_rings.integer_mod cimport jacobi_int, mod_inverse_int, mod_pow_int2122class FpT(FractionField_1poly_field):23"""24This class represents the fraction field GF(p)(T) for `2 < p < 2^16`.2526EXAMPLES::2728sage: R.<T> = GF(71)[]29sage: K = FractionField(R); K30Fraction Field of Univariate Polynomial Ring in T over Finite Field of size 7131sage: 1-1/T32(T + 70)/T33sage: parent(1-1/T) is K34True35"""36def __init__(self, R, names=None): # we include names so that one can use the syntax K.<t> = FpT(GF(5)['t']). It's actually ignored37"""38INPUT:3940- ``R`` -- A polynomial ring over a finite field of prime order `p` with `2 < p < 2^16`4142EXAMPLES::4344sage: R.<x> = GF(31)[]45sage: K = R.fraction_field(); K46Fraction Field of Univariate Polynomial Ring in x over Finite Field of size 3147"""48cdef long p = R.base_ring().characteristic()49assert 2 < p < 2**1650self.p = p51self.poly_ring = R52FractionField_1poly_field.__init__(self, R, element_class = FpTElement)53self._populate_coercion_lists_(coerce_list=[Polyring_FpT_coerce(self), Fp_FpT_coerce(self), ZZ_FpT_coerce(self)])5455def __iter__(self):56"""57Returns an iterator over this fraction field.5859EXAMPLES::6061sage: R.<t> = GF(3)[]; K = R.fraction_field()62sage: iter(K)63<sage.rings.fraction_field_FpT.FpT_iter object at ...>64"""65return self.iter()6667def iter(self, bound=None, start=None):68"""69EXAMPLES::7071sage: from sage.rings.fraction_field_FpT import *72sage: R.<t> = FpT(GF(5)['t'])73sage: list(R.iter(2))[350:355]74[(t^2 + t + 1)/(t + 2),75(t^2 + t + 2)/(t + 2),76(t^2 + t + 4)/(t + 2),77(t^2 + 2*t + 1)/(t + 2),78(t^2 + 2*t + 2)/(t + 2)]79"""80return FpT_iter(self, bound, start)8182cdef class FpTElement(RingElement):83"""84An element of an FpT fraction field.85"""8687def __init__(self, parent, numer, denom=1, coerce=True, reduce=True):88"""89INPUT:9091- parent -- the Fraction field containing this element92- numer -- something that can be converted into the polynomial ring, giving the numerator93- denom -- something that can be converted into the polynomial ring, giving the numerator (default 1)9495EXAMPLES::9697sage: from sage.rings.fraction_field_FpT import *98sage: R.<t> = FpT(GF(5)['t'])99sage: R(7)1002101102"""103RingElement.__init__(self, parent)104if coerce:105numer = parent.poly_ring(numer)106denom = parent.poly_ring(denom)107self.p = parent.p108nmod_poly_init(self._numer, self.p)109nmod_poly_init(self._denom, self.p)110self.initalized = True111cdef long n112for n, a in enumerate(numer):113nmod_poly_set_coeff_ui(self._numer, n, a)114for n, a in enumerate(denom):115nmod_poly_set_coeff_ui(self._denom, n, a)116if reduce:117normalize(self._numer, self._denom, self.p)118119def __dealloc__(self):120"""121Deallocation.122123EXAMPLES::124125sage: K = GF(11)['t'].fraction_field()126sage: t = K.gen()127sage: del t # indirect doctest128"""129if self.initalized:130nmod_poly_clear(self._numer)131nmod_poly_clear(self._denom)132133def __reduce__(self):134"""135For pickling.136137TESTS::138139sage: K = GF(11)['t'].fraction_field()140sage: loads(dumps(K.gen()))141t142sage: loads(dumps(1/K.gen()))1431/t144"""145return (unpickle_FpT_element,146(self._parent, self.numer(), self.denom()))147148cdef FpTElement _new_c(self):149"""150Creates a new FpTElement in the same field, leaving the value to be initialized.151"""152cdef FpTElement x = <FpTElement>PY_NEW(FpTElement)153x._parent = self._parent154x.p = self.p155nmod_poly_init_preinv(x._numer, x.p, self._numer.mod.ninv)156nmod_poly_init_preinv(x._denom, x.p, self._numer.mod.ninv)157x.initalized = True158return x159160cdef FpTElement _copy_c(self):161"""162Creates a new FpTElement in the same field, with the same value as self.163"""164cdef FpTElement x = <FpTElement>PY_NEW(FpTElement)165x._parent = self._parent166x.p = self.p167nmod_poly_init2_preinv(x._numer, x.p, self._numer.mod.ninv, self._numer.length)168nmod_poly_init2_preinv(x._denom, x.p, self._denom.mod.ninv, self._denom.length)169nmod_poly_set(x._numer, self._numer)170nmod_poly_set(x._denom, self._denom)171x.initalized = True172return x173174def numer(self):175"""176Returns the numerator of this element, as an element of the polynomial ring.177178EXAMPLES::179180sage: K = GF(11)['t'].fraction_field()181sage: t = K.gen(0); a = (t + 1/t)^3 - 1182sage: a.numer()183t^6 + 3*t^4 + 10*t^3 + 3*t^2 + 1184"""185return self.numerator()186187cpdef numerator(self):188"""189Returns the numerator of this element, as an element of the polynomial ring.190191EXAMPLES::192193sage: K = GF(11)['t'].fraction_field()194sage: t = K.gen(0); a = (t + 1/t)^3 - 1195sage: a.numerator()196t^6 + 3*t^4 + 10*t^3 + 3*t^2 + 1197"""198cdef Polynomial_zmod_flint res = <Polynomial_zmod_flint>PY_NEW(Polynomial_zmod_flint)199nmod_poly_init2_preinv(&res.x, self.p, self._numer.mod.ninv, self._numer.length)200nmod_poly_set(&res.x, self._numer)201res._parent = self._parent.poly_ring202res._cparent = get_cparent(self._parent.poly_ring)203return res204205def denom(self):206"""207Returns the denominator of this element, as an element of the polynomial ring.208209EXAMPLES::210211sage: K = GF(11)['t'].fraction_field()212sage: t = K.gen(0); a = (t + 1/t)^3 - 1213sage: a.denom()214t^3215"""216return self.denominator()217218cpdef denominator(self):219"""220Returns the denominator of this element, as an element of the polynomial ring.221222EXAMPLES::223224sage: K = GF(11)['t'].fraction_field()225sage: t = K.gen(0); a = (t + 1/t)^3 - 1226sage: a.denominator()227t^3228"""229cdef Polynomial_zmod_flint res = <Polynomial_zmod_flint>PY_NEW(Polynomial_zmod_flint)230nmod_poly_init2_preinv(&res.x, self.p, self._denom.mod.ninv, self._denom.length)231nmod_poly_set(&res.x, self._denom)232res._parent = self._parent.poly_ring233res._cparent = get_cparent(self._parent.poly_ring)234return res235236def __call__(self, *args, **kwds):237"""238EXAMPLES::239240sage: K = Frac(GF(5)['t'])241sage: t = K.gen()242sage: t(3)2433244sage: f = t^2/(1-t)245sage: f(2)2461247sage: f(t)2484*t^2/(t + 4)249sage: f(t^3)2504*t^6/(t^3 + 4)251sage: f((t+1)/t^3)252(t^2 + 2*t + 1)/(t^6 + 4*t^4 + 4*t^3)253"""254return self.numer()(*args, **kwds) / self.denom()(*args, **kwds)255256def subs(self, *args, **kwds):257"""258EXAMPLES::259260sage: K = Frac(GF(11)['t'])261sage: t = K.gen()262sage: f = (t+1)/(t-1)263sage: f.subs(t=2)2643265sage: f.subs(X=2)266(t + 1)/(t + 10)267"""268return self.numer().subs(*args, **kwds) / self.denom().subs(*args, **kwds)269270def valuation(self, v):271"""272Returns the valuation of self at `v`.273274EXAMPLES::275276sage: R.<t> = GF(5)[]277sage: f = (t+1)^2 * (t^2+t+1) / (t-1)^3278sage: f.valuation(t+1)2792280sage: f.valuation(t-1)281-3282sage: f.valuation(t)2830284"""285return self.numer().valuation(v) - self.denom().valuation(v)286287def factor(self):288"""289EXAMPLES::290291sage: K = Frac(GF(5)['t'])292sage: t = K.gen()293sage: f = 2 * (t+1) * (t^2+t+1)^2 / (t-1)294sage: factor(f)295(2) * (t + 4)^-1 * (t + 1) * (t^2 + t + 1)^2296"""297return self.numer().factor() / self.denom().factor()298299def _repr_(self):300"""301Returns a string representation of this element.302303EXAMPLES::304305sage: from sage.rings.fraction_field_FpT import *306sage: R.<t> = FpT(GF(17)['t'])307sage: -t # indirect doctest30816*t309sage: 1/t3101/t311sage: 1/(t+1)3121/(t + 1)313sage: 1-t/t3140315sage: (1-t)/t316(16*t + 1)/t317"""318if nmod_poly_degree(self._denom) == 0 and nmod_poly_get_coeff_ui(self._denom, 0) == 1:319return repr(self.numer())320else:321numer_s = repr(self.numer())322denom_s = repr(self.denom())323if '-' in numer_s or '+' in numer_s:324numer_s = "(%s)" % numer_s325if '-' in denom_s or '+' in denom_s:326denom_s = "(%s)" % denom_s327return "%s/%s" % (numer_s, denom_s)328329def _latex_(self):330r"""331Returns a latex representation of this element.332333EXAMPLES::334335sage: K = GF(7)['t'].fraction_field(); t = K.gen(0)336sage: latex(t^2 + 1) # indirect doctest337t^{2} + 1338sage: latex((t + 1)/(t-1))339\frac{t + 1}{t + 6}340"""341if nmod_poly_degree(self._denom) == 0 and nmod_poly_get_coeff_ui(self._denom, 0) == 1:342return self.numer()._latex_()343else:344return "\\frac{%s}{%s}" % (self.numer()._latex_(), self.denom()._latex_())345346def __richcmp__(left, right, int op):347"""348EXAMPLES::349350sage: K = Frac(GF(5)['t']); t = K.gen()351sage: t == 1352False353sage: t + 1 < t^2354True355"""356return (<Element>left)._richcmp(right, op)357358cdef int _cmp_c_impl(self, Element other) except -2:359"""360Compares this with another element. The ordering is arbitrary,361but it is an ordering, and it is consistent between runs. It has362nothing to do with the algebra structure.363364TESTS::365366sage: from sage.rings.fraction_field_FpT import *367sage: R.<t> = FpT(GF(7)['t'])368sage: t == t369True370sage: t == -t371False372sage: -t == 6*t373True374sage: 1/t == 1/t375True376sage: 1/t == 1/(t+1)377False378sage: 2*t/t == 2379True380sage: 2*t/2 == t381True382383sage: a = (t^3 + 3*t)/(5*t-2); b = (t^2-2)/(t-1)384sage: b < a385True386sage: a < b387False388sage: 1/a < b389True390sage: b < 1/a391False392"""393# They are normalized.394cdef int j = sage_cmp_nmod_poly_t(self._numer, (<FpTElement>other)._numer)395if j: return j396return sage_cmp_nmod_poly_t(self._denom, (<FpTElement>other)._denom)397398def __hash__(self):399"""400Returns a hash value for this element.401402TESTS::403404sage: from sage.rings.fraction_field_FpT import *405sage: K.<t> = FpT(GF(7)['t'])406sage: hash(K(0))4070408sage: hash(K(5))4095410sage: set([1, t, 1/t, t, t, 1/t, 1+1/t, t/t])411set([1, 1/t, t, (t + 1)/t])412sage: a = (t+1)/(t^2-1); hash(a) == hash((a.numer(),a.denom()))413True414"""415if self.denom() == 1:416return hash(self.numer())417return hash((self.numer(), self.denom()))418419def __neg__(self):420"""421Negates this element.422423EXAMPLES::424425sage: K = GF(5)['t'].fraction_field(); t = K.gen(0)426sage: a = (t^2 + 2)/(t-1)427sage: -a # indirect doctest428(4*t^2 + 3)/(t + 4)429"""430cdef FpTElement x = self._copy_c()431nmod_poly_neg(x._numer, x._numer)432return x433434def __invert__(self):435"""436Returns the multiplicative inverse of this element.437438EXAMPLES::439440sage: K = GF(5)['t'].fraction_field(); t = K.gen(0)441sage: a = (t^2 + 2)/(t-1)442sage: ~a # indirect doctest443(t + 4)/(t^2 + 2)444"""445if nmod_poly_degree(self._numer) == -1:446raise ZeroDivisionError447cdef FpTElement x = self._copy_c()448nmod_poly_swap(x._numer, x._denom)449return x450451cpdef ModuleElement _add_(self, ModuleElement _other):452"""453Returns the sum of this fraction field element and another.454455EXAMPLES::456457sage: from sage.rings.fraction_field_FpT import *458sage: R.<t> = FpT(GF(7)['t'])459sage: t + t # indirect doctest4602*t461sage: (t + 3) + (t + 10)4622*t + 6463sage: sum([t] * 7)4640465sage: 1/t + t466(t^2 + 1)/t467sage: 1/t + 1/t^2468(t + 1)/t^2469"""470cdef FpTElement other = <FpTElement>_other471cdef FpTElement x = self._new_c()472nmod_poly_mul(x._numer, self._numer, other._denom)473nmod_poly_mul(x._denom, self._denom, other._numer) # use x._denom as a temp474nmod_poly_add(x._numer, x._numer, x._denom)475nmod_poly_mul(x._denom, self._denom, other._denom)476normalize(x._numer, x._denom, self.p)477return x478479cpdef ModuleElement _sub_(self, ModuleElement _other):480"""481Returns the difference of this fraction field element and another.482483EXAMPLES::484485sage: from sage.rings.fraction_field_FpT import *486sage: R.<t> = FpT(GF(7)['t'])487sage: t - t # indirect doctest4880489sage: (t + 3) - (t + 11)4906491"""492cdef FpTElement other = <FpTElement>_other493cdef FpTElement x = self._new_c()494nmod_poly_mul(x._numer, self._numer, other._denom)495nmod_poly_mul(x._denom, self._denom, other._numer) # use x._denom as a temp496nmod_poly_sub(x._numer, x._numer, x._denom)497nmod_poly_mul(x._denom, self._denom, other._denom)498normalize(x._numer, x._denom, self.p)499return x500501cpdef RingElement _mul_(self, RingElement _other):502"""503Returns the product of this fraction field element and another.504505EXAMPLES::506507sage: from sage.rings.fraction_field_FpT import *508sage: R.<t> = FpT(GF(7)['t'])509sage: t * t # indirect doctest510t^2511sage: (t + 3) * (t + 10)512t^2 + 6*t + 2513"""514cdef FpTElement other = <FpTElement>_other515cdef FpTElement x = self._new_c()516nmod_poly_mul(x._numer, self._numer, other._numer)517nmod_poly_mul(x._denom, self._denom, other._denom)518normalize(x._numer, x._denom, self.p)519return x520521cpdef RingElement _div_(self, RingElement _other):522"""523Returns the quotient of this fraction field element and another.524525EXAMPLES::526527sage: from sage.rings.fraction_field_FpT import *528sage: R.<t> = FpT(GF(5)['t'])529sage: t / t # indirect doctest5301531sage: (t + 3) / (t + 11)532(t + 3)/(t + 1)533sage: (t^2 + 2*t + 1) / (t + 1)534t + 1535"""536cdef FpTElement other = <FpTElement>_other537if nmod_poly_degree(other._numer) == -1:538raise ZeroDivisionError539cdef FpTElement x = self._new_c()540nmod_poly_mul(x._numer, self._numer, other._denom)541nmod_poly_mul(x._denom, self._denom, other._numer)542normalize(x._numer, x._denom, self.p)543return x544545cpdef FpTElement next(self):546"""547This function iterates through all polynomials, returning the "next" polynomial after this one.548549The strategy is as follows:550551- We always leave the denominator monic.552553- We progress through the elements with both numerator and denominator monic, and with the denominator less than the numerator.554For each such, we output all the scalar multiples of it, then all of the scalar multiples of its inverse.555556- So if the leading coefficient of the numerator is less than p-1, we scale the numerator to increase it by 1.557558- Otherwise, we consider the multiple with numerator and denominator monic.559560- If the numerator is less than the denominator (lexicographically), we return the inverse of that element.561562- If the numerator is greater than the denominator, we invert, and then increase the numerator (remaining monic) until we either get something relatively prime to the new denominator, or we reach the new denominator. In this case, we increase the denominator and set the numerator to 1.563564EXAMPLES::565566sage: from sage.rings.fraction_field_FpT import *567sage: R.<t> = FpT(GF(3)['t'])568sage: a = R(0)569sage: for _ in range(30):570... a = a.next()571... print a572...573157425751/t5762/t577t5782*t5791/(t + 1)5802/(t + 1)581t + 15822*t + 2583t/(t + 1)5842*t/(t + 1)585(t + 1)/t586(2*t + 2)/t5871/(t + 2)5882/(t + 2)589t + 25902*t + 1591t/(t + 2)5922*t/(t + 2)593(t + 2)/t594(2*t + 1)/t595(t + 1)/(t + 2)596(2*t + 2)/(t + 2)597(t + 2)/(t + 1)598(2*t + 1)/(t + 1)5991/t^26002/t^2601t^26022*t^2603"""604cdef FpTElement next = self._copy_c()605cdef long a, lead606cdef nmod_poly_t g607if nmod_poly_degree(self._numer) == -1:608# self should be normalized, so denom == 1609nmod_poly_set_coeff_ui(next._numer, 0, 1)610return next611lead = nmod_poly_leading(next._numer)612if lead < self.p - 1:613a = mod_inverse_int(lead, self.p)614# no overflow since self.p < 2^16615a = a * (lead + 1) % self.p616nmod_poly_scalar_mul_nmod(next._numer, next._numer, a)617else:618a = mod_inverse_int(lead, self.p)619nmod_poly_scalar_mul_nmod(next._numer, next._numer, a)620# now both next._numer and next._denom are monic. We figure out which is lexicographically bigger:621a = nmod_poly_cmp(next._numer, next._denom)622if a == 0:623# next._numer and next._denom are relatively prime, so they're both 1.624nmod_poly_inc(next._denom, True)625return next626nmod_poly_set(next._denom, next._numer)627nmod_poly_set(next._numer, self._denom)628if a < 0:629# since next._numer is smaller, we flip and return the inverse.630return next631elif a > 0:632# since next._numer is bigger, we're in the flipped phase. We flip back, and increment the numerator (until we reach the denominator).633nmod_poly_init(g, self.p)634try:635while True:636nmod_poly_inc(next._numer, True)637if nmod_poly_equal(next._numer, next._denom):638# Since we've reached the denominator, we reset the numerator to 1 and increment the denominator.639nmod_poly_inc(next._denom, True)640nmod_poly_zero(next._numer)641nmod_poly_set_coeff_ui(next._numer, 0, 1)642break643else:644# otherwise, we keep incrementing until we have a relatively prime numerator.645nmod_poly_gcd(g, next._numer, next._denom)646if nmod_poly_is_one(g):647break648finally:649nmod_poly_clear(g)650return next651652cpdef _sqrt_or_None(self):653"""654Returns the squre root of self, or None. Differs from sqrt() by not raising an exception.655656TESTS::657658sage: from sage.rings.fraction_field_FpT import *659sage: R.<t> = FpT(GF(17)['t'])660sage: sqrt(t^2) # indirect doctest661t662sage: sqrt(1/t^2)6631/t664sage: sqrt((1+t)^2)665t + 1666sage: sqrt((1+t)^2 / t^2)667(t + 1)/t668669sage: sqrt(4 * (1+t)^2 / t^2)670(2*t + 2)/t671672sage: sqrt(R(0))6730674sage: sqrt(R(-1))6754676677sage: sqrt(t^4)678t^2679sage: sqrt(4*t^4/(1+t)^8)6802*t^2/(t^4 + 4*t^3 + 6*t^2 + 4*t + 1)681682sage: R.<t> = FpT(GF(5)['t'])683sage: [a for a in R.iter(2) if (a^2).sqrt() not in (a,-a)]684[]685sage: [a for a in R.iter(2) if a.is_square() and a.sqrt()^2 != a]686[]687688"""689if nmod_poly_is_zero(self._numer):690return self691692if not nmod_poly_sqrt_check(self._numer) or not nmod_poly_sqrt_check(self._denom):693return None694695cdef nmod_poly_t numer696cdef nmod_poly_t denom697cdef long a698cdef FpTElement res699700nmod_poly_init(denom, self.p)701nmod_poly_init(numer, self.p)702703if nmod_poly_sqrt(numer, self._numer) and nmod_poly_sqrt(denom, self._denom):704# Make denominator monic705a = nmod_poly_leading(denom)706if a != 1:707a = mod_inverse_int(a, self.p)708nmod_poly_scalar_mul_nmod(numer, numer, a)709nmod_poly_scalar_mul_nmod(denom, denom, a)710# Choose numerator with smaller leading coefficient711a = nmod_poly_leading(numer)712if a > self.p - a:713nmod_poly_neg(numer, numer)714res = self._new_c()715nmod_poly_swap(numer, res._numer)716nmod_poly_swap(denom, res._denom)717return res718else:719nmod_poly_clear(numer)720nmod_poly_clear(denom)721return None722723cpdef bint is_square(self):724"""725Returns True if this element is the square of another element of the fraction field.726727EXAMPLES::728729sage: K = GF(13)['t'].fraction_field(); t = K.gen()730sage: t.is_square()731False732sage: (1/t^2).is_square()733True734sage: K(0).is_square()735True736"""737return self._sqrt_or_None() is not None738739def sqrt(self, extend=True, all=False):740"""741Returns the square root of this element.742743INPUT:744745- ``extend`` - bool (default: True); if True, return a746square root in an extension ring, if necessary. Otherwise, raise a747ValueError if the square is not in the base ring.748749- ``all`` - bool (default: False); if True, return all750square roots of self, instead of just one.751752EXAMPLES::753754sage: from sage.rings.fraction_field_FpT import *755sage: K = GF(7)['t'].fraction_field(); t = K.gen(0)756sage: p = (t + 2)^2/(3*t^3 + 1)^4757sage: p.sqrt()758(3*t + 6)/(t^6 + 3*t^3 + 4)759sage: p.sqrt()^2 == p760True761762"""763s = self._sqrt_or_None()764if s is None:765if extend:766raise NotImplementedError, "function fields not yet implemented"767else:768raise ValueError, "not a perfect square"769else:770if all:771if not s:772return [s]773else:774return [s, -s]775else:776return s777778def __pow__(FpTElement self, Py_ssize_t e, dummy):779"""780Returns the ``e``th power of this element.781782EXAMPLES::783784sage: from sage.rings.fraction_field_FpT import *785sage: R.<t> = FpT(GF(7)['t'])786sage: t^5787t^5788sage: t^-57891/t^5790791sage: a = (t+1)/(t-1); a792(t + 1)/(t + 6)793sage: a^5794(t^5 + 5*t^4 + 3*t^3 + 3*t^2 + 5*t + 1)/(t^5 + 2*t^4 + 3*t^3 + 4*t^2 + 5*t + 6)795sage: a^7796(t^7 + 1)/(t^7 + 6)797sage: a^14798(t^14 + 2*t^7 + 1)/(t^14 + 5*t^7 + 1)799800sage: (a^2)^2 == a^4801True802sage: a^3 * a^2 == a^5803True804sage: a^47 * a^92 == a^(47+92)805True806"""807cdef long a808assert dummy is None809cdef FpTElement x = self._new_c()810if e >= 0:811nmod_poly_pow(x._numer, self._numer, e)812nmod_poly_pow(x._denom, self._denom, e)813else:814nmod_poly_pow(x._denom, self._numer, -e)815nmod_poly_pow(x._numer, self._denom, -e)816if nmod_poly_leading(x._denom) != 1:817a = mod_inverse_int(nmod_poly_leading(x._denom), self.p)818nmod_poly_scalar_mul_nmod(x._numer, x._numer, a)819nmod_poly_scalar_mul_nmod(x._denom, x._denom, a)820return x821822823cdef class FpT_iter:824"""825Returns a class that iterates over all elements of an FpT.826827EXAMPLES::828829sage: K = GF(3)['t'].fraction_field()830sage: I = K.iter(1)831sage: list(I)832[0,8331,8342,835t,836t + 1,837t + 2,8382*t,8392*t + 1,8402*t + 2,8411/t,8422/t,843(t + 1)/t,844(t + 2)/t,845(2*t + 1)/t,846(2*t + 2)/t,8471/(t + 1),8482/(t + 1),849t/(t + 1),850(t + 2)/(t + 1),8512*t/(t + 1),852(2*t + 1)/(t + 1),8531/(t + 2),8542/(t + 2),855t/(t + 2),856(t + 1)/(t + 2),8572*t/(t + 2),858(2*t + 2)/(t + 2)]859"""860def __init__(self, parent, degree=None, FpTElement start=None):861"""862INPUTS:863864- parent -- The FpT that we're iterating over.865866- degree -- The maximum degree of the numerator and denominator of the elements over which we iterate.867868- start -- (default 0) The element on which to start.869870EXAMPLES::871872sage: K = GF(11)['t'].fraction_field()873sage: I = K.iter(2) # indirect doctest874sage: for a in I:875... if a.denom()[0] == 3 and a.numer()[1] == 2:876... print a; break8772*t/(t + 3)878"""879#if degree is None:880# raise NotImplementedError881self.parent = parent882self.cur = start883self.degree = -2 if degree is None else degree884885def __cinit__(self, parent, *args, **kwds):886"""887Memory allocation for the temp variable storing the gcd of the numerator and denominator.888889TESTS::890891sage: from sage.rings.fraction_field_FpT import FpT_iter892sage: K = GF(7)['t'].fraction_field()893sage: I = FpT_iter(K, 3) # indirect doctest894sage: I895<sage.rings.fraction_field_FpT.FpT_iter object at ...>896"""897nmod_poly_init(self.g, parent.characteristic())898899def __dealloc__(self):900"""901Deallocating of self.g.902903TESTS::904905sage: from sage.rings.fraction_field_FpT import FpT_iter906sage: K = GF(7)['t'].fraction_field()907sage: I = FpT_iter(K, 3)908sage: del I # indirect doctest909"""910nmod_poly_clear(self.g)911912def __iter__(self):913"""914Returns this iterator.915916TESTS::917918sage: from sage.rings.fraction_field_FpT import FpT_iter919sage: K = GF(3)['t'].fraction_field()920sage: I = FpT_iter(K, 3)921sage: for a in I: # indirect doctest922... if a.numer()[1] == 1 and a.denom()[1] == 2 and a.is_square():923... print a; break924(t^2 + t + 1)/(t^2 + 2*t + 1)925"""926return self927928def __next__(self):929"""930Returns the next element to iterate over.931932This is achieved by iterating over monic denominators, and for each denominator,933iterating over all numerators relatively prime to the given denominator.934935EXAMPLES::936937sage: from sage.rings.fraction_field_FpT import *938sage: K.<t> = FpT(GF(3)['t'])939sage: list(K.iter(1)) # indirect doctest940[0,9411,9422,943t,944t + 1,945t + 2,9462*t,9472*t + 1,9482*t + 2,9491/t,9502/t,951(t + 1)/t,952(t + 2)/t,953(2*t + 1)/t,954(2*t + 2)/t,9551/(t + 1),9562/(t + 1),957t/(t + 1),958(t + 2)/(t + 1),9592*t/(t + 1),960(2*t + 1)/(t + 1),9611/(t + 2),9622/(t + 2),963t/(t + 2),964(t + 1)/(t + 2),9652*t/(t + 2),966(2*t + 2)/(t + 2)]967968sage: len(list(K.iter(3)))9692187970971sage: K.<t> = FpT(GF(5)['t'])972sage: L = list(K.iter(3)); len(L)97378125974sage: L[:10]975[0, 1, 2, 3, 4, t, t + 1, t + 2, t + 3, t + 4]976sage: L[2000]977(3*t^3 + 3*t^2 + 3*t + 4)/(t + 2)978sage: L[-1]979(4*t^3 + 4*t^2 + 4*t + 4)/(t^3 + 4*t^2 + 4*t + 4)980"""981cdef FpTElement next982if self.cur is None:983self.cur = self.parent(0)984elif self.degree == -2:985self.cur = self.cur.next()986else:987next = self.cur._copy_c()988sig_on()989while True:990nmod_poly_inc(next._numer, False)991if nmod_poly_degree(next._numer) > self.degree:992nmod_poly_inc(next._denom, True)993if nmod_poly_degree(next._denom) > self.degree:994sig_off()995raise StopIteration996nmod_poly_zero(next._numer)997nmod_poly_set_coeff_ui(next._numer, 0, 1)998nmod_poly_gcd(self.g, next._numer, next._denom)999if nmod_poly_is_one(self.g):1000break1001sig_off()1002self.cur = next1003# self.cur = self.cur.next()1004# if nmod_poly_degree(self.cur._numer) > self.degree:1005# raise StopIteration1006return self.cur10071008cdef class Polyring_FpT_coerce(RingHomomorphism_coercion):1009"""1010This class represents the coercion map from GF(p)[t] to GF(p)(t)10111012EXAMPLES::10131014sage: R.<t> = GF(5)[]1015sage: K = R.fraction_field()1016sage: f = K.coerce_map_from(R); f1017Ring Coercion morphism:1018From: Univariate Polynomial Ring in t over Finite Field of size 51019To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 51020sage: type(f)1021<type 'sage.rings.fraction_field_FpT.Polyring_FpT_coerce'>1022"""1023cdef long p10241025def __init__(self, R):1026"""1027INPUTS:10281029- R -- An FpT10301031EXAMPLES::10321033sage: R.<t> = GF(next_prime(2000))[]1034sage: K = R.fraction_field() # indirect doctest1035"""1036RingHomomorphism_coercion.__init__(self, R.ring_of_integers().Hom(R), check=False)1037self.p = R.base_ring().characteristic()10381039cpdef Element _call_(self, _x):1040"""1041Applies the coercion.10421043EXAMPLES::10441045sage: R.<t> = GF(5)[]1046sage: K = R.fraction_field()1047sage: f = K.coerce_map_from(R)1048sage: f(t^2 + 1) # indirect doctest1049t^2 + 11050"""1051cdef Polynomial_zmod_flint x = <Polynomial_zmod_flint?> _x1052cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)1053ans._parent = self._codomain1054ans.p = self.p1055nmod_poly_init(ans._numer, ans.p)1056nmod_poly_init(ans._denom, ans.p)1057nmod_poly_set(ans._numer, &x.x)1058nmod_poly_set_coeff_ui(ans._denom, 0, 1)1059ans.initalized = True1060return ans10611062cpdef Element _call_with_args(self, _x, args=(), kwds={}):1063"""1064This function allows the map to take multiple arguments, usually used to specify both numerator and denominator.10651066If ``reduce`` is specified as False, then the result won't be normalized.10671068EXAMPLES::10691070sage: R.<t> = GF(5)[]1071sage: K = R.fraction_field()1072sage: f = K.coerce_map_from(R)1073sage: f(2*t + 2, t + 3) # indirect doctest1074(2*t + 2)/(t + 3)1075sage: f(2*t + 2, 2)1076t + 11077sage: f(2*t + 2, 2, reduce=False)1078(2*t + 2)/210791080TEST:10811082Check that :trac:`12217` is fixed::10831084sage: R.<t> = GF(5)[]1085sage: K = R.fraction_field()1086sage: f = K.coerce_map_from(R)1087sage: f(t, 0)1088Traceback (most recent call last):1089...1090ZeroDivisionError: fraction has denominator 010911092"""1093cdef Polynomial_zmod_flint x = <Polynomial_zmod_flint?> _x1094cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)1095ans._parent = self._codomain1096ans.p = self.p1097nmod_poly_init(ans._numer, ans.p)1098nmod_poly_init(ans._denom, ans.p)1099cdef long r1100nmod_poly_set(ans._numer, &x.x)1101if len(args) == 0:1102nmod_poly_set_coeff_ui(ans._denom, 0, 1)1103elif len(args) == 1:1104y = args[0]1105if PY_TYPE_CHECK(y, Integer):1106r = mpz_fdiv_ui((<Integer>y).value, self.p)1107if r == 0:1108raise ZeroDivisionError('fraction has denominator 0')1109nmod_poly_set_coeff_ui(ans._denom, 0, r)1110else:1111# could use the coerce keyword being set to False to not check this...1112if not (PY_TYPE_CHECK(y, Element) and y.parent() is self._domain):1113# We could special case integers and GF(p) elements here.1114y = self._domain(y)1115if not y:1116raise ZeroDivisionError('fraction has denominator 0')1117nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))1118else:1119raise ValueError, "FpT only supports two positional arguments"1120if not (kwds.has_key('reduce') and not kwds['reduce']):1121normalize(ans._numer, ans._denom, ans.p)1122ans.initalized = True1123return ans11241125def section(self):1126"""1127Returns the section of this inclusion: the partially defined map from ``GF(p)(t)``1128back to ``GF(p)[t]``, defined on elements with unit denominator.11291130EXAMPLES::11311132sage: R.<t> = GF(5)[]1133sage: K = R.fraction_field()1134sage: f = K.coerce_map_from(R)1135sage: g = f.section(); g1136Section map:1137From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 51138To: Univariate Polynomial Ring in t over Finite Field of size 51139sage: t = K.gen()1140sage: g(t)1141t1142sage: g(1/t)1143Traceback (most recent call last):1144...1145ValueError: not integral1146"""1147return FpT_Polyring_section(self)11481149cdef class FpT_Polyring_section(Section):1150"""1151This class represents the section from GF(p)(t) back to GF(p)[t]11521153EXAMPLES::11541155sage: R.<t> = GF(5)[]1156sage: K = R.fraction_field()1157sage: f = R.convert_map_from(K); f1158Section map:1159From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 51160To: Univariate Polynomial Ring in t over Finite Field of size 51161sage: type(f)1162<type 'sage.rings.fraction_field_FpT.FpT_Polyring_section'>1163"""1164cdef long p11651166def __init__(self, Polyring_FpT_coerce f):1167"""1168INPUTS:11691170- f -- A Polyring_FpT_coerce homomorphism11711172EXAMPLES::11731174sage: R.<t> = GF(next_prime(2000))[]1175sage: K = R.fraction_field()1176sage: R(K.gen(0)) # indirect doctest1177t1178"""1179self.p = f.p1180Section.__init__(self, f)11811182cpdef Element _call_(self, _x):1183"""1184Applies the section.11851186EXAMPLES::11871188sage: R.<t> = GF(7)[]1189sage: K = R.fraction_field()1190sage: f = K.coerce_map_from(R)1191sage: g = f.section(); g1192Section map:1193From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 71194To: Univariate Polynomial Ring in t over Finite Field of size 71195sage: t = K.gen()1196sage: g(t^2) # indirect doctest1197t^21198sage: g(1/t)1199Traceback (most recent call last):1200...1201ValueError: not integral1202"""1203cdef FpTElement x = <FpTElement?>_x1204cdef Polynomial_zmod_flint ans1205if nmod_poly_degree(x._denom) != 0:1206normalize(x._numer, x._denom, self.p)1207if nmod_poly_degree(x._denom) != 0:1208raise ValueError, "not integral"1209ans = PY_NEW(Polynomial_zmod_flint)1210if nmod_poly_get_coeff_ui(x._denom, 0) != 1:1211normalize(x._numer, x._denom, self.p)1212nmod_poly_init(&ans.x, self.p)1213nmod_poly_set(&ans.x, x._numer)1214ans._parent = self._codomain1215ans._cparent = get_cparent(self._codomain)1216return ans12171218cdef class Fp_FpT_coerce(RingHomomorphism_coercion):1219"""1220This class represents the coercion map from GF(p) to GF(p)(t)12211222EXAMPLES::12231224sage: R.<t> = GF(5)[]1225sage: K = R.fraction_field()1226sage: f = K.coerce_map_from(GF(5)); f1227Ring Coercion morphism:1228From: Finite Field of size 51229To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 51230sage: type(f)1231<type 'sage.rings.fraction_field_FpT.Fp_FpT_coerce'>1232"""1233cdef long p12341235def __init__(self, R):1236"""1237INPUTS:12381239- R -- An FpT12401241EXAMPLES::12421243sage: R.<t> = GF(next_prime(3000))[]1244sage: K = R.fraction_field() # indirect doctest1245"""1246RingHomomorphism_coercion.__init__(self, R.base_ring().Hom(R), check=False)1247self.p = R.base_ring().characteristic()12481249cpdef Element _call_(self, _x):1250"""1251Applies the coercion.12521253EXAMPLES::12541255sage: R.<t> = GF(5)[]1256sage: K = R.fraction_field()1257sage: f = K.coerce_map_from(GF(5))1258sage: f(GF(5)(3)) # indirect doctest125931260"""1261cdef IntegerMod_int x = <IntegerMod_int?> _x1262cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)1263ans._parent = self._codomain1264ans.p = self.p1265nmod_poly_init(ans._numer, ans.p)1266nmod_poly_init(ans._denom, ans.p)1267nmod_poly_set_coeff_ui(ans._numer, 0, x.ivalue)1268nmod_poly_set_coeff_ui(ans._denom, 0, 1)1269ans.initalized = True1270return ans12711272cpdef Element _call_with_args(self, _x, args=(), kwds={}):1273"""1274This function allows the map to take multiple arguments, usually used to specify both numerator and denominator.12751276If ``reduce`` is specified as False, then the result won't be normalized.12771278EXAMPLES::12791280sage: R.<t> = GF(5)[]1281sage: K = R.fraction_field()1282sage: f = K.coerce_map_from(GF(5))1283sage: f(1, t + 3) # indirect doctest12841/(t + 3)1285sage: f(2, 2*t)12861/t1287sage: f(2, 2*t, reduce=False)12882/2*t1289"""1290cdef IntegerMod_int x = <IntegerMod_int?> _x1291cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)1292ans._parent = self._codomain1293ans.p = self.p1294nmod_poly_init(ans._numer, ans.p)1295nmod_poly_init(ans._denom, ans.p)1296cdef long r1297nmod_poly_set_coeff_ui(ans._numer, 0, x.ivalue)1298if len(args) == 0:1299nmod_poly_set_coeff_ui(ans._denom, 0, 1)1300if len(args) == 1:1301y = args[0]1302if PY_TYPE_CHECK(y, Integer):1303r = mpz_fdiv_ui((<Integer>y).value, self.p)1304if r == 0:1305raise ZeroDivisionError1306nmod_poly_set_coeff_ui(ans._denom, 0, r)1307else:1308R = self._codomain.ring_of_integers()1309# could use the coerce keyword being set to False to not check this...1310if not (PY_TYPE_CHECK(y, Element) and y.parent() is R):1311# We could special case integers and GF(p) elements here.1312y = R(y)1313nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))1314else:1315raise ValueError, "FpT only supports two positional arguments"1316if not (kwds.has_key('reduce') and not kwds['reduce']):1317normalize(ans._numer, ans._denom, ans.p)1318ans.initalized = True1319return ans13201321def section(self):1322"""1323Returns the section of this inclusion: the partially defined map from ``GF(p)(t)``1324back to ``GF(p)``, defined on constant elements.13251326EXAMPLES::13271328sage: R.<t> = GF(5)[]1329sage: K = R.fraction_field()1330sage: f = K.coerce_map_from(GF(5))1331sage: g = f.section(); g1332Section map:1333From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 51334To: Finite Field of size 51335sage: t = K.gen()1336sage: g(f(1,3,reduce=False))133721338sage: g(t)1339Traceback (most recent call last):1340...1341ValueError: not constant1342sage: g(1/t)1343Traceback (most recent call last):1344...1345ValueError: not integral1346"""1347return FpT_Fp_section(self)13481349cdef class FpT_Fp_section(Section):1350"""1351This class represents the section from GF(p)(t) back to GF(p)[t]13521353EXAMPLES::13541355sage: R.<t> = GF(5)[]1356sage: K = R.fraction_field()1357sage: f = GF(5).convert_map_from(K); f1358Section map:1359From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 51360To: Finite Field of size 51361sage: type(f)1362<type 'sage.rings.fraction_field_FpT.FpT_Fp_section'>1363"""1364cdef long p13651366def __init__(self, Fp_FpT_coerce f):1367"""1368INPUTS:13691370- f -- An Fp_FpT_coerce homomorphism13711372EXAMPLES::13731374sage: R.<t> = GF(next_prime(2000))[]1375sage: K = R.fraction_field()1376sage: GF(next_prime(2000))(K(127)) # indirect doctest13771271378"""1379self.p = f.p1380Section.__init__(self, f)13811382cpdef Element _call_(self, _x):1383"""1384Applies the section.13851386EXAMPLES::13871388sage: R.<t> = GF(7)[]1389sage: K = R.fraction_field()1390sage: f = K.coerce_map_from(GF(7))1391sage: g = f.section(); g1392Section map:1393From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 71394To: Finite Field of size 71395sage: t = K.gen()1396sage: g(t^2) # indirect doctest1397Traceback (most recent call last):1398...1399ValueError: not constant1400sage: g(1/t)1401Traceback (most recent call last):1402...1403ValueError: not integral1404sage: g(K(4))140541406sage: g(K(0))140701408"""1409cdef FpTElement x = <FpTElement?>_x1410cdef IntegerMod_int ans1411if nmod_poly_degree(x._denom) != 0 or nmod_poly_degree(x._numer) > 0:1412normalize(x._numer, x._denom, self.p)1413if nmod_poly_degree(x._denom) != 0:1414raise ValueError, "not integral"1415if nmod_poly_degree(x._numer) > 0:1416raise ValueError, "not constant"1417ans = PY_NEW(IntegerMod_int)1418ans.__modulus = self._codomain._pyx_order1419if nmod_poly_get_coeff_ui(x._denom, 0) != 1:1420normalize(x._numer, x._denom, self.p)1421ans.ivalue = nmod_poly_get_coeff_ui(x._numer, 0)1422ans._parent = self._codomain1423return ans14241425cdef class ZZ_FpT_coerce(RingHomomorphism_coercion):1426"""1427This class represents the coercion map from ZZ to GF(p)(t)14281429EXAMPLES::14301431sage: R.<t> = GF(17)[]1432sage: K = R.fraction_field()1433sage: f = K.coerce_map_from(ZZ); f1434Ring Coercion morphism:1435From: Integer Ring1436To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 171437sage: type(f)1438<type 'sage.rings.fraction_field_FpT.ZZ_FpT_coerce'>1439"""1440cdef long p14411442def __init__(self, R):1443"""1444INPUTS:14451446- R -- An FpT14471448EXAMPLES::14491450sage: R.<t> = GF(next_prime(3000))[]1451sage: K = R.fraction_field() # indirect doctest1452"""1453RingHomomorphism_coercion.__init__(self, ZZ.Hom(R), check=False)1454self.p = R.base_ring().characteristic()14551456cpdef Element _call_(self, _x):1457"""1458Applies the coercion.14591460EXAMPLES::14611462sage: R.<t> = GF(5)[]1463sage: K = R.fraction_field()1464sage: f = K.coerce_map_from(ZZ)1465sage: f(3) # indirect doctest146631467"""1468cdef Integer x = <Integer?> _x1469cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)1470ans._parent = self._codomain1471ans.p = self.p1472nmod_poly_init(ans._numer, ans.p)1473nmod_poly_init(ans._denom, ans.p)1474nmod_poly_set_coeff_ui(ans._numer, 0, mpz_fdiv_ui(x.value, self.p))1475nmod_poly_set_coeff_ui(ans._denom, 0, 1)1476ans.initalized = True1477return ans14781479cpdef Element _call_with_args(self, _x, args=(), kwds={}):1480"""1481This function allows the map to take multiple arguments, usually used to specify both numerator and denominator.14821483If ``reduce`` is specified as False, then the result won't be normalized.14841485EXAMPLES::14861487sage: R.<t> = GF(5)[]1488sage: K = R.fraction_field()1489sage: f = K.coerce_map_from(ZZ)1490sage: f(1, t + 3) # indirect doctest14911/(t + 3)1492sage: f(1,2)149331494sage: f(2, 2*t)14951/t1496sage: f(2, 2*t, reduce=False)14972/2*t1498"""1499cdef Integer x = <Integer?> _x1500cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)1501ans._parent = self._codomain1502ans.p = self.p1503nmod_poly_init(ans._numer, ans.p)1504nmod_poly_init(ans._denom, ans.p)1505cdef long r1506nmod_poly_set_coeff_ui(ans._numer, 0, mpz_fdiv_ui(x.value, self.p))1507if len(args) == 0:1508nmod_poly_set_coeff_ui(ans._denom, 0, 1)1509if len(args) == 1:1510y = args[0]1511if PY_TYPE_CHECK(y, Integer):1512r = mpz_fdiv_ui((<Integer>y).value, self.p)1513if r == 0:1514raise ZeroDivisionError1515nmod_poly_set_coeff_ui(ans._denom, 0, r)1516else:1517R = self._codomain.ring_of_integers()1518# could use the coerce keyword being set to False to not check this...1519if not (PY_TYPE_CHECK(y, Element) and y.parent() is R):1520# We could special case integers and GF(p) elements here.1521y = R(y)1522nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))1523else:1524raise ValueError, "FpT only supports two positional arguments"1525if not (kwds.has_key('reduce') and not kwds['reduce']):1526normalize(ans._numer, ans._denom, ans.p)1527ans.initalized = True1528return ans15291530def section(self):1531"""1532Returns the section of this inclusion: the partially defined map from ``GF(p)(t)``1533back to ``ZZ``, defined on constant elements.15341535EXAMPLES::15361537sage: R.<t> = GF(5)[]1538sage: K = R.fraction_field()1539sage: f = K.coerce_map_from(ZZ)1540sage: g = f.section(); g1541Composite map:1542From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 51543To: Integer Ring1544Defn: Section map:1545From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 51546To: Finite Field of size 51547then1548Lifting map:1549From: Finite Field of size 51550To: Integer Ring1551sage: t = K.gen()1552sage: g(f(1,3,reduce=False))155321554sage: g(t)1555Traceback (most recent call last):1556...1557ValueError: not constant1558sage: g(1/t)1559Traceback (most recent call last):1560...1561ValueError: not integral1562"""1563return ZZ.convert_map_from(self._codomain.base_ring()) * Fp_FpT_coerce(self._codomain).section()15641565cdef inline bint normalize(nmod_poly_t numer, nmod_poly_t denom, long p):1566"""1567Puts numer/denom into a normal form: denominator monic and sharing no common factor with the numerator.15681569The normalized form of 0 is 0/1.15701571Returns True if numer and denom were changed.1572"""1573cdef long a1574cdef bint changed1575if nmod_poly_degree(numer) == -1:1576if nmod_poly_degree(denom) > 0 or nmod_poly_leading(denom) != 1:1577changed = True1578else:1579changed = False1580nmod_poly_truncate(denom, 0)1581nmod_poly_set_coeff_ui(denom, 0, 1)1582return changed1583elif nmod_poly_degree(numer) == 0 or nmod_poly_degree(denom) == 0:1584if nmod_poly_leading(denom) != 1:1585a = mod_inverse_int(nmod_poly_leading(denom), p)1586nmod_poly_scalar_mul_nmod(numer, numer, a)1587nmod_poly_scalar_mul_nmod(denom, denom, a)1588return True1589return False1590cdef nmod_poly_t g1591changed = False1592try:1593nmod_poly_init_preinv(g, p, numer.mod.ninv)1594nmod_poly_gcd(g, numer, denom)1595if nmod_poly_degree(g) != 0:1596# Divide knowing divisible by? Can we get these quotients as a byproduct of the gcd?1597nmod_poly_div(numer, numer, g)1598nmod_poly_div(denom, denom, g)1599changed = True1600if nmod_poly_leading(denom) != 1:1601a = mod_inverse_int(nmod_poly_leading(denom), p)1602nmod_poly_scalar_mul_nmod(numer, numer, a)1603nmod_poly_scalar_mul_nmod(denom, denom, a)1604changed = True1605return changed1606finally:1607nmod_poly_clear(g)16081609cdef inline unsigned long nmod_poly_leading(nmod_poly_t poly):1610"""1611Returns the leading coefficient of ``poly``.1612"""1613return nmod_poly_get_coeff_ui(poly, nmod_poly_degree(poly))16141615cdef inline void nmod_poly_inc(nmod_poly_t poly, bint monic):1616"""1617Sets poly to the "next" polynomial: this is just counting in base p.16181619If monic is True then will only iterate through monic polynomials.1620"""1621cdef long n1622cdef long a1623cdef long p = poly.mod.n1624for n from 0 <= n <= nmod_poly_degree(poly) + 1:1625a = nmod_poly_get_coeff_ui(poly, n) + 11626if a == p:1627nmod_poly_set_coeff_ui(poly, n, 0)1628else:1629nmod_poly_set_coeff_ui(poly, n, a)1630break1631if monic and a == 2 and n == nmod_poly_degree(poly):1632nmod_poly_set_coeff_ui(poly, n, 0)1633nmod_poly_set_coeff_ui(poly, n+1, 1)16341635cdef inline long nmod_poly_cmp(nmod_poly_t a, nmod_poly_t b):1636"""1637Compares `a` and `b`, returning 0 if they are equal.16381639- If the degree of `a` is less than that of `b`, returns -1.16401641- If the degree of `b` is less than that of `a`, returns 1.16421643- Otherwise, compares `a` and `b` lexicographically, starting at the leading terms.1644"""1645cdef long ad = nmod_poly_degree(a)1646cdef long bd = nmod_poly_degree(b)1647if ad < bd:1648return -11649elif ad > bd:1650return 11651cdef long d = nmod_poly_degree(a)1652while d >= 0:1653ad = nmod_poly_get_coeff_ui(a, d)1654bd = nmod_poly_get_coeff_ui(b, d)1655if ad < bd:1656return -11657elif ad > bd:1658return 11659d -= 11660return 016611662cdef bint nmod_poly_sqrt_check(nmod_poly_t poly):1663"""1664Quick check to see if poly could possibly be a square.1665"""1666# We could use Sage's jacobi_int which is for 32 bits integers rather1667# than FLINT's n_jacobi which is for longs as the FpT class is crafted1668# for primes 2 < p < 2^161669return (nmod_poly_degree(poly) % 2 == 01670and n_jacobi(nmod_poly_leading(poly), poly.mod.n) == 11671and n_jacobi(nmod_poly_get_coeff_ui(poly, 0), poly.mod.n) != -1)16721673def unpickle_FpT_element(K, numer, denom):1674"""1675Used for pickling.16761677TESTS::16781679sage: from sage.rings.fraction_field_FpT import unpickle_FpT_element1680sage: R.<t> = GF(13)['t']1681sage: unpickle_FpT_element(Frac(R), t+1, t)1682(t + 1)/t1683"""1684return FpTElement(K, numer, denom, coerce=False, reduce=False)168516861687# Somehow this isn't in FLINT, evidently. It could be moved1688# elsewhere at some point.1689cdef int sage_cmp_nmod_poly_t(nmod_poly_t L, nmod_poly_t R):1690"""1691Compare two nmod_poly_t in a Pythonic way, so this returns -1, 0,1692or 1, and is consistent.1693"""1694cdef int j1695cdef Py_ssize_t i16961697# First compare the degrees1698j = nmod_poly_degree(L) - nmod_poly_degree(R)1699if j<0: return -11700elif j>0: return 117011702# Same degree, so compare coefficients, term by term1703for i in range(nmod_poly_degree(L)+1):1704j = nmod_poly_get_coeff_ui(L,i) - nmod_poly_get_coeff_ui(R,i)1705if j<0: return -11706elif j>0: return 117071708# Two polynomials are equal1709return 0171017111712