Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/rings/fraction_field_FpT.pyx
8817 views
1
2
3
import sys
4
5
include "sage/ext/cdefs.pxi"
6
include "sage/ext/gmp.pxi"
7
include "sage/ext/interrupt.pxi"
8
include "sage/ext/stdsage.pxi"
9
10
from sage.rings.all import GF
11
from sage.libs.flint.nmod_poly cimport *
12
from sage.libs.flint.ulong_extras cimport n_jacobi
13
from sage.structure.element cimport Element, ModuleElement, RingElement
14
from sage.rings.integer_ring import ZZ
15
from sage.rings.fraction_field import FractionField_generic, FractionField_1poly_field
16
from sage.rings.finite_rings.integer_mod cimport IntegerMod_int
17
from sage.rings.integer cimport Integer
18
from sage.rings.polynomial.polynomial_zmod_flint cimport Polynomial_zmod_flint, get_cparent
19
import sage.algebras.algebra
20
21
from sage.rings.finite_rings.integer_mod cimport jacobi_int, mod_inverse_int, mod_pow_int
22
23
class FpT(FractionField_1poly_field):
24
"""
25
This class represents the fraction field GF(p)(T) for `2 < p < 2^16`.
26
27
EXAMPLES::
28
29
sage: R.<T> = GF(71)[]
30
sage: K = FractionField(R); K
31
Fraction Field of Univariate Polynomial Ring in T over Finite Field of size 71
32
sage: 1-1/T
33
(T + 70)/T
34
sage: parent(1-1/T) is K
35
True
36
"""
37
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
38
"""
39
INPUT:
40
41
- ``R`` -- A polynomial ring over a finite field of prime order `p` with `2 < p < 2^16`
42
43
EXAMPLES::
44
45
sage: R.<x> = GF(31)[]
46
sage: K = R.fraction_field(); K
47
Fraction Field of Univariate Polynomial Ring in x over Finite Field of size 31
48
"""
49
cdef long p = R.base_ring().characteristic()
50
assert 2 < p < 2**16
51
self.p = p
52
self.poly_ring = R
53
FractionField_1poly_field.__init__(self, R, element_class = FpTElement)
54
self._populate_coercion_lists_(coerce_list=[Polyring_FpT_coerce(self), Fp_FpT_coerce(self), ZZ_FpT_coerce(self)])
55
56
def __iter__(self):
57
"""
58
Returns an iterator over this fraction field.
59
60
EXAMPLES::
61
62
sage: R.<t> = GF(3)[]; K = R.fraction_field()
63
sage: iter(K)
64
<sage.rings.fraction_field_FpT.FpT_iter object at ...>
65
"""
66
return self.iter()
67
68
def iter(self, bound=None, start=None):
69
"""
70
EXAMPLES::
71
72
sage: from sage.rings.fraction_field_FpT import *
73
sage: R.<t> = FpT(GF(5)['t'])
74
sage: list(R.iter(2))[350:355]
75
[(t^2 + t + 1)/(t + 2),
76
(t^2 + t + 2)/(t + 2),
77
(t^2 + t + 4)/(t + 2),
78
(t^2 + 2*t + 1)/(t + 2),
79
(t^2 + 2*t + 2)/(t + 2)]
80
"""
81
return FpT_iter(self, bound, start)
82
83
cdef class FpTElement(RingElement):
84
"""
85
An element of an FpT fraction field.
86
"""
87
88
def __init__(self, parent, numer, denom=1, coerce=True, reduce=True):
89
"""
90
INPUT:
91
92
- parent -- the Fraction field containing this element
93
- numer -- something that can be converted into the polynomial ring, giving the numerator
94
- denom -- something that can be converted into the polynomial ring, giving the numerator (default 1)
95
96
EXAMPLES::
97
98
sage: from sage.rings.fraction_field_FpT import *
99
sage: R.<t> = FpT(GF(5)['t'])
100
sage: R(7)
101
2
102
103
"""
104
RingElement.__init__(self, parent)
105
if coerce:
106
numer = parent.poly_ring(numer)
107
denom = parent.poly_ring(denom)
108
self.p = parent.p
109
nmod_poly_init(self._numer, self.p)
110
nmod_poly_init(self._denom, self.p)
111
self.initalized = True
112
cdef long n
113
for n, a in enumerate(numer):
114
nmod_poly_set_coeff_ui(self._numer, n, a)
115
for n, a in enumerate(denom):
116
nmod_poly_set_coeff_ui(self._denom, n, a)
117
if reduce:
118
normalize(self._numer, self._denom, self.p)
119
120
def __dealloc__(self):
121
"""
122
Deallocation.
123
124
EXAMPLES::
125
126
sage: K = GF(11)['t'].fraction_field()
127
sage: t = K.gen()
128
sage: del t # indirect doctest
129
"""
130
if self.initalized:
131
nmod_poly_clear(self._numer)
132
nmod_poly_clear(self._denom)
133
134
def __reduce__(self):
135
"""
136
For pickling.
137
138
TESTS::
139
140
sage: K = GF(11)['t'].fraction_field()
141
sage: loads(dumps(K.gen()))
142
t
143
sage: loads(dumps(1/K.gen()))
144
1/t
145
"""
146
return (unpickle_FpT_element,
147
(self._parent, self.numer(), self.denom()))
148
149
cdef FpTElement _new_c(self):
150
"""
151
Creates a new FpTElement in the same field, leaving the value to be initialized.
152
"""
153
cdef FpTElement x = <FpTElement>PY_NEW(FpTElement)
154
x._parent = self._parent
155
x.p = self.p
156
nmod_poly_init_preinv(x._numer, x.p, self._numer.mod.ninv)
157
nmod_poly_init_preinv(x._denom, x.p, self._numer.mod.ninv)
158
x.initalized = True
159
return x
160
161
cdef FpTElement _copy_c(self):
162
"""
163
Creates a new FpTElement in the same field, with the same value as self.
164
"""
165
cdef FpTElement x = <FpTElement>PY_NEW(FpTElement)
166
x._parent = self._parent
167
x.p = self.p
168
nmod_poly_init2_preinv(x._numer, x.p, self._numer.mod.ninv, self._numer.length)
169
nmod_poly_init2_preinv(x._denom, x.p, self._denom.mod.ninv, self._denom.length)
170
nmod_poly_set(x._numer, self._numer)
171
nmod_poly_set(x._denom, self._denom)
172
x.initalized = True
173
return x
174
175
def numer(self):
176
"""
177
Returns the numerator of this element, as an element of the polynomial ring.
178
179
EXAMPLES::
180
181
sage: K = GF(11)['t'].fraction_field()
182
sage: t = K.gen(0); a = (t + 1/t)^3 - 1
183
sage: a.numer()
184
t^6 + 3*t^4 + 10*t^3 + 3*t^2 + 1
185
"""
186
return self.numerator()
187
188
cpdef numerator(self):
189
"""
190
Returns the numerator of this element, as an element of the polynomial ring.
191
192
EXAMPLES::
193
194
sage: K = GF(11)['t'].fraction_field()
195
sage: t = K.gen(0); a = (t + 1/t)^3 - 1
196
sage: a.numerator()
197
t^6 + 3*t^4 + 10*t^3 + 3*t^2 + 1
198
"""
199
cdef Polynomial_zmod_flint res = <Polynomial_zmod_flint>PY_NEW(Polynomial_zmod_flint)
200
nmod_poly_init2_preinv(&res.x, self.p, self._numer.mod.ninv, self._numer.length)
201
nmod_poly_set(&res.x, self._numer)
202
res._parent = self._parent.poly_ring
203
res._cparent = get_cparent(self._parent.poly_ring)
204
return res
205
206
def denom(self):
207
"""
208
Returns the denominator of this element, as an element of the polynomial ring.
209
210
EXAMPLES::
211
212
sage: K = GF(11)['t'].fraction_field()
213
sage: t = K.gen(0); a = (t + 1/t)^3 - 1
214
sage: a.denom()
215
t^3
216
"""
217
return self.denominator()
218
219
cpdef denominator(self):
220
"""
221
Returns the denominator of this element, as an element of the polynomial ring.
222
223
EXAMPLES::
224
225
sage: K = GF(11)['t'].fraction_field()
226
sage: t = K.gen(0); a = (t + 1/t)^3 - 1
227
sage: a.denominator()
228
t^3
229
"""
230
cdef Polynomial_zmod_flint res = <Polynomial_zmod_flint>PY_NEW(Polynomial_zmod_flint)
231
nmod_poly_init2_preinv(&res.x, self.p, self._denom.mod.ninv, self._denom.length)
232
nmod_poly_set(&res.x, self._denom)
233
res._parent = self._parent.poly_ring
234
res._cparent = get_cparent(self._parent.poly_ring)
235
return res
236
237
def __call__(self, *args, **kwds):
238
"""
239
EXAMPLES::
240
241
sage: K = Frac(GF(5)['t'])
242
sage: t = K.gen()
243
sage: t(3)
244
3
245
sage: f = t^2/(1-t)
246
sage: f(2)
247
1
248
sage: f(t)
249
4*t^2/(t + 4)
250
sage: f(t^3)
251
4*t^6/(t^3 + 4)
252
sage: f((t+1)/t^3)
253
(t^2 + 2*t + 1)/(t^6 + 4*t^4 + 4*t^3)
254
"""
255
return self.numer()(*args, **kwds) / self.denom()(*args, **kwds)
256
257
def subs(self, *args, **kwds):
258
"""
259
EXAMPLES::
260
261
sage: K = Frac(GF(11)['t'])
262
sage: t = K.gen()
263
sage: f = (t+1)/(t-1)
264
sage: f.subs(t=2)
265
3
266
sage: f.subs(X=2)
267
(t + 1)/(t + 10)
268
"""
269
return self.numer().subs(*args, **kwds) / self.denom().subs(*args, **kwds)
270
271
def valuation(self, v):
272
"""
273
Returns the valuation of self at `v`.
274
275
EXAMPLES::
276
277
sage: R.<t> = GF(5)[]
278
sage: f = (t+1)^2 * (t^2+t+1) / (t-1)^3
279
sage: f.valuation(t+1)
280
2
281
sage: f.valuation(t-1)
282
-3
283
sage: f.valuation(t)
284
0
285
"""
286
return self.numer().valuation(v) - self.denom().valuation(v)
287
288
def factor(self):
289
"""
290
EXAMPLES::
291
292
sage: K = Frac(GF(5)['t'])
293
sage: t = K.gen()
294
sage: f = 2 * (t+1) * (t^2+t+1)^2 / (t-1)
295
sage: factor(f)
296
(2) * (t + 4)^-1 * (t + 1) * (t^2 + t + 1)^2
297
"""
298
return self.numer().factor() / self.denom().factor()
299
300
def _repr_(self):
301
"""
302
Returns a string representation of this element.
303
304
EXAMPLES::
305
306
sage: from sage.rings.fraction_field_FpT import *
307
sage: R.<t> = FpT(GF(17)['t'])
308
sage: -t # indirect doctest
309
16*t
310
sage: 1/t
311
1/t
312
sage: 1/(t+1)
313
1/(t + 1)
314
sage: 1-t/t
315
0
316
sage: (1-t)/t
317
(16*t + 1)/t
318
"""
319
if nmod_poly_degree(self._denom) == 0 and nmod_poly_get_coeff_ui(self._denom, 0) == 1:
320
return repr(self.numer())
321
else:
322
numer_s = repr(self.numer())
323
denom_s = repr(self.denom())
324
if '-' in numer_s or '+' in numer_s:
325
numer_s = "(%s)" % numer_s
326
if '-' in denom_s or '+' in denom_s:
327
denom_s = "(%s)" % denom_s
328
return "%s/%s" % (numer_s, denom_s)
329
330
def _latex_(self):
331
r"""
332
Returns a latex representation of this element.
333
334
EXAMPLES::
335
336
sage: K = GF(7)['t'].fraction_field(); t = K.gen(0)
337
sage: latex(t^2 + 1) # indirect doctest
338
t^{2} + 1
339
sage: latex((t + 1)/(t-1))
340
\frac{t + 1}{t + 6}
341
"""
342
if nmod_poly_degree(self._denom) == 0 and nmod_poly_get_coeff_ui(self._denom, 0) == 1:
343
return self.numer()._latex_()
344
else:
345
return "\\frac{%s}{%s}" % (self.numer()._latex_(), self.denom()._latex_())
346
347
def __richcmp__(left, right, int op):
348
"""
349
EXAMPLES::
350
351
sage: K = Frac(GF(5)['t']); t = K.gen()
352
sage: t == 1
353
False
354
sage: t + 1 < t^2
355
True
356
"""
357
return (<Element>left)._richcmp(right, op)
358
359
cdef int _cmp_c_impl(self, Element other) except -2:
360
"""
361
Compares this with another element. The ordering is arbitrary,
362
but it is an ordering, and it is consistent between runs. It has
363
nothing to do with the algebra structure.
364
365
TESTS::
366
367
sage: from sage.rings.fraction_field_FpT import *
368
sage: R.<t> = FpT(GF(7)['t'])
369
sage: t == t
370
True
371
sage: t == -t
372
False
373
sage: -t == 6*t
374
True
375
sage: 1/t == 1/t
376
True
377
sage: 1/t == 1/(t+1)
378
False
379
sage: 2*t/t == 2
380
True
381
sage: 2*t/2 == t
382
True
383
384
sage: a = (t^3 + 3*t)/(5*t-2); b = (t^2-2)/(t-1)
385
sage: b < a
386
True
387
sage: a < b
388
False
389
sage: 1/a < b
390
True
391
sage: b < 1/a
392
False
393
"""
394
# They are normalized.
395
cdef int j = sage_cmp_nmod_poly_t(self._numer, (<FpTElement>other)._numer)
396
if j: return j
397
return sage_cmp_nmod_poly_t(self._denom, (<FpTElement>other)._denom)
398
399
def __hash__(self):
400
"""
401
Returns a hash value for this element.
402
403
TESTS::
404
405
sage: from sage.rings.fraction_field_FpT import *
406
sage: K.<t> = FpT(GF(7)['t'])
407
sage: hash(K(0))
408
0
409
sage: hash(K(5))
410
5
411
sage: set([1, t, 1/t, t, t, 1/t, 1+1/t, t/t])
412
set([1, 1/t, t, (t + 1)/t])
413
sage: a = (t+1)/(t^2-1); hash(a) == hash((a.numer(),a.denom()))
414
True
415
"""
416
if self.denom() == 1:
417
return hash(self.numer())
418
return hash((self.numer(), self.denom()))
419
420
def __neg__(self):
421
"""
422
Negates this element.
423
424
EXAMPLES::
425
426
sage: K = GF(5)['t'].fraction_field(); t = K.gen(0)
427
sage: a = (t^2 + 2)/(t-1)
428
sage: -a # indirect doctest
429
(4*t^2 + 3)/(t + 4)
430
"""
431
cdef FpTElement x = self._copy_c()
432
nmod_poly_neg(x._numer, x._numer)
433
return x
434
435
def __invert__(self):
436
"""
437
Returns the multiplicative inverse of this element.
438
439
EXAMPLES::
440
441
sage: K = GF(5)['t'].fraction_field(); t = K.gen(0)
442
sage: a = (t^2 + 2)/(t-1)
443
sage: ~a # indirect doctest
444
(t + 4)/(t^2 + 2)
445
"""
446
if nmod_poly_degree(self._numer) == -1:
447
raise ZeroDivisionError
448
cdef FpTElement x = self._copy_c()
449
nmod_poly_swap(x._numer, x._denom)
450
return x
451
452
cpdef ModuleElement _add_(self, ModuleElement _other):
453
"""
454
Returns the sum of this fraction field element and another.
455
456
EXAMPLES::
457
458
sage: from sage.rings.fraction_field_FpT import *
459
sage: R.<t> = FpT(GF(7)['t'])
460
sage: t + t # indirect doctest
461
2*t
462
sage: (t + 3) + (t + 10)
463
2*t + 6
464
sage: sum([t] * 7)
465
0
466
sage: 1/t + t
467
(t^2 + 1)/t
468
sage: 1/t + 1/t^2
469
(t + 1)/t^2
470
"""
471
cdef FpTElement other = <FpTElement>_other
472
cdef FpTElement x = self._new_c()
473
nmod_poly_mul(x._numer, self._numer, other._denom)
474
nmod_poly_mul(x._denom, self._denom, other._numer) # use x._denom as a temp
475
nmod_poly_add(x._numer, x._numer, x._denom)
476
nmod_poly_mul(x._denom, self._denom, other._denom)
477
normalize(x._numer, x._denom, self.p)
478
return x
479
480
cpdef ModuleElement _sub_(self, ModuleElement _other):
481
"""
482
Returns the difference of this fraction field element and another.
483
484
EXAMPLES::
485
486
sage: from sage.rings.fraction_field_FpT import *
487
sage: R.<t> = FpT(GF(7)['t'])
488
sage: t - t # indirect doctest
489
0
490
sage: (t + 3) - (t + 11)
491
6
492
"""
493
cdef FpTElement other = <FpTElement>_other
494
cdef FpTElement x = self._new_c()
495
nmod_poly_mul(x._numer, self._numer, other._denom)
496
nmod_poly_mul(x._denom, self._denom, other._numer) # use x._denom as a temp
497
nmod_poly_sub(x._numer, x._numer, x._denom)
498
nmod_poly_mul(x._denom, self._denom, other._denom)
499
normalize(x._numer, x._denom, self.p)
500
return x
501
502
cpdef RingElement _mul_(self, RingElement _other):
503
"""
504
Returns the product of this fraction field element and another.
505
506
EXAMPLES::
507
508
sage: from sage.rings.fraction_field_FpT import *
509
sage: R.<t> = FpT(GF(7)['t'])
510
sage: t * t # indirect doctest
511
t^2
512
sage: (t + 3) * (t + 10)
513
t^2 + 6*t + 2
514
"""
515
cdef FpTElement other = <FpTElement>_other
516
cdef FpTElement x = self._new_c()
517
nmod_poly_mul(x._numer, self._numer, other._numer)
518
nmod_poly_mul(x._denom, self._denom, other._denom)
519
normalize(x._numer, x._denom, self.p)
520
return x
521
522
cpdef RingElement _div_(self, RingElement _other):
523
"""
524
Returns the quotient of this fraction field element and another.
525
526
EXAMPLES::
527
528
sage: from sage.rings.fraction_field_FpT import *
529
sage: R.<t> = FpT(GF(5)['t'])
530
sage: t / t # indirect doctest
531
1
532
sage: (t + 3) / (t + 11)
533
(t + 3)/(t + 1)
534
sage: (t^2 + 2*t + 1) / (t + 1)
535
t + 1
536
"""
537
cdef FpTElement other = <FpTElement>_other
538
if nmod_poly_degree(other._numer) == -1:
539
raise ZeroDivisionError
540
cdef FpTElement x = self._new_c()
541
nmod_poly_mul(x._numer, self._numer, other._denom)
542
nmod_poly_mul(x._denom, self._denom, other._numer)
543
normalize(x._numer, x._denom, self.p)
544
return x
545
546
cpdef FpTElement next(self):
547
"""
548
This function iterates through all polynomials, returning the "next" polynomial after this one.
549
550
The strategy is as follows:
551
552
- We always leave the denominator monic.
553
554
- We progress through the elements with both numerator and denominator monic, and with the denominator less than the numerator.
555
For each such, we output all the scalar multiples of it, then all of the scalar multiples of its inverse.
556
557
- So if the leading coefficient of the numerator is less than p-1, we scale the numerator to increase it by 1.
558
559
- Otherwise, we consider the multiple with numerator and denominator monic.
560
561
- If the numerator is less than the denominator (lexicographically), we return the inverse of that element.
562
563
- 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.
564
565
EXAMPLES::
566
567
sage: from sage.rings.fraction_field_FpT import *
568
sage: R.<t> = FpT(GF(3)['t'])
569
sage: a = R(0)
570
sage: for _ in range(30):
571
... a = a.next()
572
... print a
573
...
574
1
575
2
576
1/t
577
2/t
578
t
579
2*t
580
1/(t + 1)
581
2/(t + 1)
582
t + 1
583
2*t + 2
584
t/(t + 1)
585
2*t/(t + 1)
586
(t + 1)/t
587
(2*t + 2)/t
588
1/(t + 2)
589
2/(t + 2)
590
t + 2
591
2*t + 1
592
t/(t + 2)
593
2*t/(t + 2)
594
(t + 2)/t
595
(2*t + 1)/t
596
(t + 1)/(t + 2)
597
(2*t + 2)/(t + 2)
598
(t + 2)/(t + 1)
599
(2*t + 1)/(t + 1)
600
1/t^2
601
2/t^2
602
t^2
603
2*t^2
604
"""
605
cdef FpTElement next = self._copy_c()
606
cdef long a, lead
607
cdef nmod_poly_t g
608
if nmod_poly_degree(self._numer) == -1:
609
# self should be normalized, so denom == 1
610
nmod_poly_set_coeff_ui(next._numer, 0, 1)
611
return next
612
lead = nmod_poly_leading(next._numer)
613
if lead < self.p - 1:
614
a = mod_inverse_int(lead, self.p)
615
# no overflow since self.p < 2^16
616
a = a * (lead + 1) % self.p
617
nmod_poly_scalar_mul_nmod(next._numer, next._numer, a)
618
else:
619
a = mod_inverse_int(lead, self.p)
620
nmod_poly_scalar_mul_nmod(next._numer, next._numer, a)
621
# now both next._numer and next._denom are monic. We figure out which is lexicographically bigger:
622
a = nmod_poly_cmp(next._numer, next._denom)
623
if a == 0:
624
# next._numer and next._denom are relatively prime, so they're both 1.
625
nmod_poly_inc(next._denom, True)
626
return next
627
nmod_poly_set(next._denom, next._numer)
628
nmod_poly_set(next._numer, self._denom)
629
if a < 0:
630
# since next._numer is smaller, we flip and return the inverse.
631
return next
632
elif a > 0:
633
# since next._numer is bigger, we're in the flipped phase. We flip back, and increment the numerator (until we reach the denominator).
634
nmod_poly_init(g, self.p)
635
try:
636
while True:
637
nmod_poly_inc(next._numer, True)
638
if nmod_poly_equal(next._numer, next._denom):
639
# Since we've reached the denominator, we reset the numerator to 1 and increment the denominator.
640
nmod_poly_inc(next._denom, True)
641
nmod_poly_zero(next._numer)
642
nmod_poly_set_coeff_ui(next._numer, 0, 1)
643
break
644
else:
645
# otherwise, we keep incrementing until we have a relatively prime numerator.
646
nmod_poly_gcd(g, next._numer, next._denom)
647
if nmod_poly_is_one(g):
648
break
649
finally:
650
nmod_poly_clear(g)
651
return next
652
653
cpdef _sqrt_or_None(self):
654
"""
655
Returns the squre root of self, or None. Differs from sqrt() by not raising an exception.
656
657
TESTS::
658
659
sage: from sage.rings.fraction_field_FpT import *
660
sage: R.<t> = FpT(GF(17)['t'])
661
sage: sqrt(t^2) # indirect doctest
662
t
663
sage: sqrt(1/t^2)
664
1/t
665
sage: sqrt((1+t)^2)
666
t + 1
667
sage: sqrt((1+t)^2 / t^2)
668
(t + 1)/t
669
670
sage: sqrt(4 * (1+t)^2 / t^2)
671
(2*t + 2)/t
672
673
sage: sqrt(R(0))
674
0
675
sage: sqrt(R(-1))
676
4
677
678
sage: sqrt(t^4)
679
t^2
680
sage: sqrt(4*t^4/(1+t)^8)
681
2*t^2/(t^4 + 4*t^3 + 6*t^2 + 4*t + 1)
682
683
sage: R.<t> = FpT(GF(5)['t'])
684
sage: [a for a in R.iter(2) if (a^2).sqrt() not in (a,-a)]
685
[]
686
sage: [a for a in R.iter(2) if a.is_square() and a.sqrt()^2 != a]
687
[]
688
689
"""
690
if nmod_poly_is_zero(self._numer):
691
return self
692
693
if not nmod_poly_sqrt_check(self._numer) or not nmod_poly_sqrt_check(self._denom):
694
return None
695
696
cdef nmod_poly_t numer
697
cdef nmod_poly_t denom
698
cdef long a
699
cdef FpTElement res
700
701
nmod_poly_init(denom, self.p)
702
nmod_poly_init(numer, self.p)
703
704
if nmod_poly_sqrt(numer, self._numer) and nmod_poly_sqrt(denom, self._denom):
705
# Make denominator monic
706
a = nmod_poly_leading(denom)
707
if a != 1:
708
a = mod_inverse_int(a, self.p)
709
nmod_poly_scalar_mul_nmod(numer, numer, a)
710
nmod_poly_scalar_mul_nmod(denom, denom, a)
711
# Choose numerator with smaller leading coefficient
712
a = nmod_poly_leading(numer)
713
if a > self.p - a:
714
nmod_poly_neg(numer, numer)
715
res = self._new_c()
716
nmod_poly_swap(numer, res._numer)
717
nmod_poly_swap(denom, res._denom)
718
return res
719
else:
720
nmod_poly_clear(numer)
721
nmod_poly_clear(denom)
722
return None
723
724
cpdef bint is_square(self):
725
"""
726
Returns True if this element is the square of another element of the fraction field.
727
728
EXAMPLES::
729
730
sage: K = GF(13)['t'].fraction_field(); t = K.gen()
731
sage: t.is_square()
732
False
733
sage: (1/t^2).is_square()
734
True
735
sage: K(0).is_square()
736
True
737
"""
738
return self._sqrt_or_None() is not None
739
740
def sqrt(self, extend=True, all=False):
741
"""
742
Returns the square root of this element.
743
744
INPUT:
745
746
- ``extend`` - bool (default: True); if True, return a
747
square root in an extension ring, if necessary. Otherwise, raise a
748
ValueError if the square is not in the base ring.
749
750
- ``all`` - bool (default: False); if True, return all
751
square roots of self, instead of just one.
752
753
EXAMPLES::
754
755
sage: from sage.rings.fraction_field_FpT import *
756
sage: K = GF(7)['t'].fraction_field(); t = K.gen(0)
757
sage: p = (t + 2)^2/(3*t^3 + 1)^4
758
sage: p.sqrt()
759
(3*t + 6)/(t^6 + 3*t^3 + 4)
760
sage: p.sqrt()^2 == p
761
True
762
763
"""
764
s = self._sqrt_or_None()
765
if s is None:
766
if extend:
767
raise NotImplementedError, "function fields not yet implemented"
768
else:
769
raise ValueError, "not a perfect square"
770
else:
771
if all:
772
if not s:
773
return [s]
774
else:
775
return [s, -s]
776
else:
777
return s
778
779
def __pow__(FpTElement self, Py_ssize_t e, dummy):
780
"""
781
Returns the ``e``th power of this element.
782
783
EXAMPLES::
784
785
sage: from sage.rings.fraction_field_FpT import *
786
sage: R.<t> = FpT(GF(7)['t'])
787
sage: t^5
788
t^5
789
sage: t^-5
790
1/t^5
791
792
sage: a = (t+1)/(t-1); a
793
(t + 1)/(t + 6)
794
sage: a^5
795
(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)
796
sage: a^7
797
(t^7 + 1)/(t^7 + 6)
798
sage: a^14
799
(t^14 + 2*t^7 + 1)/(t^14 + 5*t^7 + 1)
800
801
sage: (a^2)^2 == a^4
802
True
803
sage: a^3 * a^2 == a^5
804
True
805
sage: a^47 * a^92 == a^(47+92)
806
True
807
"""
808
cdef long a
809
assert dummy is None
810
cdef FpTElement x = self._new_c()
811
if e >= 0:
812
nmod_poly_pow(x._numer, self._numer, e)
813
nmod_poly_pow(x._denom, self._denom, e)
814
else:
815
nmod_poly_pow(x._denom, self._numer, -e)
816
nmod_poly_pow(x._numer, self._denom, -e)
817
if nmod_poly_leading(x._denom) != 1:
818
a = mod_inverse_int(nmod_poly_leading(x._denom), self.p)
819
nmod_poly_scalar_mul_nmod(x._numer, x._numer, a)
820
nmod_poly_scalar_mul_nmod(x._denom, x._denom, a)
821
return x
822
823
824
cdef class FpT_iter:
825
"""
826
Returns a class that iterates over all elements of an FpT.
827
828
EXAMPLES::
829
830
sage: K = GF(3)['t'].fraction_field()
831
sage: I = K.iter(1)
832
sage: list(I)
833
[0,
834
1,
835
2,
836
t,
837
t + 1,
838
t + 2,
839
2*t,
840
2*t + 1,
841
2*t + 2,
842
1/t,
843
2/t,
844
(t + 1)/t,
845
(t + 2)/t,
846
(2*t + 1)/t,
847
(2*t + 2)/t,
848
1/(t + 1),
849
2/(t + 1),
850
t/(t + 1),
851
(t + 2)/(t + 1),
852
2*t/(t + 1),
853
(2*t + 1)/(t + 1),
854
1/(t + 2),
855
2/(t + 2),
856
t/(t + 2),
857
(t + 1)/(t + 2),
858
2*t/(t + 2),
859
(2*t + 2)/(t + 2)]
860
"""
861
def __init__(self, parent, degree=None, FpTElement start=None):
862
"""
863
INPUTS:
864
865
- parent -- The FpT that we're iterating over.
866
867
- degree -- The maximum degree of the numerator and denominator of the elements over which we iterate.
868
869
- start -- (default 0) The element on which to start.
870
871
EXAMPLES::
872
873
sage: K = GF(11)['t'].fraction_field()
874
sage: I = K.iter(2) # indirect doctest
875
sage: for a in I:
876
... if a.denom()[0] == 3 and a.numer()[1] == 2:
877
... print a; break
878
2*t/(t + 3)
879
"""
880
#if degree is None:
881
# raise NotImplementedError
882
self.parent = parent
883
self.cur = start
884
self.degree = -2 if degree is None else degree
885
886
def __cinit__(self, parent, *args, **kwds):
887
"""
888
Memory allocation for the temp variable storing the gcd of the numerator and denominator.
889
890
TESTS::
891
892
sage: from sage.rings.fraction_field_FpT import FpT_iter
893
sage: K = GF(7)['t'].fraction_field()
894
sage: I = FpT_iter(K, 3) # indirect doctest
895
sage: I
896
<sage.rings.fraction_field_FpT.FpT_iter object at ...>
897
"""
898
nmod_poly_init(self.g, parent.characteristic())
899
900
def __dealloc__(self):
901
"""
902
Deallocating of self.g.
903
904
TESTS::
905
906
sage: from sage.rings.fraction_field_FpT import FpT_iter
907
sage: K = GF(7)['t'].fraction_field()
908
sage: I = FpT_iter(K, 3)
909
sage: del I # indirect doctest
910
"""
911
nmod_poly_clear(self.g)
912
913
def __iter__(self):
914
"""
915
Returns this iterator.
916
917
TESTS::
918
919
sage: from sage.rings.fraction_field_FpT import FpT_iter
920
sage: K = GF(3)['t'].fraction_field()
921
sage: I = FpT_iter(K, 3)
922
sage: for a in I: # indirect doctest
923
... if a.numer()[1] == 1 and a.denom()[1] == 2 and a.is_square():
924
... print a; break
925
(t^2 + t + 1)/(t^2 + 2*t + 1)
926
"""
927
return self
928
929
def __next__(self):
930
"""
931
Returns the next element to iterate over.
932
933
This is achieved by iterating over monic denominators, and for each denominator,
934
iterating over all numerators relatively prime to the given denominator.
935
936
EXAMPLES::
937
938
sage: from sage.rings.fraction_field_FpT import *
939
sage: K.<t> = FpT(GF(3)['t'])
940
sage: list(K.iter(1)) # indirect doctest
941
[0,
942
1,
943
2,
944
t,
945
t + 1,
946
t + 2,
947
2*t,
948
2*t + 1,
949
2*t + 2,
950
1/t,
951
2/t,
952
(t + 1)/t,
953
(t + 2)/t,
954
(2*t + 1)/t,
955
(2*t + 2)/t,
956
1/(t + 1),
957
2/(t + 1),
958
t/(t + 1),
959
(t + 2)/(t + 1),
960
2*t/(t + 1),
961
(2*t + 1)/(t + 1),
962
1/(t + 2),
963
2/(t + 2),
964
t/(t + 2),
965
(t + 1)/(t + 2),
966
2*t/(t + 2),
967
(2*t + 2)/(t + 2)]
968
969
sage: len(list(K.iter(3)))
970
2187
971
972
sage: K.<t> = FpT(GF(5)['t'])
973
sage: L = list(K.iter(3)); len(L)
974
78125
975
sage: L[:10]
976
[0, 1, 2, 3, 4, t, t + 1, t + 2, t + 3, t + 4]
977
sage: L[2000]
978
(3*t^3 + 3*t^2 + 3*t + 4)/(t + 2)
979
sage: L[-1]
980
(4*t^3 + 4*t^2 + 4*t + 4)/(t^3 + 4*t^2 + 4*t + 4)
981
"""
982
cdef FpTElement next
983
if self.cur is None:
984
self.cur = self.parent(0)
985
elif self.degree == -2:
986
self.cur = self.cur.next()
987
else:
988
next = self.cur._copy_c()
989
sig_on()
990
while True:
991
nmod_poly_inc(next._numer, False)
992
if nmod_poly_degree(next._numer) > self.degree:
993
nmod_poly_inc(next._denom, True)
994
if nmod_poly_degree(next._denom) > self.degree:
995
sig_off()
996
raise StopIteration
997
nmod_poly_zero(next._numer)
998
nmod_poly_set_coeff_ui(next._numer, 0, 1)
999
nmod_poly_gcd(self.g, next._numer, next._denom)
1000
if nmod_poly_is_one(self.g):
1001
break
1002
sig_off()
1003
self.cur = next
1004
# self.cur = self.cur.next()
1005
# if nmod_poly_degree(self.cur._numer) > self.degree:
1006
# raise StopIteration
1007
return self.cur
1008
1009
cdef class Polyring_FpT_coerce(RingHomomorphism_coercion):
1010
"""
1011
This class represents the coercion map from GF(p)[t] to GF(p)(t)
1012
1013
EXAMPLES::
1014
1015
sage: R.<t> = GF(5)[]
1016
sage: K = R.fraction_field()
1017
sage: f = K.coerce_map_from(R); f
1018
Ring Coercion morphism:
1019
From: Univariate Polynomial Ring in t over Finite Field of size 5
1020
To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
1021
sage: type(f)
1022
<type 'sage.rings.fraction_field_FpT.Polyring_FpT_coerce'>
1023
"""
1024
cdef long p
1025
1026
def __init__(self, R):
1027
"""
1028
INPUTS:
1029
1030
- R -- An FpT
1031
1032
EXAMPLES::
1033
1034
sage: R.<t> = GF(next_prime(2000))[]
1035
sage: K = R.fraction_field() # indirect doctest
1036
"""
1037
RingHomomorphism_coercion.__init__(self, R.ring_of_integers().Hom(R), check=False)
1038
self.p = R.base_ring().characteristic()
1039
1040
cpdef Element _call_(self, _x):
1041
"""
1042
Applies the coercion.
1043
1044
EXAMPLES::
1045
1046
sage: R.<t> = GF(5)[]
1047
sage: K = R.fraction_field()
1048
sage: f = K.coerce_map_from(R)
1049
sage: f(t^2 + 1) # indirect doctest
1050
t^2 + 1
1051
"""
1052
cdef Polynomial_zmod_flint x = <Polynomial_zmod_flint?> _x
1053
cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)
1054
ans._parent = self._codomain
1055
ans.p = self.p
1056
nmod_poly_init(ans._numer, ans.p)
1057
nmod_poly_init(ans._denom, ans.p)
1058
nmod_poly_set(ans._numer, &x.x)
1059
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
1060
ans.initalized = True
1061
return ans
1062
1063
cpdef Element _call_with_args(self, _x, args=(), kwds={}):
1064
"""
1065
This function allows the map to take multiple arguments, usually used to specify both numerator and denominator.
1066
1067
If ``reduce`` is specified as False, then the result won't be normalized.
1068
1069
EXAMPLES::
1070
1071
sage: R.<t> = GF(5)[]
1072
sage: K = R.fraction_field()
1073
sage: f = K.coerce_map_from(R)
1074
sage: f(2*t + 2, t + 3) # indirect doctest
1075
(2*t + 2)/(t + 3)
1076
sage: f(2*t + 2, 2)
1077
t + 1
1078
sage: f(2*t + 2, 2, reduce=False)
1079
(2*t + 2)/2
1080
1081
TEST:
1082
1083
Check that :trac:`12217` is fixed::
1084
1085
sage: R.<t> = GF(5)[]
1086
sage: K = R.fraction_field()
1087
sage: f = K.coerce_map_from(R)
1088
sage: f(t, 0)
1089
Traceback (most recent call last):
1090
...
1091
ZeroDivisionError: fraction has denominator 0
1092
1093
"""
1094
cdef Polynomial_zmod_flint x = <Polynomial_zmod_flint?> _x
1095
cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)
1096
ans._parent = self._codomain
1097
ans.p = self.p
1098
nmod_poly_init(ans._numer, ans.p)
1099
nmod_poly_init(ans._denom, ans.p)
1100
cdef long r
1101
nmod_poly_set(ans._numer, &x.x)
1102
if len(args) == 0:
1103
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
1104
elif len(args) == 1:
1105
y = args[0]
1106
if PY_TYPE_CHECK(y, Integer):
1107
r = mpz_fdiv_ui((<Integer>y).value, self.p)
1108
if r == 0:
1109
raise ZeroDivisionError('fraction has denominator 0')
1110
nmod_poly_set_coeff_ui(ans._denom, 0, r)
1111
else:
1112
# could use the coerce keyword being set to False to not check this...
1113
if not (PY_TYPE_CHECK(y, Element) and y.parent() is self._domain):
1114
# We could special case integers and GF(p) elements here.
1115
y = self._domain(y)
1116
if not y:
1117
raise ZeroDivisionError('fraction has denominator 0')
1118
nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))
1119
else:
1120
raise ValueError, "FpT only supports two positional arguments"
1121
if not (kwds.has_key('reduce') and not kwds['reduce']):
1122
normalize(ans._numer, ans._denom, ans.p)
1123
ans.initalized = True
1124
return ans
1125
1126
def section(self):
1127
"""
1128
Returns the section of this inclusion: the partially defined map from ``GF(p)(t)``
1129
back to ``GF(p)[t]``, defined on elements with unit denominator.
1130
1131
EXAMPLES::
1132
1133
sage: R.<t> = GF(5)[]
1134
sage: K = R.fraction_field()
1135
sage: f = K.coerce_map_from(R)
1136
sage: g = f.section(); g
1137
Section map:
1138
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
1139
To: Univariate Polynomial Ring in t over Finite Field of size 5
1140
sage: t = K.gen()
1141
sage: g(t)
1142
t
1143
sage: g(1/t)
1144
Traceback (most recent call last):
1145
...
1146
ValueError: not integral
1147
"""
1148
return FpT_Polyring_section(self)
1149
1150
cdef class FpT_Polyring_section(Section):
1151
"""
1152
This class represents the section from GF(p)(t) back to GF(p)[t]
1153
1154
EXAMPLES::
1155
1156
sage: R.<t> = GF(5)[]
1157
sage: K = R.fraction_field()
1158
sage: f = R.convert_map_from(K); f
1159
Section map:
1160
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
1161
To: Univariate Polynomial Ring in t over Finite Field of size 5
1162
sage: type(f)
1163
<type 'sage.rings.fraction_field_FpT.FpT_Polyring_section'>
1164
"""
1165
cdef long p
1166
1167
def __init__(self, Polyring_FpT_coerce f):
1168
"""
1169
INPUTS:
1170
1171
- f -- A Polyring_FpT_coerce homomorphism
1172
1173
EXAMPLES::
1174
1175
sage: R.<t> = GF(next_prime(2000))[]
1176
sage: K = R.fraction_field()
1177
sage: R(K.gen(0)) # indirect doctest
1178
t
1179
"""
1180
self.p = f.p
1181
Section.__init__(self, f)
1182
1183
cpdef Element _call_(self, _x):
1184
"""
1185
Applies the section.
1186
1187
EXAMPLES::
1188
1189
sage: R.<t> = GF(7)[]
1190
sage: K = R.fraction_field()
1191
sage: f = K.coerce_map_from(R)
1192
sage: g = f.section(); g
1193
Section map:
1194
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7
1195
To: Univariate Polynomial Ring in t over Finite Field of size 7
1196
sage: t = K.gen()
1197
sage: g(t^2) # indirect doctest
1198
t^2
1199
sage: g(1/t)
1200
Traceback (most recent call last):
1201
...
1202
ValueError: not integral
1203
"""
1204
cdef FpTElement x = <FpTElement?>_x
1205
cdef Polynomial_zmod_flint ans
1206
if nmod_poly_degree(x._denom) != 0:
1207
normalize(x._numer, x._denom, self.p)
1208
if nmod_poly_degree(x._denom) != 0:
1209
raise ValueError, "not integral"
1210
ans = PY_NEW(Polynomial_zmod_flint)
1211
if nmod_poly_get_coeff_ui(x._denom, 0) != 1:
1212
normalize(x._numer, x._denom, self.p)
1213
nmod_poly_init(&ans.x, self.p)
1214
nmod_poly_set(&ans.x, x._numer)
1215
ans._parent = self._codomain
1216
ans._cparent = get_cparent(self._codomain)
1217
return ans
1218
1219
cdef class Fp_FpT_coerce(RingHomomorphism_coercion):
1220
"""
1221
This class represents the coercion map from GF(p) to GF(p)(t)
1222
1223
EXAMPLES::
1224
1225
sage: R.<t> = GF(5)[]
1226
sage: K = R.fraction_field()
1227
sage: f = K.coerce_map_from(GF(5)); f
1228
Ring Coercion morphism:
1229
From: Finite Field of size 5
1230
To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
1231
sage: type(f)
1232
<type 'sage.rings.fraction_field_FpT.Fp_FpT_coerce'>
1233
"""
1234
cdef long p
1235
1236
def __init__(self, R):
1237
"""
1238
INPUTS:
1239
1240
- R -- An FpT
1241
1242
EXAMPLES::
1243
1244
sage: R.<t> = GF(next_prime(3000))[]
1245
sage: K = R.fraction_field() # indirect doctest
1246
"""
1247
RingHomomorphism_coercion.__init__(self, R.base_ring().Hom(R), check=False)
1248
self.p = R.base_ring().characteristic()
1249
1250
cpdef Element _call_(self, _x):
1251
"""
1252
Applies the coercion.
1253
1254
EXAMPLES::
1255
1256
sage: R.<t> = GF(5)[]
1257
sage: K = R.fraction_field()
1258
sage: f = K.coerce_map_from(GF(5))
1259
sage: f(GF(5)(3)) # indirect doctest
1260
3
1261
"""
1262
cdef IntegerMod_int x = <IntegerMod_int?> _x
1263
cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)
1264
ans._parent = self._codomain
1265
ans.p = self.p
1266
nmod_poly_init(ans._numer, ans.p)
1267
nmod_poly_init(ans._denom, ans.p)
1268
nmod_poly_set_coeff_ui(ans._numer, 0, x.ivalue)
1269
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
1270
ans.initalized = True
1271
return ans
1272
1273
cpdef Element _call_with_args(self, _x, args=(), kwds={}):
1274
"""
1275
This function allows the map to take multiple arguments, usually used to specify both numerator and denominator.
1276
1277
If ``reduce`` is specified as False, then the result won't be normalized.
1278
1279
EXAMPLES::
1280
1281
sage: R.<t> = GF(5)[]
1282
sage: K = R.fraction_field()
1283
sage: f = K.coerce_map_from(GF(5))
1284
sage: f(1, t + 3) # indirect doctest
1285
1/(t + 3)
1286
sage: f(2, 2*t)
1287
1/t
1288
sage: f(2, 2*t, reduce=False)
1289
2/2*t
1290
"""
1291
cdef IntegerMod_int x = <IntegerMod_int?> _x
1292
cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)
1293
ans._parent = self._codomain
1294
ans.p = self.p
1295
nmod_poly_init(ans._numer, ans.p)
1296
nmod_poly_init(ans._denom, ans.p)
1297
cdef long r
1298
nmod_poly_set_coeff_ui(ans._numer, 0, x.ivalue)
1299
if len(args) == 0:
1300
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
1301
if len(args) == 1:
1302
y = args[0]
1303
if PY_TYPE_CHECK(y, Integer):
1304
r = mpz_fdiv_ui((<Integer>y).value, self.p)
1305
if r == 0:
1306
raise ZeroDivisionError
1307
nmod_poly_set_coeff_ui(ans._denom, 0, r)
1308
else:
1309
R = self._codomain.ring_of_integers()
1310
# could use the coerce keyword being set to False to not check this...
1311
if not (PY_TYPE_CHECK(y, Element) and y.parent() is R):
1312
# We could special case integers and GF(p) elements here.
1313
y = R(y)
1314
nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))
1315
else:
1316
raise ValueError, "FpT only supports two positional arguments"
1317
if not (kwds.has_key('reduce') and not kwds['reduce']):
1318
normalize(ans._numer, ans._denom, ans.p)
1319
ans.initalized = True
1320
return ans
1321
1322
def section(self):
1323
"""
1324
Returns the section of this inclusion: the partially defined map from ``GF(p)(t)``
1325
back to ``GF(p)``, defined on constant elements.
1326
1327
EXAMPLES::
1328
1329
sage: R.<t> = GF(5)[]
1330
sage: K = R.fraction_field()
1331
sage: f = K.coerce_map_from(GF(5))
1332
sage: g = f.section(); g
1333
Section map:
1334
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
1335
To: Finite Field of size 5
1336
sage: t = K.gen()
1337
sage: g(f(1,3,reduce=False))
1338
2
1339
sage: g(t)
1340
Traceback (most recent call last):
1341
...
1342
ValueError: not constant
1343
sage: g(1/t)
1344
Traceback (most recent call last):
1345
...
1346
ValueError: not integral
1347
"""
1348
return FpT_Fp_section(self)
1349
1350
cdef class FpT_Fp_section(Section):
1351
"""
1352
This class represents the section from GF(p)(t) back to GF(p)[t]
1353
1354
EXAMPLES::
1355
1356
sage: R.<t> = GF(5)[]
1357
sage: K = R.fraction_field()
1358
sage: f = GF(5).convert_map_from(K); f
1359
Section map:
1360
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
1361
To: Finite Field of size 5
1362
sage: type(f)
1363
<type 'sage.rings.fraction_field_FpT.FpT_Fp_section'>
1364
"""
1365
cdef long p
1366
1367
def __init__(self, Fp_FpT_coerce f):
1368
"""
1369
INPUTS:
1370
1371
- f -- An Fp_FpT_coerce homomorphism
1372
1373
EXAMPLES::
1374
1375
sage: R.<t> = GF(next_prime(2000))[]
1376
sage: K = R.fraction_field()
1377
sage: GF(next_prime(2000))(K(127)) # indirect doctest
1378
127
1379
"""
1380
self.p = f.p
1381
Section.__init__(self, f)
1382
1383
cpdef Element _call_(self, _x):
1384
"""
1385
Applies the section.
1386
1387
EXAMPLES::
1388
1389
sage: R.<t> = GF(7)[]
1390
sage: K = R.fraction_field()
1391
sage: f = K.coerce_map_from(GF(7))
1392
sage: g = f.section(); g
1393
Section map:
1394
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7
1395
To: Finite Field of size 7
1396
sage: t = K.gen()
1397
sage: g(t^2) # indirect doctest
1398
Traceback (most recent call last):
1399
...
1400
ValueError: not constant
1401
sage: g(1/t)
1402
Traceback (most recent call last):
1403
...
1404
ValueError: not integral
1405
sage: g(K(4))
1406
4
1407
sage: g(K(0))
1408
0
1409
"""
1410
cdef FpTElement x = <FpTElement?>_x
1411
cdef IntegerMod_int ans
1412
if nmod_poly_degree(x._denom) != 0 or nmod_poly_degree(x._numer) > 0:
1413
normalize(x._numer, x._denom, self.p)
1414
if nmod_poly_degree(x._denom) != 0:
1415
raise ValueError, "not integral"
1416
if nmod_poly_degree(x._numer) > 0:
1417
raise ValueError, "not constant"
1418
ans = PY_NEW(IntegerMod_int)
1419
ans.__modulus = self._codomain._pyx_order
1420
if nmod_poly_get_coeff_ui(x._denom, 0) != 1:
1421
normalize(x._numer, x._denom, self.p)
1422
ans.ivalue = nmod_poly_get_coeff_ui(x._numer, 0)
1423
ans._parent = self._codomain
1424
return ans
1425
1426
cdef class ZZ_FpT_coerce(RingHomomorphism_coercion):
1427
"""
1428
This class represents the coercion map from ZZ to GF(p)(t)
1429
1430
EXAMPLES::
1431
1432
sage: R.<t> = GF(17)[]
1433
sage: K = R.fraction_field()
1434
sage: f = K.coerce_map_from(ZZ); f
1435
Ring Coercion morphism:
1436
From: Integer Ring
1437
To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 17
1438
sage: type(f)
1439
<type 'sage.rings.fraction_field_FpT.ZZ_FpT_coerce'>
1440
"""
1441
cdef long p
1442
1443
def __init__(self, R):
1444
"""
1445
INPUTS:
1446
1447
- R -- An FpT
1448
1449
EXAMPLES::
1450
1451
sage: R.<t> = GF(next_prime(3000))[]
1452
sage: K = R.fraction_field() # indirect doctest
1453
"""
1454
RingHomomorphism_coercion.__init__(self, ZZ.Hom(R), check=False)
1455
self.p = R.base_ring().characteristic()
1456
1457
cpdef Element _call_(self, _x):
1458
"""
1459
Applies the coercion.
1460
1461
EXAMPLES::
1462
1463
sage: R.<t> = GF(5)[]
1464
sage: K = R.fraction_field()
1465
sage: f = K.coerce_map_from(ZZ)
1466
sage: f(3) # indirect doctest
1467
3
1468
"""
1469
cdef Integer x = <Integer?> _x
1470
cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)
1471
ans._parent = self._codomain
1472
ans.p = self.p
1473
nmod_poly_init(ans._numer, ans.p)
1474
nmod_poly_init(ans._denom, ans.p)
1475
nmod_poly_set_coeff_ui(ans._numer, 0, mpz_fdiv_ui(x.value, self.p))
1476
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
1477
ans.initalized = True
1478
return ans
1479
1480
cpdef Element _call_with_args(self, _x, args=(), kwds={}):
1481
"""
1482
This function allows the map to take multiple arguments, usually used to specify both numerator and denominator.
1483
1484
If ``reduce`` is specified as False, then the result won't be normalized.
1485
1486
EXAMPLES::
1487
1488
sage: R.<t> = GF(5)[]
1489
sage: K = R.fraction_field()
1490
sage: f = K.coerce_map_from(ZZ)
1491
sage: f(1, t + 3) # indirect doctest
1492
1/(t + 3)
1493
sage: f(1,2)
1494
3
1495
sage: f(2, 2*t)
1496
1/t
1497
sage: f(2, 2*t, reduce=False)
1498
2/2*t
1499
"""
1500
cdef Integer x = <Integer?> _x
1501
cdef FpTElement ans = <FpTElement>PY_NEW(FpTElement)
1502
ans._parent = self._codomain
1503
ans.p = self.p
1504
nmod_poly_init(ans._numer, ans.p)
1505
nmod_poly_init(ans._denom, ans.p)
1506
cdef long r
1507
nmod_poly_set_coeff_ui(ans._numer, 0, mpz_fdiv_ui(x.value, self.p))
1508
if len(args) == 0:
1509
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
1510
if len(args) == 1:
1511
y = args[0]
1512
if PY_TYPE_CHECK(y, Integer):
1513
r = mpz_fdiv_ui((<Integer>y).value, self.p)
1514
if r == 0:
1515
raise ZeroDivisionError
1516
nmod_poly_set_coeff_ui(ans._denom, 0, r)
1517
else:
1518
R = self._codomain.ring_of_integers()
1519
# could use the coerce keyword being set to False to not check this...
1520
if not (PY_TYPE_CHECK(y, Element) and y.parent() is R):
1521
# We could special case integers and GF(p) elements here.
1522
y = R(y)
1523
nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))
1524
else:
1525
raise ValueError, "FpT only supports two positional arguments"
1526
if not (kwds.has_key('reduce') and not kwds['reduce']):
1527
normalize(ans._numer, ans._denom, ans.p)
1528
ans.initalized = True
1529
return ans
1530
1531
def section(self):
1532
"""
1533
Returns the section of this inclusion: the partially defined map from ``GF(p)(t)``
1534
back to ``ZZ``, defined on constant elements.
1535
1536
EXAMPLES::
1537
1538
sage: R.<t> = GF(5)[]
1539
sage: K = R.fraction_field()
1540
sage: f = K.coerce_map_from(ZZ)
1541
sage: g = f.section(); g
1542
Composite map:
1543
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
1544
To: Integer Ring
1545
Defn: Section map:
1546
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
1547
To: Finite Field of size 5
1548
then
1549
Lifting map:
1550
From: Finite Field of size 5
1551
To: Integer Ring
1552
sage: t = K.gen()
1553
sage: g(f(1,3,reduce=False))
1554
2
1555
sage: g(t)
1556
Traceback (most recent call last):
1557
...
1558
ValueError: not constant
1559
sage: g(1/t)
1560
Traceback (most recent call last):
1561
...
1562
ValueError: not integral
1563
"""
1564
return ZZ.convert_map_from(self._codomain.base_ring()) * Fp_FpT_coerce(self._codomain).section()
1565
1566
cdef inline bint normalize(nmod_poly_t numer, nmod_poly_t denom, long p):
1567
"""
1568
Puts numer/denom into a normal form: denominator monic and sharing no common factor with the numerator.
1569
1570
The normalized form of 0 is 0/1.
1571
1572
Returns True if numer and denom were changed.
1573
"""
1574
cdef long a
1575
cdef bint changed
1576
if nmod_poly_degree(numer) == -1:
1577
if nmod_poly_degree(denom) > 0 or nmod_poly_leading(denom) != 1:
1578
changed = True
1579
else:
1580
changed = False
1581
nmod_poly_truncate(denom, 0)
1582
nmod_poly_set_coeff_ui(denom, 0, 1)
1583
return changed
1584
elif nmod_poly_degree(numer) == 0 or nmod_poly_degree(denom) == 0:
1585
if nmod_poly_leading(denom) != 1:
1586
a = mod_inverse_int(nmod_poly_leading(denom), p)
1587
nmod_poly_scalar_mul_nmod(numer, numer, a)
1588
nmod_poly_scalar_mul_nmod(denom, denom, a)
1589
return True
1590
return False
1591
cdef nmod_poly_t g
1592
changed = False
1593
try:
1594
nmod_poly_init_preinv(g, p, numer.mod.ninv)
1595
nmod_poly_gcd(g, numer, denom)
1596
if nmod_poly_degree(g) != 0:
1597
# Divide knowing divisible by? Can we get these quotients as a byproduct of the gcd?
1598
nmod_poly_div(numer, numer, g)
1599
nmod_poly_div(denom, denom, g)
1600
changed = True
1601
if nmod_poly_leading(denom) != 1:
1602
a = mod_inverse_int(nmod_poly_leading(denom), p)
1603
nmod_poly_scalar_mul_nmod(numer, numer, a)
1604
nmod_poly_scalar_mul_nmod(denom, denom, a)
1605
changed = True
1606
return changed
1607
finally:
1608
nmod_poly_clear(g)
1609
1610
cdef inline unsigned long nmod_poly_leading(nmod_poly_t poly):
1611
"""
1612
Returns the leading coefficient of ``poly``.
1613
"""
1614
return nmod_poly_get_coeff_ui(poly, nmod_poly_degree(poly))
1615
1616
cdef inline void nmod_poly_inc(nmod_poly_t poly, bint monic):
1617
"""
1618
Sets poly to the "next" polynomial: this is just counting in base p.
1619
1620
If monic is True then will only iterate through monic polynomials.
1621
"""
1622
cdef long n
1623
cdef long a
1624
cdef long p = poly.mod.n
1625
for n from 0 <= n <= nmod_poly_degree(poly) + 1:
1626
a = nmod_poly_get_coeff_ui(poly, n) + 1
1627
if a == p:
1628
nmod_poly_set_coeff_ui(poly, n, 0)
1629
else:
1630
nmod_poly_set_coeff_ui(poly, n, a)
1631
break
1632
if monic and a == 2 and n == nmod_poly_degree(poly):
1633
nmod_poly_set_coeff_ui(poly, n, 0)
1634
nmod_poly_set_coeff_ui(poly, n+1, 1)
1635
1636
cdef inline long nmod_poly_cmp(nmod_poly_t a, nmod_poly_t b):
1637
"""
1638
Compares `a` and `b`, returning 0 if they are equal.
1639
1640
- If the degree of `a` is less than that of `b`, returns -1.
1641
1642
- If the degree of `b` is less than that of `a`, returns 1.
1643
1644
- Otherwise, compares `a` and `b` lexicographically, starting at the leading terms.
1645
"""
1646
cdef long ad = nmod_poly_degree(a)
1647
cdef long bd = nmod_poly_degree(b)
1648
if ad < bd:
1649
return -1
1650
elif ad > bd:
1651
return 1
1652
cdef long d = nmod_poly_degree(a)
1653
while d >= 0:
1654
ad = nmod_poly_get_coeff_ui(a, d)
1655
bd = nmod_poly_get_coeff_ui(b, d)
1656
if ad < bd:
1657
return -1
1658
elif ad > bd:
1659
return 1
1660
d -= 1
1661
return 0
1662
1663
cdef bint nmod_poly_sqrt_check(nmod_poly_t poly):
1664
"""
1665
Quick check to see if poly could possibly be a square.
1666
"""
1667
# We could use Sage's jacobi_int which is for 32 bits integers rather
1668
# than FLINT's n_jacobi which is for longs as the FpT class is crafted
1669
# for primes 2 < p < 2^16
1670
return (nmod_poly_degree(poly) % 2 == 0
1671
and n_jacobi(nmod_poly_leading(poly), poly.mod.n) == 1
1672
and n_jacobi(nmod_poly_get_coeff_ui(poly, 0), poly.mod.n) != -1)
1673
1674
def unpickle_FpT_element(K, numer, denom):
1675
"""
1676
Used for pickling.
1677
1678
TESTS::
1679
1680
sage: from sage.rings.fraction_field_FpT import unpickle_FpT_element
1681
sage: R.<t> = GF(13)['t']
1682
sage: unpickle_FpT_element(Frac(R), t+1, t)
1683
(t + 1)/t
1684
"""
1685
return FpTElement(K, numer, denom, coerce=False, reduce=False)
1686
1687
1688
# Somehow this isn't in FLINT, evidently. It could be moved
1689
# elsewhere at some point.
1690
cdef int sage_cmp_nmod_poly_t(nmod_poly_t L, nmod_poly_t R):
1691
"""
1692
Compare two nmod_poly_t in a Pythonic way, so this returns -1, 0,
1693
or 1, and is consistent.
1694
"""
1695
cdef int j
1696
cdef Py_ssize_t i
1697
1698
# First compare the degrees
1699
j = nmod_poly_degree(L) - nmod_poly_degree(R)
1700
if j<0: return -1
1701
elif j>0: return 1
1702
1703
# Same degree, so compare coefficients, term by term
1704
for i in range(nmod_poly_degree(L)+1):
1705
j = nmod_poly_get_coeff_ui(L,i) - nmod_poly_get_coeff_ui(R,i)
1706
if j<0: return -1
1707
elif j>0: return 1
1708
1709
# Two polynomials are equal
1710
return 0
1711
1712