def num_cusps_of_width(N, d) -> Integer: r""" Return the number of cusps on `X_0(N)` of width ``d``. INPUT: - ``N`` -- (integer): the level - ``d`` -- (integer): an integer dividing N, the cusp width EXAMPLES:: sage: from sage.modular.etaproducts import num_cusps_of_width sage: [num_cusps_of_width(18,d) for d in divisors(18)] [1, 1, 2, 2, 1, 1] sage: num_cusps_of_width(4,8) Traceback (most recent call last): ... ValueError: N and d must be positive integers with d|N """ N = ZZ(N) d = ZZ(d) if N <= 0 or d <= 0 or N % d: raise ValueError("N and d must be positive integers with d|N") return euler_phi(d.gcd(N // d))
class Small_primes_of_degree_one_iter(): r""" Iterator that finds primes of a number field of absolute degree one and bounded small prime norm. INPUT: - ``field`` -- a ``NumberField``. - ``num_integer_primes`` (default: 10000) -- an integer. We try to find primes of absolute norm no greater than the ``num_integer_primes``-th prime number. For example, if ``num_integer_primes`` is 2, the largest norm found will be 3, since the second prime is 3. - ``max_iterations`` (default: 100) -- an integer. We test ``max_iterations`` integers to find small primes before raising ``StopIteration``. AUTHOR: - Nick Alexander """ def __init__(self, field, num_integer_primes=10000, max_iterations=100): r""" Construct a new iterator of small degree one primes. EXAMPLES:: sage: x = QQ['x'].gen() sage: K.<a> = NumberField(x^2 - 3) sage: K.primes_of_degree_one_list(3) # random [Fractional ideal (2*a + 1), Fractional ideal (-a + 4), Fractional ideal (3*a + 2)] """ self._field = field self._poly = self._field.absolute_field('b').defining_polynomial() self._poly = ZZ['x'](self._poly.denominator() * self._poly()) # make integer polynomial self._lc = self._poly.leading_coefficient() # this uses that [ O_K : Z[a] ]^2 = | disc(f(x)) / disc(O_K) | from sage.libs.pari.all import pari self._prod_of_small_primes = ZZ(pari('TEMPn = %s; TEMPps = primes(TEMPn); prod(X = 1, TEMPn, TEMPps[X])' % num_integer_primes)) self._prod_of_small_primes //= self._prod_of_small_primes.gcd(self._poly.discriminant() * self._lc) self._integer_iter = iter(ZZ) self._queue = [] self._max_iterations = max_iterations def __iter__(self): r""" Return self as an iterator. EXAMPLES:: sage: x = QQ['x'].gen() sage: K.<a> = NumberField(x^2 - 3) sage: it = K.primes_of_degree_one_iter() sage: iter(it) == it # indirect doctest True """ return self def _lengthen_queue(self): r""" Try to find more primes of absolute degree one of small prime norm. Checks \code{self._max_iterations} integers before failing. WARNING: Internal function. Not for external use! EXAMPLES:: sage: x = QQ['x'].gen() sage: K.<a> = NumberField(x^2 - 3) sage: Ps = K.primes_of_degree_one_list(20, max_iterations=3) # indirect doctest sage: len(Ps) == 20 True """ count = 0 while count < self._max_iterations: n = next(self._integer_iter) g = self._prod_of_small_primes.gcd(self._poly(n)) self._prod_of_small_primes //= g self._queue = self._queue + [ (p, n) for p in g.prime_divisors() ] count += 1 self._queue.sort() # sorts in ascending order def __next__(self): r""" Return a prime of absolute degree one of small prime norm. Raises ``StopIteration`` if such a prime cannot be easily found. EXAMPLES:: sage: x = QQ['x'].gen() sage: K.<a> = NumberField(x^2 - 3) sage: it = K.primes_of_degree_one_iter() sage: [ next(it) for i in range(3) ] # random [Fractional ideal (2*a + 1), Fractional ideal (-a + 4), Fractional ideal (3*a + 2)] TESTS: We test that :trac:`6396` is fixed. Note that the doctest is flagged as random since the string representation of ideals is somewhat unpredictable:: sage: N.<a,b> = NumberField([x^2 + 1, x^2 - 5]) sage: ids = N.primes_of_degree_one_list(10); ids # random [Fractional ideal ((-1/2*b + 1/2)*a + 2), Fractional ideal (-b*a + 1/2*b + 1/2), Fractional ideal ((1/2*b + 3/2)*a - b), Fractional ideal ((-1/2*b - 3/2)*a + b - 1), Fractional ideal (-b*a - b + 1), Fractional ideal (3*a + 1/2*b - 1/2), Fractional ideal ((-3/2*b + 1/2)*a + 1/2*b - 1/2), Fractional ideal ((-1/2*b - 5/2)*a - b + 1), Fractional ideal (2*a - 3/2*b - 1/2), Fractional ideal (3*a + 1/2*b + 5/2)] sage: [x.absolute_norm() for x in ids] [29, 41, 61, 89, 101, 109, 149, 181, 229, 241] sage: ids[9] == N.ideal(3*a + 1/2*b + 5/2) True We test that :trac:`23468` is fixed:: sage: R.<z> = QQ[] sage: K.<y> = QQ.extension(25*z^2 + 26*z + 5) sage: for p in K.primes_of_degree_one_list(10): ....: assert p.is_prime() """ if not self._queue: self._lengthen_queue() if not self._queue: raise StopIteration p, n = self._queue.pop(0) x = self._field.absolute_generator() return self._field.ideal([p, (x - n) * self._lc]) next = __next__
def find_m(n, k, bound = None, b = 1): ''' INPUT : - ``n`` -- an integer, the degree, - ``k`` -- a finite field, the base field, - ``bound`` -- (default : None) a positive integer used as the max for m. OUTPUT : - A tuple containing an integer and a set of class modulo m. EXAMPLES : sage: find_m(281, GF(1747)) (3373, {4, 14, 18, 43, 57, 3325, 3337, 3348, 3354, 3357, 3364}) sage: find_m(23, GF(11)) (47, {0, 1, 2, 3, 44, 45, 46}) ALGORITHM : First and foremost we are looking for an integer m for which n | phi(m). A good way to obtain such integers is to look for prime power of the form m = an + 1, because then phi(m) = d.(an) which is divisible by n. We also want phi(m) to be coprime with n, then choosing m to be a prime (which is possible thanks to Dirichlet's theorem on the arithmetic progressions) we ensure that it is actually the case. It still works fine, theoratically, if an + 1 is a prime power and d isn't divisble by n. Though, we almost always get to pick a m that is prime. Once we have that integer, we try to compute good candidates for the traces and see how many works. If less than a certain number works (this number is equal to 1 at the moment), we discard it and test the next prime power. When one is found, we return it with its trace class candidates. ''' if bound is None: bound_a = 100 # Arbitrary value. else: # if m = a*n + 1 < b, then a < (b- 1)/n. bound_a = (bound - 1) / n for a in range(bound_a): m = a*n + b try: euphin = ZZ(euler_phi(m)/n) except TypeError: continue # m composite not implemented yet if not m.is_prime(): continue #elif euphin == 1: # temp = find_m(n, k, b = b+1) # if temp == None: # continue # else: # return temp elif euphin.gcd(n) != 1: continue else: S_t = find_trace(n, m, k) # Some time in the future we'd like to have a # better bound than just 1. if len(S_t) < 1: continue else: return m, S_t, 0