Skip to content

Commit c228541

Browse files
committed
Documentation and Iteration instead of Random
Fixed Latex documentation and error message capitalization. Instead of picking randomly for a quadratic non residue we now iterate through the field until we find one, making sqrt and _tonelli deterministic, _cipolla is still random pick.
1 parent 345f8f4 commit c228541

File tree

1 file changed

+37
-29
lines changed

1 file changed

+37
-29
lines changed

src/sage/categories/finite_fields.py

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,9 @@ def quadratic_non_residue(self):
251251
r"""
252252
Returns a random non square element of the finite field
253253
254-
OUTPUTS:
255-
- a non-square element of the finite field; raises an error if
256-
the finite field is of even order
254+
OUTPUT:
255+
A non-square element of the finite field; raises an error if
256+
the finite field is of even order.
257257
258258
EXAMPLES::
259259
@@ -266,27 +266,25 @@ def quadratic_non_residue(self):
266266
sage: k.quadratic_non_residue()
267267
Traceback (most recent call last):
268268
...
269-
ValueError: There are no non-squares in finite fields of even order
269+
ValueError: there are no non-squares in finite fields of even order
270270
"""
271271
# if the order is an even power of two
272272
# then every element is a square
273273
if self.characteristic() == 2:
274-
raise ValueError("There are no non-squares in finite fields of even order")
274+
raise ValueError("there are no non-squares in finite fields of even order")
275275
# uniformly randomly select elements for a non-square
276276
# with probability 1/2 for a non-square
277-
element = self.random_element()
278-
while element.is_square():
279-
element = self.random_element()
280-
return element
277+
for element in self:
278+
if not element.is_square():
279+
return element
281280

282281
class ElementMethods:
283282
def is_square(self) -> bool:
284283
r"""
285284
Tests if the element is a square or has
286-
a square root element
285+
a square root element.
287286
288-
OUTPUT:
289-
- ``True`` if the element is a square ``False`` if not
287+
OUTPUT: ``True`` if the element is a square ``False`` if not
290288
291289
EXAMPLES::
292290
@@ -312,11 +310,10 @@ def is_square(self) -> bool:
312310
def _tonelli(self):
313311
r"""
314312
Returns a square root of the element if it exists
315-
using Tonelli's algorithm
316-
317-
OUTPUT:
313+
using Tonelli's algorithm, only works for finite fields
314+
of odd characteristic.
318315
319-
- A square root of the element; raises an error
316+
OUTPUT: A square root of the element; raises an error
320317
if the element is not a square
321318
322319
EXAMPLES::
@@ -329,11 +326,11 @@ def _tonelli(self):
329326
sage: k.quadratic_non_residue()._tonelli()
330327
Traceback (most recent call last):
331328
...
332-
ValueError: Element is not a square
329+
ValueError: element is not a square
333330
"""
334331
q = self.parent().cardinality()
335332
if not self.is_square():
336-
raise ValueError("Element is not a square")
333+
raise ValueError("element is not a square")
337334
g = self.parent().quadratic_non_residue()
338335
even_exp, odd_order = (q - ZZ.one()).val_unit(2)
339336
e = 0
@@ -351,11 +348,10 @@ def _cipolla(self):
351348
r"""
352349
Returns a square root of the element if it exists
353350
using Cipolla's algorithm, more suited if order - 1
354-
is highly divisible by 2
355-
356-
OUTPUT:
351+
is highly divisible by 2. Only works for finite fields
352+
of odd characteristic.
357353
358-
- A square root of the element; raises an error
354+
OUTPUT: A square root of the element; raises an error
359355
if the element is not a square
360356
361357
EXAMPLES::
@@ -368,12 +364,12 @@ def _cipolla(self):
368364
sage: k.quadratic_non_residue()._cipolla()
369365
Traceback (most recent call last):
370366
...
371-
ValueError: Element is not a square
367+
ValueError: element is not a square
372368
"""
373369
parent = self.parent()
374370
q = parent.cardinality()
375371
if not self.is_square():
376-
raise ValueError("Element is not a square")
372+
raise ValueError("element is not a square")
377373
t = parent.random_element()
378374
root = t**2 - 4 * self
379375
while root.is_square():
@@ -387,7 +383,7 @@ def _cipolla(self):
387383

388384
def sqrt(self, all: bool = False, algorithm: str = 'tonelli'):
389385
r"""
390-
Returns the square root of the element if it exists
386+
Returns the square root of the element if it exists.
391387
392388
INPUT:
393389
@@ -430,18 +426,30 @@ def sqrt(self, all: bool = False, algorithm: str = 'tonelli'):
430426
sage: k.quadratic_non_residue().sqrt()
431427
Traceback (most recent call last):
432428
...
433-
ValueError: Element is not a square
429+
ValueError: element is not a square
434430
sage: k.quadratic_non_residue().sqrt(all=True)
435431
()
436432
433+
Here is an example where changing the algorithm results
434+
in a faster square root::
435+
436+
sage: p = 141 * 2^141 + 1
437+
sage: S.<x> = GF(p)[]
438+
sage: f = S.irreducible_element(2)
439+
sage: k.<y> = S.quotient_ring(f)
440+
sage: k in Fields()
441+
True
442+
sage: k(2).sqrt(algorithm="cipolla")^2 == k(2)
443+
True
444+
437445
ALGORITHM:
438446
439447
The algorithms used come from chapter 7 of [BS1996]_.
440448
Let `q = p^n` be the order of the finite field, let `a` be the finite field element
441449
that we wish to find the square root of.
442450
443-
- If `p = 2` then `a` is always a square, and the square root of `\sqrt{a} = a^{(q / 2)}`.
444-
- If `q \equiv 3 \pmod{4}` then if `a` is a square `\sqrt{a} = {a^((q+1) / 4)}`
451+
- If `p = 2` then `a` is always a square, and the square root of `\sqrt{a} = a^{q / 2}`.
452+
- If `q \equiv 3 \pmod{4}` then if `a` is a square `\sqrt{a} = a^{\frac{q+1}{4}}`
445453
- For all other cases we use the algorithm given by the ``algorithm`` parameter.
446454
"""
447455
cardinality = self.parent().order()
@@ -457,7 +465,7 @@ def sqrt(self, all: bool = False, algorithm: str = 'tonelli'):
457465
if all:
458466
return ()
459467
else:
460-
raise ValueError("Element is not a square")
468+
raise ValueError("element is not a square")
461469
if cardinality % 4 == 3:
462470
square_root = self**((cardinality+1)//4)
463471
elif algorithm == 'tonelli':

0 commit comments

Comments
 (0)