Skip to content

Commit

Permalink
remove BinaryQF.random() since its distribution was far from uniform …
Browse files Browse the repository at this point in the history
…on classes
  • Loading branch information
yyyyx4 committed Nov 2, 2023
1 parent 60d683e commit 7c0a6c7
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 57 deletions.
52 changes: 0 additions & 52 deletions src/sage/quadratic_forms/binary_qf.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,58 +222,6 @@ def principal(D):
raise ValueError('discriminant must be congruent to 0 or 1 modulo 4')
return BinaryQF([1, D4, (D4-D)//4])

@staticmethod
def random(D):
r"""
Return a somewhat random primitive binary quadratic form of the
given discriminant.
(In the case `D < 0`, only positive definite forms are returned.)
.. NOTE::
No guarantees are being made about the distribution of forms
sampled by this function.
EXAMPLES::
sage: BinaryQF.random(5) # random
448219*x^2 - 597179*x*y + 198911*y^2
sage: BinaryQF.random(-7) # random
10007*x^2 + 10107*x*y + 2552*y^2
TESTS::
sage: D = choice((-4,+4)) * randrange(9999) + randrange(2) or 1
sage: Q = BinaryQF.random(D)
sage: Q.discriminant() == D
True
sage: Q.is_primitive()
True
sage: Q.is_indefinite() or Q.is_positive_definite()
True
"""
D = ZZ(D)
D4 = D % 4
if D4 not in (0,1):
raise ValueError('discriminant must be congruent to 0 or 1 modulo 4')

from sage.misc.prandom import randrange
from sage.misc.misc_c import prod
from sage.matrix.special import random_matrix
B = (D.abs() or 1) * 99 # kind of arbitrary
while True:
b = randrange(D4, B, 2)
ac = (b**2 - D) // 4
if ac:
break
a = prod(l**randrange(e+1) for l,e in ac.factor())
a = a.prime_to_m_part(gcd([a, b, ac//a]))
c = ac // a
M = random_matrix(ZZ, 2, 2, 'unimodular')
M.rescale_row(0, (-1)**randrange(2))
return BinaryQF([a, b, c]) * M

def __mul__(self, right):
"""
Gauss composition or right action by a 2x2 integer matrix.
Expand Down
25 changes: 20 additions & 5 deletions src/sage/quadratic_forms/bqf_class_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@

from sage.misc.prandom import randrange
from sage.rings.integer_ring import ZZ
from sage.rings.finite_rings.integer_mod import Mod
from sage.arith.misc import random_prime
from sage.groups.generic import order_from_multiple, multiple
from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper
from sage.quadratic_forms.binary_qf import BinaryQF
Expand Down Expand Up @@ -181,13 +183,17 @@ def random_element(self):
r"""
Return a somewhat random element of this form class group.
ALGORITHM: :meth:`BinaryQF.random`
ALGORITHM:
Sample random odd primes `a` until `b^2 = D \pmod{4a}` has a
solution `b \in \ZZ` and set `c = (b^2-D)/(4a)`. Flip a coin
to choose the sign of `b`. Then return the class of `[a,b,c]`.
.. NOTE::
No guarantees are being made about the distribution of classes
sampled by this function. Heuristically, however, it should be
fairly close to uniform.
No strict guarantees are being made about the distribution of
classes sampled by this function. Heuristically, however, it
should be fairly close to uniform.
EXAMPLES::
Expand All @@ -198,7 +204,16 @@ def random_element(self):
sage: cl.form().discriminant()
-999
"""
return self(BinaryQF.random(self._disc))
B = self._disc.abs() * 100 + 9999
while True:
a = random_prime(B, proof=False, lbound=3)
if self._disc.kronecker(a) == 1:
break
b = ZZ(Mod(self._disc, 4*a).sqrt())
c = (b**2 - self._disc) // (4*a)
if randrange(2):
b = -b
return self(BinaryQF([a,b,c]))

def __hash__(self):
r"""
Expand Down

0 comments on commit 7c0a6c7

Please sign in to comment.