Ticket #7585: 7585_3_FpT-update.patch
| File 7585_3_FpT-update.patch, 58.9 KB (added by roed, 4 years ago) |
|---|
-
sage/libs/flint/zmod_poly.pxd
# HG changeset patch # User David Roe <roed@math.harvard.edu> # Date 1260892899 18000 # Node ID 081dadd2f119edf305fae88c98e1fff8af08792e # Parent 1cf975c520f1a19bc9336595e86dde77b71b26f6 Added fraction_field_FpT.pxd. Added doctests. Made iterators work a bit better. diff -r 1cf975c520f1 -r 081dadd2f119 sage/libs/flint/zmod_poly.pxd
a b 253 253 cdef unsigned long zmod_poly_evaluate(zmod_poly_t, unsigned long) 254 254 cdef void zmod_poly_compose_horner(zmod_poly_t, zmod_poly_t, zmod_poly_t) 255 255 256 # Factorization257 258 cdef int zmod_poly_isirreducible(zmod_poly_t p)259 260 ctypedef struct zmod_poly_factors_struct:261 unsigned long num_factors262 unsigned long* exponents263 zmod_poly_t* factors264 265 ctypedef zmod_poly_factors_struct* zmod_poly_factor_t266 267 cdef void zmod_poly_factor_init(zmod_poly_factor_t)268 cdef void zmod_poly_factor_clear(zmod_poly_factor_t)269 cdef void zmod_poly_factor_square_free(zmod_poly_factor_t, zmod_poly_t)270 cdef void zmod_poly_factor(zmod_poly_factor_t, zmod_poly_t)271 272 256 # FLINT 1.1 will have: 273 257 # cdef void zmod_poly_powmod(zmod_poly_t res, zmod_poly_t pol, long exp, zmod_poly_t f) 274 258 … … 284 268 285 269 ctypedef zmod_poly_factor_struct zmod_poly_factor_t[1] 286 270 287 void zmod_poly_factor_init(zmod_poly_factor_t fac)288 void zmod_poly_factor_clear(zmod_poly_factor_t fac)271 cdef void zmod_poly_factor_init(zmod_poly_factor_t fac) 272 cdef void zmod_poly_factor_clear(zmod_poly_factor_t fac) 289 273 290 bint zmod_poly_isirreducible(zmod_poly_t f)291 void zmod_poly_factor_add(zmod_poly_factor_t fac, zmod_poly_t poly)292 void zmod_poly_factor_concat(zmod_poly_factor_t res, zmod_poly_factor_t fac)293 void zmod_poly_factor_print(zmod_poly_factor_t fac)294 void zmod_poly_factor_pow(zmod_poly_factor_t fac, unsigned long exp)274 cdef bint zmod_poly_isirreducible(zmod_poly_t f) 275 cdef void zmod_poly_factor_add(zmod_poly_factor_t fac, zmod_poly_t poly) 276 cdef void zmod_poly_factor_concat(zmod_poly_factor_t res, zmod_poly_factor_t fac) 277 cdef void zmod_poly_factor_print(zmod_poly_factor_t fac) 278 cdef void zmod_poly_factor_pow(zmod_poly_factor_t fac, unsigned long exp) 295 279 296 void zmod_poly_factor_square_free(zmod_poly_factor_t res, zmod_poly_t f)297 void zmod_poly_factor_berlekamp(zmod_poly_factor_t factors, zmod_poly_t f)298 unsigned long zmod_poly_factor(zmod_poly_factor_t result, zmod_poly_t input)280 cdef void zmod_poly_factor_square_free(zmod_poly_factor_t res, zmod_poly_t f) 281 cdef void zmod_poly_factor_berlekamp(zmod_poly_factor_t factors, zmod_poly_t f) 282 cdef unsigned long zmod_poly_factor(zmod_poly_factor_t result, zmod_poly_t input) -
new file sage/rings/fraction_field_FpT.pxd
diff -r 1cf975c520f1 -r 081dadd2f119 sage/rings/fraction_field_FpT.pxd
- + 1 2 from sage.libs.flint.zmod_poly cimport * 3 4 from sage.rings.morphism cimport RingHomomorphism_coercion 5 from sage.categories.morphism cimport Morphism 6 from sage.structure.element cimport Element, ModuleElement, RingElement 7 from sage.categories.map cimport Section 8 9 cdef class FpTElement(RingElement): 10 cdef zmod_poly_t _numer, _denom 11 cdef bint initalized 12 cdef long p 13 14 cdef FpTElement _new_c(self) 15 cdef FpTElement _copy_c(self) 16 cpdef FpTElement next(self) 17 cpdef _sqrt_or_None(self) 18 cpdef bint is_square(self) 19 20 cdef class FpT_iter: 21 cdef parent 22 cdef long degree 23 cdef FpTElement cur 24 cdef zmod_poly_t g 25 26 cdef class Polyring_FpT_coerce(RingHomomorphism_coercion): 27 cdef long p 28 cdef class FpT_Polyring_section(Section): 29 cdef long p 30 cdef class Fp_FpT_coerce(RingHomomorphism_coercion): 31 cdef long p 32 cdef class FpT_Fp_section(Section): 33 cdef long p 34 cdef class ZZ_FpT_coerce(RingHomomorphism_coercion): 35 cdef long p 36 #cdef class int_FpT_coerce(Morphism): 37 # cdef long p 38 39 40 -
sage/rings/fraction_field_FpT.pyx
diff -r 1cf975c520f1 -r 081dadd2f119 sage/rings/fraction_field_FpT.pyx
a b 1 2 1 3 import sys 2 4 5 include "../ext/cdefs.pxi" 6 include "../ext/gmp.pxi" 7 include "../ext/interrupt.pxi" 8 include "../ext/stdsage.pxi" 9 3 10 from sage.rings.all import GF 4 from sage.rings.ring cimport Field5 11 from sage.libs.flint.zmod_poly cimport * 6 12 from sage.structure.element cimport Element, ModuleElement, RingElement 13 from sage.rings.integer_ring import ZZ 14 from sage.rings.fraction_field import FractionField_generic 15 from sage.rings.integer_mod cimport IntegerMod_int 16 from sage.rings.integer cimport Integer 17 from sage.rings.polynomial.polynomial_zmod_flint cimport Polynomial_zmod_flint 7 18 import sage.algebras.algebra 8 19 9 20 from sage.rings.integer_mod cimport jacobi_int, mod_inverse_int, mod_pow_int 10 21 11 class Fpt(Field): 12 def __init__(self, long p, names='t'): 22 class FpT(FractionField_generic): 23 """ 24 This class represents the fraction field GF(p)(T) for `2 < p < 2^16`. 25 26 EXAMPLES:: 27 28 sage: R.<T> = GF(71)[] 29 sage: K = FractionField(R); K 30 Fraction Field of Univariate Polynomial Ring in T over Finite Field of size 71 31 sage: TestSuite(R).run() 32 """ 33 def __init__(self, R, names=None): # we include names so that one can use the syntax K.<t> = FpT(GF(5)['t']). It's actually ignored 34 """ 35 INPUT: 36 37 - ``R`` -- A polynomial ring over a finite field of prime order `p` with `2 < p < 2^16` 38 39 EXAMPLES:: 40 41 sage: R.<x> = GF(31)[] 42 sage: K = R.fraction_field(); K 43 Fraction Field of Univariate Polynomial Ring in x over Finite Field of size 31 44 """ 45 cdef long p = R.base_ring().characteristic() 13 46 assert 2 < p < 2**16 14 if isinstance(names, tuple):15 names, = names16 47 self.p = p 17 base_ring = GF(p) 18 self.poly_ring = base_ring[names] 19 sage.algebras.algebra.Algebra.__init__(self, base_ring, names=names, normalize=True) 20 self._populate_coercion_lists_(element_constructor=FptElement) 21 22 # def _element_constructor_(self, *args): 23 # return FptElement(self, *args) 24 25 def ngens(self): 26 return 1 27 28 def gen(self, ix): 29 assert ix == 0 30 return FptElement(self, self.poly_ring.gen()) 31 32 def characteristic(self): 33 return self.p 34 35 def _coerce_map_from_(self, R): 36 return self.poly_ring.has_coerce_map_from(R) 48 self.poly_ring = R 49 FractionField_generic.__init__(self, R, element_class = FpTElement) 50 self._populate_coercion_lists_(coerce_list=[Polyring_FpT_coerce(self), Fp_FpT_coerce(self), ZZ_FpT_coerce(self)]) 37 51 38 52 def __iter__(self): 53 """ 54 Returns an iterator over this fraction field. 55 56 EXAMPLES:: 57 58 sage: R.<t> = GF(3)[]; K = R.fraction_field() 59 sage: iter(K) 60 <sage.rings.fraction_field_FpT.FpT_iter object at ...> 61 """ 39 62 return self.iter() 40 63 41 64 def iter(self, bound=None, start=None): 42 65 """ 43 66 sage: from sage.rings.fraction_field_FpT import * 44 sage: R.<t> = Fpt(5) 45 sage: list(R.iter(2)) 67 sage: R.<t> = FpT(GF(5)['t']) 68 sage: list(R.iter(2))[350:355] 69 [(t^2 + t + 1)/(t + 2), 70 (t^2 + t + 2)/(t + 2), 71 (t^2 + t + 4)/(t + 2), 72 (t^2 + 2*t + 1)/(t + 2), 73 (t^2 + 2*t + 2)/(t + 2)] 46 74 """ 47 return Fp t_iter(self, bound, start)75 return FpT_iter(self, bound, start) 48 76 49 cdef class FptElement(RingElement): 77 cdef class FpTElement(RingElement): 78 """ 79 An element of an FpT fraction field. 80 """ 81 82 def __init__(self, parent, numer, denom=1, coerce=True, reduce=True): 83 """ 84 INPUT: 50 85 51 cdef long p52 cdef zmod_poly_t _numer, _denom53 cdef bint initalized86 - parent -- the Fraction field containing this element 87 - numer -- something that can be converted into the polynomial ring, giving the numerator 88 - denom -- something that can be converted into the polynomial ring, giving the numerator (default 1) 54 89 55 def __init__(self, parent, numer, denom=1):56 """57 90 EXAMPLES:: 58 91 59 92 sage: from sage.rings.fraction_field_FpT import * 60 sage: R.<t> = Fp t(5)93 sage: R.<t> = FpT(GF(5)['t']) 61 94 sage: R(7) 62 95 2 63 96 64 97 """ 65 98 RingElement.__init__(self, parent) 66 numer = parent.poly_ring(numer) 67 denom = parent.poly_ring(denom) 99 if coerce: 100 numer = parent.poly_ring(numer) 101 denom = parent.poly_ring(denom) 68 102 self.p = parent.p 69 103 zmod_poly_init(self._numer, self.p) 70 104 zmod_poly_init(self._denom, self.p) … … 74 108 zmod_poly_set_coeff_ui(self._numer, n, a) 75 109 for n, a in enumerate(denom): 76 110 zmod_poly_set_coeff_ui(self._denom, n, a) 77 normalize(self._numer, self._denom, self.p) 111 if reduce: 112 normalize(self._numer, self._denom, self.p) 78 113 79 114 def __dealloc__(self): 115 """ 116 Deallocation. 117 118 EXAMPLES:: 119 120 sage: K = GF(11)['t'].fraction_field() 121 sage: t = K.gen() 122 sage: del t # indirect doctest 123 """ 80 124 if self.initalized: 81 125 zmod_poly_clear(self._numer) 82 126 zmod_poly_clear(self._denom) 83 127 84 cdef FptElement _new_c(self): 85 cdef FptElement x = <FptElement>PY_NEW(FptElement) 128 cdef FpTElement _new_c(self): 129 """ 130 Creates a new FpTElement in the same field, leaving the value to be initialized. 131 """ 132 cdef FpTElement x = <FpTElement>PY_NEW(FpTElement) 86 133 x._parent = self._parent 87 134 x.p = self.p 88 135 zmod_poly_init_precomp(x._numer, x.p, self._numer.p_inv) … … 90 137 x.initalized = True 91 138 return x 92 139 93 cdef FptElement _copy_c(self): 94 cdef FptElement x = <FptElement>PY_NEW(FptElement) 140 cdef FpTElement _copy_c(self): 141 """ 142 Creates a new FpTElement in the same field, with the same value as self. 143 """ 144 cdef FpTElement x = <FpTElement>PY_NEW(FpTElement) 95 145 x._parent = self._parent 96 146 x.p = self.p 97 147 zmod_poly_init2_precomp(x._numer, x.p, self._numer.p_inv, self._numer.length) … … 102 152 return x 103 153 104 154 def numer(self): 155 """ 156 Returns the numerator of this element, as an element of the polynomial ring. 157 158 EXAMPLES:: 159 160 sage: K = GF(11)['t'].fraction_field() 161 sage: t = K.gen(0); a = (t + 1/t)^3 - 1 162 sage: a.numer() 163 t^6 + 3*t^4 + 10*t^3 + 3*t^2 + 1 164 """ 105 165 cdef long n 106 166 return self._parent.poly_ring( 107 167 [zmod_poly_get_coeff_ui (self._numer, n) for n in range(0, zmod_poly_degree(self._numer)+1)]) 108 168 169 def numerator(self): 170 """ 171 Returns the numerator of this element, as an element of the polynomial ring. 172 173 EXAMPLES:: 174 175 sage: K = GF(11)['t'].fraction_field() 176 sage: t = K.gen(0); a = (t + 1/t)^3 - 1 177 sage: a.numerator() 178 t^6 + 3*t^4 + 10*t^3 + 3*t^2 + 1 179 """ 180 return self.numer() 181 109 182 def denom(self): 183 """ 184 Returns the denominator of this element, as an element of the polynomial ring. 185 186 EXAMPLES:: 187 188 sage: K = GF(11)['t'].fraction_field() 189 sage: t = K.gen(0); a = (t + 1/t)^3 - 1 190 sage: a.denom() 191 t^3 192 """ 110 193 cdef long n 111 194 return self._parent.poly_ring( 112 195 [zmod_poly_get_coeff_ui (self._denom, n) for n in range(0, zmod_poly_degree(self._denom)+1)]) 113 196 197 def denominator(self): 198 """ 199 Returns the denominator of this element, as an element of the polynomial ring. 200 201 EXAMPLES:: 202 203 sage: K = GF(11)['t'].fraction_field() 204 sage: t = K.gen(0); a = (t + 1/t)^3 - 1 205 sage: a.denominator() 206 t^3 207 """ 208 return self.denom() 209 114 210 def _repr_(self): 115 211 """ 212 Returns a string representation of this element. 213 214 EXAMPLES:: 215 116 216 sage: from sage.rings.fraction_field_FpT import * 117 sage: R.<t> = Fp t(17)118 sage: -t 217 sage: R.<t> = FpT(GF(17)['t']) 218 sage: -t # indirect doctest 119 219 16*t 120 220 sage: 1/t 121 221 1/t … … 138 238 return "%s/%s" % (numer_s, denom_s) 139 239 140 240 def _latex_(self): 241 r""" 242 Returns a latex representation of this element. 243 244 EXAMPLES:: 245 246 sage: K = GF(7)['t'].fraction_field(); t = K.gen(0) 247 sage: latex(t^2 + 1) # indirect doctest 248 t^{2} + 1 249 sage: latex((t + 1)/(t-1)) 250 \frac{t + 1}{t + 6} 251 """ 141 252 if zmod_poly_degree(self._denom) == 0 and zmod_poly_get_coeff_ui(self._denom, 0) == 1: 142 253 return self.numer()._latex_() 143 254 else: 144 return "{%s}/{%s}" % (self.numer()._latex_(), self.denom()._latex_()) 145 return 255 return "\\frac{%s}{%s}" % (self.numer()._latex_(), self.denom()._latex_()) 146 256 147 def __ cmp__(self, other):257 def __richcmp__(left, right, int op): 148 258 """ 259 EXAMPLES:: 260 261 sage: K = Frac(GF(5)['t']); t = K.gen() 262 sage: t == 1 263 False 264 sage: t + 1 < t^2 265 True 266 """ 267 return (<Element>left)._richcmp(right, op) 268 269 cdef int _cmp_c_impl(self, Element other) except -2: 270 """ 271 Compares this with another element. 272 149 273 TESTS:: 150 274 151 275 sage: from sage.rings.fraction_field_FpT import * 152 sage: R.<t> = Fp t(7)276 sage: R.<t> = FpT(GF(7)['t']) 153 277 sage: t == t 154 278 True 155 279 sage: t == -t … … 160 284 True 161 285 sage: 1/t == 1/(t+1) 162 286 False 287 sage: 2*t/t == 2 288 True 289 sage: 2*t/2 == t 290 True 163 291 """ 164 if isinstance(other, FptElement): 165 # They are normalized. 166 if (zmod_poly_equal(self._numer, (<FptElement>other)._numer) and 167 zmod_poly_equal(self._denom, (<FptElement>other)._denom)): 168 return 0 169 else: 170 return -1 292 # They are normalized. 293 if (zmod_poly_equal(self._numer, (<FpTElement>other)._numer) and 294 zmod_poly_equal(self._denom, (<FpTElement>other)._denom)): 295 return 0 171 296 else: 172 return cmp(type(self), type(other))297 return -1 173 298 174 299 def __hash__(self): 175 300 """ 301 Returns a hash value for this element. 302 176 303 TESTS:: 177 304 178 305 sage: from sage.rings.fraction_field_FpT import * 179 sage: K.<t> = Fp t(7)306 sage: K.<t> = FpT(GF(7)['t']) 180 307 sage: hash(K(0)) 181 308 0 182 309 sage: hash(K(5)) 183 310 5 184 311 sage: set([1, t, 1/t, t, t, 1/t, 1+1/t, t/t]) 185 set([1 , (t + 1)/t, t, 1/t])312 set([1/t, 1, t, (t + 1)/t]) 186 313 """ 187 314 if self.denom() == 1: 188 315 return hash(self.numer()) 189 316 return hash(str(self)) 190 317 191 318 def __neg__(self): 192 cdef FptElement x = self._new_c() 319 """ 320 Negates this element. 321 322 EXAMPLES:: 323 324 sage: K = GF(5)['t'].fraction_field(); t = K.gen(0) 325 sage: a = (t^2 + 2)/(t-1) 326 sage: -a # indirect doctest 327 (4*t^2 + 3)/(t + 4) 328 """ 329 cdef FpTElement x = self._new_c() 193 330 zmod_poly_neg(x._numer, self._numer) 194 331 zmod_poly_set(x._denom, self._denom) 195 332 return x 196 333 197 334 def __invert__(self): 335 """ 336 Returns the multiplicative inverse of this element. 337 338 EXAMPLES:: 339 340 sage: K = GF(5)['t'].fraction_field(); t = K.gen(0) 341 sage: a = (t^2 + 2)/(t-1) 342 sage: ~a # indirect doctest 343 (t + 4)/(t^2 + 2) 344 """ 198 345 if zmod_poly_degree(self._numer) == -1: 199 346 raise ZeroDivisionError 200 cdef Fp tElement x = self._new_c()347 cdef FpTElement x = self._new_c() 201 348 zmod_poly_set(x._denom, self._numer) 202 349 zmod_poly_set(x._numer, self._denom) 203 350 return x 204 351 205 352 cpdef ModuleElement _add_(self, ModuleElement _other): 206 353 """ 354 Returns the sum of this fraction field element and another. 355 207 356 EXAMPLES:: 208 357 209 358 sage: from sage.rings.fraction_field_FpT import * 210 sage: R.<t> = Fp t(7)211 sage: t + t 359 sage: R.<t> = FpT(GF(7)['t']) 360 sage: t + t # indirect doctest 212 361 2*t 213 362 sage: (t + 3) + (t + 10) 214 363 2*t + 6 215 364 sage: sum([t] * 7) 216 365 0 217 366 sage: 1/t + t 218 (t^2 + 1)/ (t)367 (t^2 + 1)/t 219 368 sage: 1/t + 1/t^2 220 (t + 1)/ (t^2)369 (t + 1)/t^2 221 370 """ 222 cdef Fp tElement other = <FptElement>_other223 cdef Fp tElement x = self._new_c()371 cdef FpTElement other = <FpTElement>_other 372 cdef FpTElement x = self._new_c() 224 373 zmod_poly_mul(x._numer, self._numer, other._denom) 225 374 zmod_poly_mul(x._denom, self._denom, other._numer) # use x._denom as a temp 226 375 zmod_poly_add(x._numer, x._numer, x._denom) … … 230 379 231 380 cpdef ModuleElement _sub_(self, ModuleElement _other): 232 381 """ 382 Returns the difference of this fraction field element and another. 383 233 384 EXAMPLES:: 234 385 235 386 sage: from sage.rings.fraction_field_FpT import * 236 sage: R.<t> = Fp t(7)237 sage: t - t 387 sage: R.<t> = FpT(GF(7)['t']) 388 sage: t - t # indirect doctest 238 389 0 239 390 sage: (t + 3) - (t + 11) 240 sage:6391 6 241 392 """ 242 cdef Fp tElement other = <FptElement>_other243 cdef Fp tElement x = self._new_c()393 cdef FpTElement other = <FpTElement>_other 394 cdef FpTElement x = self._new_c() 244 395 zmod_poly_mul(x._numer, self._numer, other._denom) 245 396 zmod_poly_mul(x._denom, self._denom, other._numer) # use x._denom as a temp 246 397 zmod_poly_sub(x._numer, x._numer, x._denom) … … 250 401 251 402 cpdef RingElement _mul_(self, RingElement _other): 252 403 """ 404 Returns the product of this fraction field element and another. 405 253 406 EXAMPLES:: 254 407 255 408 sage: from sage.rings.fraction_field_FpT import * 256 sage: R.<t> = Fp t(7)257 sage: t * t 409 sage: R.<t> = FpT(GF(7)['t']) 410 sage: t * t # indirect doctest 258 411 t^2 259 412 sage: (t + 3) * (t + 10) 260 413 t^2 + 6*t + 2 261 414 """ 262 cdef Fp tElement other = <FptElement>_other263 cdef Fp tElement x = self._new_c()415 cdef FpTElement other = <FpTElement>_other 416 cdef FpTElement x = self._new_c() 264 417 zmod_poly_mul(x._numer, self._numer, other._numer) 265 418 zmod_poly_mul(x._denom, self._denom, other._denom) 266 419 normalize(x._numer, x._denom, self.p) … … 268 421 269 422 cpdef RingElement _div_(self, RingElement _other): 270 423 """ 424 Returns the quotient of this fraction field element and another. 425 271 426 EXAMPLES:: 272 427 273 428 sage: from sage.rings.fraction_field_FpT import * 274 sage: R.<t> = Fp t(5)275 sage: t / t 429 sage: R.<t> = FpT(GF(5)['t']) 430 sage: t / t # indirect doctest 276 431 1 277 432 sage: (t + 3) / (t + 11) 278 433 (t + 3)/(t + 1) 279 434 sage: (t^2 + 2*t + 1) / (t + 1) 280 435 t + 1 281 436 """ 282 cdef Fp tElement other = <FptElement>_other437 cdef FpTElement other = <FpTElement>_other 283 438 if zmod_poly_degree(other._numer) == -1: 284 439 raise ZeroDivisionError 285 cdef Fp tElement x = self._new_c()440 cdef FpTElement x = self._new_c() 286 441 zmod_poly_mul(x._numer, self._numer, other._denom) 287 442 zmod_poly_mul(x._denom, self._denom, other._numer) 288 443 normalize(x._numer, x._denom, self.p) 289 444 return x 290 445 291 cpdef FptElement next(self): 292 # TODO: This misses denom > numer... 446 cpdef FpTElement next(self): 293 447 """ 448 This function iterates through all polynomials, returning the "next" polynomial after this one. 449 450 The strategy is as follows: 451 452 - We always leave the denominator monic. 453 454 - We progress through the elements with both numerator and denominator monic, and with the denominator less than the numerator. 455 For each such, we output all the scalar multiples of it, then all of the scalar multiples of its inverse. 456 457 - So if the leading coefficient of the numerator is less than p-1, we scale the numerator to increase it by 1. 458 459 - Otherwise, we consider the multiple with numerator and denominator monic. 460 461 - If the numerator is less than the denominator (lexicographically), we return the inverse of that element. 462 463 - 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. 464 294 465 EXAMPLES:: 295 466 296 467 sage: from sage.rings.fraction_field_FpT import * 297 sage: R.<t> = Fp t(3)468 sage: R.<t> = FpT(GF(3)['t']) 298 469 sage: a = R(0) 299 sage: for _ in range( 15):470 sage: for _ in range(30): 300 471 ... a = a.next() 301 472 ... print a 302 473 ... 303 474 1 304 475 2 476 1/t 477 2/t 305 478 t 479 2*t 480 1/(t + 1) 481 2/(t + 1) 306 482 t + 1 307 (t + 1)/(t) 483 2*t + 2 484 t/(t + 1) 485 2*t/(t + 1) 486 (t + 1)/t 487 (2*t + 2)/t 488 1/(t + 2) 489 2/(t + 2) 308 490 t + 2 309 (t + 2)/(t) 491 2*t + 1 492 t/(t + 2) 493 2*t/(t + 2) 494 (t + 2)/t 495 (2*t + 1)/t 496 (t + 1)/(t + 2) 497 (2*t + 2)/(t + 2) 310 498 (t + 2)/(t + 1) 311 2*t312 (2*t)/(t + 1)313 (2*t)/(t + 2)314 2*t + 1315 (2*t + 1)/(t)316 499 (2*t + 1)/(t + 1) 317 2*t + 2 500 1/t^2 501 2/t^2 502 t^2 503 2*t^2 318 504 """ 319 cdef FptElement x = self._new_c() 505 cdef FpTElement next = self._copy_c() 506 cdef long a, lead 507 cdef zmod_poly_t g 320 508 if zmod_poly_degree(self._numer) == -1: 321 zmod_poly_set_coeff_ui(x._numer, 0, 1) 322 zmod_poly_set_coeff_ui(x._denom, 0, 1) 323 return x 324 elif zmod_poly_degree(self._numer) == 0: 325 zmod_poly_set_coeff_ui(x._numer, 0, zmod_poly_get_coeff_ui(self._numer, 0) + 1) 326 zmod_poly_set_coeff_ui(x._denom, 0, 1) 327 if zmod_poly_get_coeff_ui(x._numer, 0) == 0: 328 zmod_poly_set_coeff_ui(x._numer, 1, 1) 329 return x 330 cdef zmod_poly_t g 331 zmod_poly_init(g, self.p) 332 zmod_poly_set(x._numer, self._numer) 333 zmod_poly_set(x._denom, self._denom) 334 while True: 335 zmod_poly_inc(x._denom, True) 336 if zmod_poly_degree(x._numer) < zmod_poly_degree(x._denom): 337 zmod_poly_inc(x._numer, False) 338 zmod_poly_zero(x._denom) 339 zmod_poly_set_coeff_ui(x._denom, 0, 1) 340 zmod_poly_gcd(g, x._numer, x._denom) 341 if zmod_poly_is_one(g): 342 zmod_poly_clear(g) 343 return x 509 # self should be normalized, so denom == 1 510 zmod_poly_set_coeff_ui(next._numer, 0, 1) 511 return next 512 lead = zmod_poly_leading(next._numer) 513 if lead < self.p - 1: 514 a = mod_inverse_int(lead, self.p) 515 # no overflow since self.p < 2^16 516 a = a * (lead + 1) % self.p 517 zmod_poly_scalar_mul(next._numer, next._numer, a) 518 else: 519 a = mod_inverse_int(lead, self.p) 520 zmod_poly_scalar_mul(next._numer, next._numer, a) 521 # now both next._numer and next._denom are monic. We figure out which is lexicographically bigger: 522 a = zmod_poly_cmp(next._numer, next._denom) 523 if a == 0: 524 # next._numer and next._denom are relatively prime, so they're both 1. 525 zmod_poly_inc(next._denom, True) 526 return next 527 zmod_poly_set(next._denom, next._numer) 528 zmod_poly_set(next._numer, self._denom) 529 if a < 0: 530 # since next._numer is smaller, we flip and return the inverse. 531 return next 532 elif a > 0: 533 # since next._numer is bigger, we're in the flipped phase. We flip back, and increment the numerator (until we reach the denominator). 534 zmod_poly_init(g, self.p) 535 try: 536 while True: 537 zmod_poly_inc(next._numer, True) 538 if zmod_poly_equal(next._numer, next._denom): 539 # Since we've reached the denominator, we reset the numerator to 1 and increment the denominator. 540 zmod_poly_inc(next._denom, True) 541 zmod_poly_zero(next._numer) 542 zmod_poly_set_coeff_ui(next._numer, 0, 1) 543 break 544 else: 545 # otherwise, we keep incrementing until we have a relatively prime numerator. 546 zmod_poly_gcd(g, next._numer, next._denom) 547 if zmod_poly_is_one(g): 548 break 549 finally: 550 zmod_poly_clear(g) 551 return next 552 553 # if zmod_poly_degree(self._numer) == -1: 554 # zmod_poly_set_coeff_ui(x._numer, 0, 1) 555 # zmod_poly_set_coeff_ui(x._denom, 0, 1) 556 # return x 557 # elif zmod_poly_degree(self._numer) == 0: 558 # zmod_poly_set_coeff_ui(x._numer, 0, zmod_poly_get_coeff_ui(self._numer, 0) + 1) 559 # zmod_poly_set_coeff_ui(x._denom, 0, 1) 560 # if zmod_poly_get_coeff_ui(x._numer, 0) == 0: 561 # zmod_poly_set_coeff_ui(x._numer, 1, 1) 562 # return x 563 # cdef zmod_poly_t g 564 # zmod_poly_init(g, self.p) 565 # zmod_poly_set(x._numer, self._numer) 566 # zmod_poly_set(x._denom, self._denom) 567 # while True: 568 # zmod_poly_inc(x._denom, True) 569 # if zmod_poly_degree(x._numer) < zmod_poly_degree(x._denom): 570 # zmod_poly_inc(x._numer, False) 571 # zmod_poly_zero(x._denom) 572 # zmod_poly_set_coeff_ui(x._denom, 0, 1) 573 # zmod_poly_gcd(g, x._numer, x._denom) 574 # if zmod_poly_is_one(g): 575 # zmod_poly_clear(g) 576 # return x 344 577 345 578 cpdef _sqrt_or_None(self): 346 579 """ … … 349 582 TESTS:: 350 583 351 584 sage: from sage.rings.fraction_field_FpT import * 352 sage: R.<t> = Fp t(17)353 sage: sqrt(t^2) 585 sage: R.<t> = FpT(GF(17)['t']) 586 sage: sqrt(t^2) # indirect doctest 354 587 t 355 588 sage: sqrt(1/t^2) 356 589 1/t … … 370 603 sage: sqrt(t^4) 371 604 t^2 372 605 sage: sqrt(4*t^4/(1+t)^8) 373 4*t^2/(t^4 + 4*t^3 + 6*t^2 + 4*t + 1)606 2*t^2/(t^4 + 4*t^3 + 6*t^2 + 4*t + 1) 374 607 375 sage: R.<t> = Fp t(5)608 sage: R.<t> = FpT(GF(5)['t']) 376 609 sage: [a for a in R.iter(2) if (a^2).sqrt() not in (a,-a)] 377 610 [] 378 611 sage: [a for a in R.iter(2) if a.is_square() and a.sqrt()^2 != a] … … 385 618 return None 386 619 cdef zmod_poly_t numer 387 620 cdef zmod_poly_t denom 388 cdef Fp tElement res621 cdef FpTElement res 389 622 try: 390 623 zmod_poly_init(denom, self.p) 391 624 zmod_poly_init(numer, self.p) … … 402 635 zmod_poly_clear(denom) 403 636 404 637 cpdef bint is_square(self): 638 """ 639 Returns True if this element is the square of another element of the fraction field. 640 641 EXAMPLES:: 642 643 sage: K = GF(13)['t'].fraction_field(); t = K.gen() 644 sage: t.is_square() 645 False 646 sage: (1/t^2).is_square() 647 True 648 sage: K(0).is_square() 649 True 650 """ 405 651 return self._sqrt_or_None() is not None 406 652 407 def sqrt(self ):653 def sqrt(self, extend=True, all=False): 408 654 """ 655 Returns the square root of this element. 656 657 INPUT: 658 659 - ``extend`` - bool (default: True); if True, return a 660 square root in an extension ring, if necessary. Otherwise, raise a 661 ValueError if the square is not in the base ring. 662 663 - ``all`` - bool (default: False); if True, return all 664 square roots of self, instead of just one. 665 409 666 EXAMPLES:: 410 667 411 668 sage: from sage.rings.fraction_field_FpT import * 412 sage: R.<t> = Fpt(7) 669 sage: K = GF(7)['t'].fraction_field(); t = K.gen(0) 670 sage: ((t + 2)^2/(3*t^3 + 1)^4).sqrt() 671 (3*t + 6)/(t^6 + 3*t^3 + 4) 413 672 """ 414 673 s = self._sqrt_or_None() 415 674 if s is None: 416 raise ValueError, "not a perfect square" 675 if extend: 676 raise NotImplementedError, "function fields not yet implemented" 677 else: 678 raise ValueError, "not a perfect square" 417 679 else: 418 return s 680 if all: 681 if not s: 682 return [s] 683 else: 684 return [s, -s] 685 else: 686 return s 419 687 420 def __pow__(Fp tElement self, Py_ssize_t e, dummy):688 def __pow__(FpTElement self, Py_ssize_t e, dummy): 421 689 """ 690 Returns the ``e``th power of this element. 691 422 692 EXAMPLES:: 423 693 424 694 sage: from sage.rings.fraction_field_FpT import * 425 sage: R.<t> = Fp t(7)695 sage: R.<t> = FpT(GF(7)['t']) 426 696 sage: t^5 427 697 t^5 428 698 sage: t^-5 … … 446 716 """ 447 717 cdef long a 448 718 assert dummy is None 449 cdef Fp tElement x = self._new_c()719 cdef FpTElement x = self._new_c() 450 720 if e >= 0: 451 721 zmod_poly_pow(x._numer, self._numer, e) 452 722 zmod_poly_pow(x._denom, self._denom, e) … … 460 730 return x 461 731 462 732 463 cdef class Fpt_iter: 464 465 cdef parent 466 cdef long degree 467 cdef FptElement cur 468 cdef zmod_poly_t g 469 470 def __init__(self, parent, degree=None, FptElement start=None): 471 if degree is None: 472 raise NotImplementedError 733 cdef class FpT_iter: 734 """ 735 Returns a class that iterates over all elements of an FpT. 736 737 EXAMPLES:: 738 739 sage: K = GF(3)['t'].fraction_field() 740 sage: I = K.iter(1) 741 sage: list(I) 742 [0, 743 1, 744 2, 745 t, 746 t + 1, 747 t + 2, 748 2*t, 749 2*t + 1, 750 2*t + 2, 751 1/t, 752 2/t, 753 (t + 1)/t, 754 (t + 2)/t, 755 (2*t + 1)/t, 756 (2*t + 2)/t, 757 1/(t + 1), 758 2/(t + 1), 759 t/(t + 1), 760 (t + 2)/(t + 1), 761 2*t/(t + 1), 762 (2*t + 1)/(t + 1), 763 1/(t + 2), 764 2/(t + 2), 765 t/(t + 2), 766 (t + 1)/(t + 2), 767 2*t/(t + 2), 768 (2*t + 2)/(t + 2)] 769 """ 770 def __init__(self, parent, degree=None, FpTElement start=None): 771 """ 772 INPUTS: 773 774 - parent -- The FpT that we're iterating over. 775 776 - degree -- The maximum degree of the numerator and denominator of the elements over which we iterate. 777 778 - start -- (default 0) The element on which to start. 779 780 EXAMPLES:: 781 782 sage: K = GF(11)['t'].fraction_field() 783 sage: I = K.iter(2) # indirect doctest 784 sage: for a in I: 785 ... if a.denom()[0] == 3 and a.numer()[1] == 2: 786 ... print a; break 787 2*t/(t + 3) 788 """ 789 #if degree is None: 790 # raise NotImplementedError 473 791 self.parent = parent 474 792 self.cur = start 475 self.degree = sys.maxintif degree is None else degree793 self.degree = -2 if degree is None else degree 476 794 477 795 def __cinit__(self, parent, *args, **kwds): 796 """ 797 Memory allocation for the temp variable storing the gcd of the numerator and denominator. 798 799 TESTS:: 800 801 sage: from sage.rings.fraction_field_FpT import FpT_iter 802 sage: K = GF(7)['t'].fraction_field() 803 sage: I = FpT_iter(K, 3) # indirect doctest 804 sage: I 805 <sage.rings.fraction_field_FpT.FpT_iter object at ...> 806 """ 478 807 zmod_poly_init(self.g, parent.characteristic()) 479 808 480 809 def __dealloc__(self): 810 """ 811 Deallocating of the self.g 812 813 TESTS:: 814 815 sage: from sage.rings.fraction_field_FpT import FpT_iter 816 sage: K = GF(7)['t'].fraction_field() 817 sage: I = FpT_iter(K, 3) 818 sage: del I # indirect doctest 819 """ 481 820 zmod_poly_clear(self.g) 482 821 483 822 def __iter__(self): 823 """ 824 Returns this iterator. 825 826 TESTS:: 827 828 sage: from sage.rings.fraction_field_FpT import FpT_iter 829 sage: K = GF(3)['t'].fraction_field() 830 sage: I = FpT_iter(K, 3) 831 sage: for a in I: # indirect doctest 832 ... if a.numer()[1] == 1 and a.denom()[1] == 2 and a.is_square(): 833 ... print a; break 834 (t^2 + t + 1)/(t^2 + 2*t + 1) 835 """ 484 836 return self 485 837 486 838 def __next__(self): 487 839 """ 840 Returns the next element to iterate over. 841 842 This is achieved by iterating over monic denominators, and for each denominator, 843 iterating over all numerators relatively prime to the given denominator. 844 488 845 EXAMPLES:: 489 846 490 847 sage: from sage.rings.fraction_field_FpT import * 491 sage: K.<t> = Fp t(3)492 sage: list(K.iter(1)) 848 sage: K.<t> = FpT(GF(3)['t']) 849 sage: list(K.iter(1)) # indirect doctest 493 850 [0, 494 851 1, 495 852 2, … … 521 878 sage: len(list(K.iter(3))) 522 879 2187 523 880 524 sage: K.<t> = Fp t(5)525 sage: L = list(K.iter(3)) 881 sage: K.<t> = FpT(GF(5)['t']) 882 sage: L = list(K.iter(3)); len(L) 526 883 78125 527 884 sage: L[:10] 528 885 [0, 1, 2, 3, 4, t, t + 1, t + 2, t + 3, t + 4] … … 531 888 sage: L[-1] 532 889 (4*t^3 + 4*t^2 + 4*t + 4)/(t^3 + 4*t^2 + 4*t + 4) 533 890 """ 534 cdef Fp tElement next891 cdef FpTElement next 535 892 if self.cur is None: 536 893 self.cur = self.parent(0) 894 elif self.degree == -2: 895 self.cur = self.cur.next() 537 896 else: 538 897 next = self.cur._copy_c() 898 _sig_on 539 899 while True: 540 900 zmod_poly_inc(next._numer, False) 541 901 if zmod_poly_degree(next._numer) > self.degree: … … 547 907 zmod_poly_gcd(self.g, next._numer, next._denom) 548 908 if zmod_poly_is_one(self.g): 549 909 break 910 _sig_off 550 911 self.cur = next 551 912 # self.cur = self.cur.next() 552 913 # if zmod_poly_degree(self.cur._numer) > self.degree: 553 914 # raise StopIteration 554 915 return self.cur 555 916 917 cdef class Polyring_FpT_coerce(RingHomomorphism_coercion): 918 """ 919 This class represents the coercion map from GF(p)[t] to GF(p)(t) 556 920 921 EXAMPLES:: 922 923 sage: R.<t> = GF(5)[] 924 sage: K = R.fraction_field() 925 sage: f = K.coerce_map_from(R); f 926 Ring Coercion morphism: 927 From: Univariate Polynomial Ring in t over Finite Field of size 5 928 To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 929 sage: type(f) 930 <type 'sage.rings.fraction_field_FpT.Polyring_FpT_coerce'> 931 """ 932 def __init__(self, R): 933 """ 934 INPUTS: 935 936 - R -- An FpT 937 938 EXAMPLES:: 939 940 sage: R.<t> = GF(next_prime(2000))[] 941 sage: K = R.fraction_field() # indirect doctest 942 """ 943 RingHomomorphism_coercion.__init__(self, R.ring_of_integers().Hom(R), check=False) 944 self.p = R.base_ring().characteristic() 945 946 cpdef Element _call_(self, _x): 947 """ 948 Applies the coercion. 949 950 EXAMPLES:: 951 952 sage: R.<t> = GF(5)[] 953 sage: K = R.fraction_field() 954 sage: f = K.coerce_map_from(R) 955 sage: f(t^2 + 1) # indirect doctest 956 t^2 + 1 957 """ 958 cdef Polynomial_zmod_flint x = <Polynomial_zmod_flint?> _x 959 cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement) 960 ans._parent = self._codomain 961 ans.p = self.p 962 zmod_poly_init(ans._numer, ans.p) 963 zmod_poly_init(ans._denom, ans.p) 964 zmod_poly_set(ans._numer, &x.x) 965 zmod_poly_set_coeff_ui(ans._denom, 0, 1) 966 ans.initalized = True 967 return ans 968 969 cpdef Element _call_with_args(self, _x, args=(), kwds={}): 970 """ 971 This function allows the map to take multiple arguments, usually used to specify both numerator and denominator. 972 973 If ``reduce`` is specified as False, then the result won't be normalized. 974 975 EXAMPLES:: 976 977 sage: R.<t> = GF(5)[] 978 sage: K = R.fraction_field() 979 sage: f = K.coerce_map_from(R) 980 sage: f(2*t + 2, t + 3) # indirect doctest 981 (2*t + 2)/(t + 3) 982 sage: f(2*t + 2, 2) 983 t + 1 984 sage: f(2*t + 2, 2, reduce=False) 985 (2*t + 2)/2 986 """ 987 cdef Polynomial_zmod_flint x = <Polynomial_zmod_flint?> _x 988 cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement) 989 ans._parent = self._codomain 990 ans.p = self.p 991 zmod_poly_init(ans._numer, ans.p) 992 zmod_poly_init(ans._denom, ans.p) 993 cdef long r 994 zmod_poly_set(ans._numer, &x.x) 995 if len(args) == 0: 996 zmod_poly_set_coeff_ui(ans._denom, 0, 1) 997 elif len(args) == 1: 998 y = args[0] 999 if PY_TYPE_CHECK(y, Integer): 1000 r = mpz_fdiv_ui((<Integer>y).value, self.p) 1001 if r == 0: 1002 raise ZeroDivisionError 1003 zmod_poly_set_coeff_ui(ans._denom, 0, r) 1004 else: 1005 # could use the coerce keyword being set to False to not check this... 1006 if not (PY_TYPE_CHECK(y, Element) and y.parent() is self._domain): 1007 # We could special case integers and GF(p) elements here. 1008 y = self._domain(y) 1009 zmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x)) 1010 else: 1011 raise ValueError, "FpT only supports two positional arguments" 1012 if not (kwds.has_key('reduce') and not kwds['reduce']): 1013 normalize(ans._numer, ans._denom, ans.p) 1014 ans.initalized = True 1015 return ans 1016 1017 def section(self): 1018 """ 1019 Returns the section of this inclusion: the partially defined map from ``GF(p)(t)`` 1020 back to ``GF(p)[t]``, defined on elements with unit denominator. 1021 1022 EXAMPLES:: 1023 1024 sage: R.<t> = GF(5)[] 1025 sage: K = R.fraction_field() 1026 sage: f = K.coerce_map_from(R) 1027 sage: g = f.section(); g 1028 Section map: 1029 From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 1030 To: Univariate Polynomial Ring in t over Finite Field of size 5 1031 sage: t = K.gen() 1032 sage: g(t) 1033 t 1034 sage: g(1/t) 1035 Traceback (most recent call last): 1036 ... 1037 ValueError: not integral 1038 """ 1039 return FpT_Polyring_section(self) 1040 1041 cdef class FpT_Polyring_section(Section): 1042 """ 1043 This class represents the section from GF(p)(t) back to GF(p)[t] 1044 1045 EXAMPLES:: 1046 1047 sage: R.<t> = GF(5)[] 1048 sage: K = R.fraction_field() 1049 sage: f = R.convert_map_from(K); f 1050 Section map: 1051 From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 1052 To: Univariate Polynomial Ring in t over Finite Field of size 5 1053 sage: type(f) 1054 <type 'sage.rings.fraction_field_FpT.FpT_Polyring_section'> 1055 """ 1056 def __init__(self, Polyring_FpT_coerce f): 1057 """ 1058 INPUTS: 1059 1060 - f -- A Polyring_FpT_coerce homomorphism 1061 1062 EXAMPLES:: 1063 1064 sage: R.<t> = GF(next_prime(2000))[] 1065 sage: K = R.fraction_field() 1066 sage: R(K.gen(0)) # indirect doctest 1067 t 1068 """ 1069 self.p = f.p 1070 Section.__init__(self, f) 1071 1072 cpdef Element _call_(self, _x): 1073 """ 1074 Applies the section. 1075 1076 EXAMPLES:: 1077 1078 sage: R.<t> = GF(7)[] 1079 sage: K = R.fraction_field() 1080 sage: f = K.coerce_map_from(R) 1081 sage: g = f.section(); g 1082 Section map: 1083 From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 1084 To: Univariate Polynomial Ring in t over Finite Field of size 7 1085 sage: t = K.gen() 1086 sage: g(t^2) # indirect doctest 1087 t^2 1088 sage: g(1/t) 1089 Traceback (most recent call last): 1090 ... 1091 ValueError: not integral 1092 """ 1093 cdef FpTElement x = <FpTElement?>_x 1094 cdef Polynomial_zmod_flint ans 1095 if zmod_poly_degree(x._denom) != 0: 1096 normalize(x._numer, x._denom, self.p) 1097 if zmod_poly_degree(x._denom) != 0: 1098 raise ValueError, "not integral" 1099 ans = PY_NEW(Polynomial_zmod_flint) 1100 if zmod_poly_get_coeff_ui(x._denom, 0) != 1: 1101 normalize(x._numer, x._denom, self.p) 1102 zmod_poly_init(&ans.x, self.p) 1103 zmod_poly_set(&ans.x, x._numer) 1104 ans._parent = self._codomain 1105 return ans 1106 1107 cdef class Fp_FpT_coerce(RingHomomorphism_coercion): 1108 """ 1109 This class represents the coercion map from GF(p) to GF(p)(t) 1110 1111 EXAMPLES:: 1112 1113 sage: R.<t> = GF(5)[] 1114 sage: K = R.fraction_field() 1115 sage: f = K.coerce_map_from(GF(5)); f 1116 Ring Coercion morphism: 1117 From: Finite Field of size 5 1118 To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 1119 sage: type(f) 1120 <type 'sage.rings.fraction_field_FpT.Fp_FpT_coerce'> 1121 """ 1122 def __init__(self, R): 1123 """ 1124 INPUTS: 1125 1126 - R -- An FpT 1127 1128 EXAMPLES:: 1129 1130 sage: R.<t> = GF(next_prime(3000))[] 1131 sage: K = R.fraction_field() # indirect doctest 1132 """ 1133 RingHomomorphism_coercion.__init__(self, R.base_ring().Hom(R), check=False) 1134 self.p = R.base_ring().characteristic() 1135 1136 cpdef Element _call_(self, _x): 1137 """ 1138 Applies the coercion. 1139 1140 EXAMPLES:: 1141 1142 sage: R.<t> = GF(5)[] 1143 sage: K = R.fraction_field() 1144 sage: f = K.coerce_map_from(GF(5)) 1145 sage: f(GF(5)(3)) # indirect doctest 1146 3 1147 """ 1148 cdef IntegerMod_int x = <IntegerMod_int?> _x 1149 cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement) 1150 ans._parent = self._codomain 1151 ans.p = self.p 1152 zmod_poly_init(ans._numer, ans.p) 1153 zmod_poly_init(ans._denom, ans.p) 1154 zmod_poly_set_coeff_ui(ans._numer, 0, x.ivalue) 1155 zmod_poly_set_coeff_ui(ans._denom, 0, 1) 1156 ans.initalized = True 1157 return ans 1158 1159 cpdef Element _call_with_args(self, _x, args=(), kwds={}): 1160 """ 1161 This function allows the map to take multiple arguments, usually used to specify both numerator and denominator. 1162 1163 If ``reduce`` is specified as False, then the result won't be normalized. 1164 1165 EXAMPLES:: 1166 1167 sage: R.<t> = GF(5)[] 1168 sage: K = R.fraction_field() 1169 sage: f = K.coerce_map_from(GF(5)) 1170 sage: f(1, t + 3) # indirect doctest 1171 1/(t + 3) 1172 sage: f(2, 2*t) 1173 1/t 1174 sage: f(2, 2*t, reduce=False) 1175 2/2*t 1176 """ 1177 cdef IntegerMod_int x = <IntegerMod_int?> _x 1178 cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement) 1179 ans._parent = self._codomain 1180 ans.p = self.p 1181 zmod_poly_init(ans._numer, ans.p) 1182 zmod_poly_init(ans._denom, ans.p) 1183 cdef long r 1184 zmod_poly_set_coeff_ui(ans._numer, 0, x.ivalue) 1185 if len(args) == 0: 1186 zmod_poly_set_coeff_ui(ans._denom, 0, 1) 1187 if len(args) == 1: 1188 y = args[0] 1189 if PY_TYPE_CHECK(y, Integer): 1190 r = mpz_fdiv_ui((<Integer>y).value, self.p) 1191 if r == 0: 1192 raise ZeroDivisionError 1193 zmod_poly_set_coeff_ui(ans._denom, 0, r) 1194 else: 1195 R = self._codomain.ring_of_integers() 1196 # could use the coerce keyword being set to False to not check this... 1197 if not (PY_TYPE_CHECK(y, Element) and y.parent() is R): 1198 # We could special case integers and GF(p) elements here. 1199 y = R(y) 1200 zmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x)) 1201 else: 1202 raise ValueError, "FpT only supports two positional arguments" 1203 if not (kwds.has_key('reduce') and not kwds['reduce']): 1204 normalize(ans._numer, ans._denom, ans.p) 1205 ans.initalized = True 1206 return ans 1207 1208 def section(self): 1209 """ 1210 Returns the section of this inclusion: the partially defined map from ``GF(p)(t)`` 1211 back to ``GF(p)``, defined on constant elements. 1212 1213 EXAMPLES:: 1214 1215 sage: R.<t> = GF(5)[] 1216 sage: K = R.fraction_field() 1217 sage: f = K.coerce_map_from(GF(5)) 1218 sage: g = f.section(); g 1219 Section map: 1220 From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 1221 To: Finite Field of size 5 1222 sage: t = K.gen() 1223 sage: g(f(1,3,reduce=False)) 1224 2 1225 sage: g(t) 1226 Traceback (most recent call last): 1227 ... 1228 ValueError: not constant 1229 sage: g(1/t) 1230 Traceback (most recent call last): 1231 ... 1232 ValueError: not integral 1233 """ 1234 return FpT_Fp_section(self) 1235 1236 cdef class FpT_Fp_section(Section): 1237 """ 1238 This class represents the section from GF(p)(t) back to GF(p)[t] 1239 1240 EXAMPLES:: 1241 1242 sage: R.<t> = GF(5)[] 1243 sage: K = R.fraction_field() 1244 sage: f = GF(5).convert_map_from(K); f 1245 Section map: 1246 From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 1247 To: Finite Field of size 5 1248 sage: type(f) 1249 <type 'sage.rings.fraction_field_FpT.FpT_Fp_section'> 1250 """ 1251 def __init__(self, Fp_FpT_coerce f): 1252 """ 1253 INPUTS: 1254 1255 - f -- An Fp_FpT_coerce homomorphism 1256 1257 EXAMPLES:: 1258 1259 sage: R.<t> = GF(next_prime(2000))[] 1260 sage: K = R.fraction_field() 1261 sage: GF(next_prime(2000))(K(127)) # indirect doctest 1262 127 1263 """ 1264 self.p = f.p 1265 Section.__init__(self, f) 1266 1267 cpdef Element _call_(self, _x): 1268 """ 1269 Applies the section. 1270 1271 EXAMPLES:: 1272 1273 sage: R.<t> = GF(7)[] 1274 sage: K = R.fraction_field() 1275 sage: f = K.coerce_map_from(GF(7)) 1276 sage: g = f.section(); g 1277 Section map: 1278 From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 1279 To: Finite Field of size 7 1280 sage: t = K.gen() 1281 sage: g(t^2) # indirect doctest 1282 Traceback (most recent call last): 1283 ... 1284 ValueError: not constant 1285 sage: g(1/t) 1286 Traceback (most recent call last): 1287 ... 1288 ValueError: not integral 1289 sage: g(K(4)) 1290 4 1291 sage: g(K(0)) 1292 0 1293 """ 1294 cdef FpTElement x = <FpTElement?>_x 1295 cdef IntegerMod_int ans 1296 if zmod_poly_degree(x._denom) != 0 or zmod_poly_degree(x._numer) > 0: 1297 normalize(x._numer, x._denom, self.p) 1298 if zmod_poly_degree(x._denom) != 0: 1299 raise ValueError, "not integral" 1300 if zmod_poly_degree(x._numer) > 0: 1301 raise ValueError, "not constant" 1302 ans = PY_NEW(IntegerMod_int) 1303 ans.__modulus = self._codomain._pyx_order 1304 if zmod_poly_get_coeff_ui(x._denom, 0) != 1: 1305 normalize(x._numer, x._denom, self.p) 1306 ans.ivalue = zmod_poly_get_coeff_ui(x._numer, 0) 1307 ans._parent = self._codomain 1308 return ans 1309 1310 cdef class ZZ_FpT_coerce(RingHomomorphism_coercion): 1311 """ 1312 This class represents the coercion map from ZZ to GF(p)(t) 1313 1314 EXAMPLES:: 1315 1316 sage: R.<t> = GF(17)[] 1317 sage: K = R.fraction_field() 1318 sage: f = K.coerce_map_from(ZZ); f 1319 Ring Coercion morphism: 1320 From: Integer Ring 1321 To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 17 1322 sage: type(f) 1323 <type 'sage.rings.fraction_field_FpT.ZZ_FpT_coerce'> 1324 """ 1325 def __init__(self, R): 1326 """ 1327 INPUTS: 1328 1329 - R -- An FpT 1330 1331 EXAMPLES:: 1332 1333 sage: R.<t> = GF(next_prime(3000))[] 1334 sage: K = R.fraction_field() # indirect doctest 1335 """ 1336 RingHomomorphism_coercion.__init__(self, ZZ.Hom(R), check=False) 1337 self.p = R.base_ring().characteristic() 1338 1339 cpdef Element _call_(self, _x): 1340 """ 1341 Applies the coercion. 1342 1343 EXAMPLES:: 1344 1345 sage: R.<t> = GF(5)[] 1346 sage: K = R.fraction_field() 1347 sage: f = K.coerce_map_from(ZZ) 1348 sage: f(3) # indirect doctest 1349 3 1350 """ 1351 cdef Integer x = <Integer?> _x 1352 cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement) 1353 ans._parent = self._codomain 1354 ans.p = self.p 1355 zmod_poly_init(ans._numer, ans.p) 1356 zmod_poly_init(ans._denom, ans.p) 1357 zmod_poly_set_coeff_ui(ans._numer, 0, mpz_fdiv_ui(x.value, self.p)) 1358 zmod_poly_set_coeff_ui(ans._denom, 0, 1) 1359 ans.initalized = True 1360 return ans 1361 1362 cpdef Element _call_with_args(self, _x, args=(), kwds={}): 1363 """ 1364 This function allows the map to take multiple arguments, usually used to specify both numerator and denominator. 1365 1366 If ``reduce`` is specified as False, then the result won't be normalized. 1367 1368 EXAMPLES:: 1369 1370 sage: R.<t> = GF(5)[] 1371 sage: K = R.fraction_field() 1372 sage: f = K.coerce_map_from(ZZ) 1373 sage: f(1, t + 3) # indirect doctest 1374 1/(t + 3) 1375 sage: f(1,2) 1376 3 1377 sage: f(2, 2*t) 1378 1/t 1379 sage: f(2, 2*t, reduce=False) 1380 2/2*t 1381 """ 1382 cdef Integer x = <Integer?> _x 1383 cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement) 1384 ans._parent = self._codomain 1385 ans.p = self.p 1386 zmod_poly_init(ans._numer, ans.p) 1387 zmod_poly_init(ans._denom, ans.p) 1388 cdef long r 1389 zmod_poly_set_coeff_ui(ans._numer, 0, mpz_fdiv_ui(x.value, self.p)) 1390 if len(args) == 0: 1391 zmod_poly_set_coeff_ui(ans._denom, 0, 1) 1392 if len(args) == 1: 1393 y = args[0] 1394 if PY_TYPE_CHECK(y, Integer): 1395 r = mpz_fdiv_ui((<Integer>y).value, self.p) 1396 if r == 0: 1397 raise ZeroDivisionError 1398 zmod_poly_set_coeff_ui(ans._denom, 0, r) 1399 else: 1400 R = self._codomain.ring_of_integers() 1401 # could use the coerce keyword being set to False to not check this... 1402 if not (PY_TYPE_CHECK(y, Element) and y.parent() is R): 1403 # We could special case integers and GF(p) elements here. 1404 y = R(y) 1405 zmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x)) 1406 else: 1407 raise ValueError, "FpT only supports two positional arguments" 1408 if not (kwds.has_key('reduce') and not kwds['reduce']): 1409 normalize(ans._numer, ans._denom, ans.p) 1410 ans.initalized = True 1411 return ans 1412 1413 def section(self): 1414 """ 1415 Returns the section of this inclusion: the partially defined map from ``GF(p)(t)`` 1416 back to ``ZZ``, defined on constant elements. 1417 1418 EXAMPLES:: 1419 1420 sage: R.<t> = GF(5)[] 1421 sage: K = R.fraction_field() 1422 sage: f = K.coerce_map_from(ZZ) 1423 sage: g = f.section(); g 1424 Composite map: 1425 From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 1426 To: Integer Ring 1427 Defn: Section map: 1428 From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 1429 To: Finite Field of size 5 1430 then 1431 Lifting morphism: 1432 From: Finite Field of size 5 1433 To: Integer Ring 1434 sage: t = K.gen() 1435 sage: g(f(1,3,reduce=False)) 1436 2 1437 sage: g(t) 1438 Traceback (most recent call last): 1439 ... 1440 ValueError: not constant 1441 sage: g(1/t) 1442 Traceback (most recent call last): 1443 ... 1444 ValueError: not integral 1445 """ 1446 return self._codomain.base_ring().coerce_map_from(ZZ).section() * Fp_FpT_coerce(self._codomain).section() 1447 1448 # cdef class int_FpT_coerce(Morphism): 1449 # """ 1450 # This class represents the coercion map from int to GF(p)(t) 1451 1452 # EXAMPLES:: 1453 1454 # sage: R.<t> = GF(17)[] 1455 # sage: K = R.fraction_field() 1456 # sage: f = K.coerce_map_from(int); f 1457 # Ring Coercion morphism: 1458 # From: Integer Ring 1459 # To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 17 1460 # sage: type(f) 1461 # <type 'sage.rings.fraction_field_FpT.ZZ_FpT_coerce'> 1462 # """ 1463 # def __init__(self, R): 1464 # import sage.categories.homset 1465 # from sage.structure.parent import Set_PythonType 1466 # Morphism.__init__(self, sage.categories.homset.Hom(Set_PythonType(int), R)) 1467 # self.p = R.base_ring().characteristic() 1468 1469 # cpdef Element _call_(self, a): 1470 # cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement) 1471 # ans._parent = self._codomain 1472 # ans.p = self.p 1473 # zmod_poly_init(ans._numer, ans.p) 1474 # zmod_poly_init(ans._denom, ans.p) 1475 # cdef long amodp = PyInt_AS_LONG(a) % self.p 1476 # if amodp < 0: 1477 # amodp = self.p - amodp 1478 # zmod_poly_set_coeff_ui(ans._numer, 0, amodp) 1479 # zmod_poly_set_coeff_ui(ans._denom, 0, 1) 1480 # ans.initalized = True 1481 # return ans 1482 1483 # def _repr_type(self): 1484 # return "Native" 557 1485 558 1486 cdef inline bint normalize(zmod_poly_t numer, zmod_poly_t denom, long p): 1487 """ 1488 Puts numer/denom into a normal form: denominator monic and sharing no common factor with the numerator. 1489 1490 The normalized form of 0 is 0/1. 1491 1492 Returns True if numer and denom were changed. 1493 """ 559 1494 cdef long a 1495 cdef bint changed 560 1496 if zmod_poly_degree(numer) == -1: 1497 if zmod_poly_degree(denom) > 0 or zmod_poly_leading(denom) != 1: 1498 changed = True 1499 else: 1500 changed = False 561 1501 zmod_poly_truncate(denom, 0) 562 1502 zmod_poly_set_coeff_ui(denom, 0, 1) 1503 return changed 563 1504 elif zmod_poly_degree(numer) == 0 or zmod_poly_degree(denom) == 0: 564 1505 if zmod_poly_leading(denom) != 1: 565 1506 a = mod_inverse_int(zmod_poly_leading(denom), p) … … 568 1509 return True 569 1510 return False 570 1511 cdef zmod_poly_t g 571 c def bint changed = False1512 changed = False 572 1513 try: 573 1514 zmod_poly_init_precomp(g, p, numer.p_inv) 574 1515 zmod_poly_gcd(g, numer, denom) … … 587 1528 zmod_poly_clear(g) 588 1529 589 1530 cdef inline unsigned long zmod_poly_leading(zmod_poly_t poly): 1531 """ 1532 Returns the leading coefficient of ``poly``. 1533 """ 590 1534 return zmod_poly_get_coeff_ui(poly, zmod_poly_degree(poly)) 591 1535 592 1536 cdef inline void zmod_poly_inc(zmod_poly_t poly, bint monic): 1537 """ 1538 Sets poly to the "next" polynomial: this is just counting in base p. 1539 1540 If monic is True then will only iterate through monic polynomials. 1541 """ 593 1542 cdef long n 594 1543 cdef long a 595 1544 cdef long p = poly.p 596 1545 for n from 0 <= n <= zmod_poly_degree(poly) + 1: 597 1546 a = zmod_poly_get_coeff_ui(poly, n) + 1 598 if a == p oly.p:1547 if a == p: 599 1548 zmod_poly_set_coeff_ui(poly, n, 0) 600 1549 else: 601 1550 zmod_poly_set_coeff_ui(poly, n, a) … … 604 1553 zmod_poly_set_coeff_ui(poly, n, 0) 605 1554 zmod_poly_set_coeff_ui(poly, n+1, 1) 606 1555 1556 cdef inline long zmod_poly_cmp(zmod_poly_t a, zmod_poly_t b): 1557 """ 1558 Compares `a` and `b`, returning 0 if they are equal. 1559 1560 - If the degree of `a` is less than that of `b`, returns -1. 1561 1562 - If the degree of `b` is less than that of `a`, returns 1. 1563 1564 - Otherwise, compares `a` and `b` lexicographically, starting at the leading terms. 1565 """ 1566 cdef long ad = zmod_poly_degree(a) 1567 cdef long bd = zmod_poly_degree(b) 1568 if ad < bd: 1569 return -1 1570 elif ad > bd: 1571 return 1 1572 cdef long d = zmod_poly_degree(a) 1573 while d >= 0: 1574 ad = zmod_poly_get_coeff_ui(a, d) 1575 bd = zmod_poly_get_coeff_ui(b, d) 1576 if ad < bd: 1577 return -1 1578 elif ad > bd: 1579 return 1 1580 d -= 1 1581 return 0 1582 607 1583 cdef void zmod_poly_pow(zmod_poly_t res, zmod_poly_t poly, unsigned long e): 1584 """ 1585 Raises poly to the `e`th power and stores the result in ``res``. 1586 """ 608 1587 if zmod_poly_degree(poly) < 2: 609 1588 if zmod_poly_degree(poly) == -1: 610 1589 zmod_poly_zero(res) … … 650 1629 651 1630 652 1631 cdef long sqrt_mod_int(long a, long p) except -1: 1632 """ 1633 Returns the square root of a modulo p, as a long. 1634 """ 653 1635 return GF(p)(a).sqrt() 654 1636 655 1637 cdef bint zmod_poly_sqrt_check(zmod_poly_t poly):
