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