def enumerate_hypergeometric_data(d, weight=None): r""" Return an iterator over parameters of hypergeometric motives (up to swapping). INPUT: - ``d`` -- the degree - ``weight`` -- optional integer, to specify the motivic weight EXAMPLES:: sage: from sage.modular.hypergeometric_motive import enumerate_hypergeometric_data as enum sage: l = [H for H in enum(6, weight=2) if H.hodge_numbers()[0] == 1] sage: len(l) 112 """ bound = 2 * d * d # to make sure that phi(n) <= d possible = [(i, euler_phi(i)) for i in range(1, bound + 1) if euler_phi(i) <= d] poids = [z[1] for z in possible] N = len(poids) vectors = WeightedIntegerVectors(d, poids) def formule(u): return [possible[j][0] for j in range(N) for _ in range(u[j])] for a,b in combinations(vectors, 2): if not any(a[j] and b[j] for j in range(N)): H = HypergeometricData(cyclotomic=(formule(a), formule(b))) if weight is None or H.weight() == weight: yield H
def enumerate_hypergeometric_data(d, weight=None): r""" Return an iterator over parameters of hypergeometric motives (up to swapping). INPUT: - ``d`` -- the degree - ``weight`` -- optional integer, to specify the motivic weight EXAMPLES:: sage: from sage.modular.hypergeometric_motive import enumerate_hypergeometric_data as enum sage: l = [H for H in enum(6, weight=2) if H.hodge_numbers()[0] == 1] sage: len(l) 112 """ bound = 2 * d * d # to make sure that phi(n) <= d possible = [(i, euler_phi(i)) for i in range(1, bound + 1) if euler_phi(i) <= d] poids = [z[1] for z in possible] N = len(poids) vectors = WeightedIntegerVectors(d, poids) def formule(u): return [possible[j][0] for j in range(N) for _ in range(u[j])] for a, b in combinations(vectors, 2): if not any(a[j] and b[j] for j in range(N)): H = HypergeometricData(cyclotomic=(formule(a), formule(b))) if weight is None or H.weight() == weight: yield H
def _denominator(): R = PolynomialRing(ZZ, "T") T = R.gen() denom = R(1) lc = self._f.list()[-1] if lc == 1: # MONIC for i in range(2, self._delta + 1): if self._delta % i == 0: phi = euler_phi(i) G = IntegerModRing(i) ki = G(self._q).multiplicative_order() denom = denom * (T**ki - 1)**(phi // ki) return denom else: # Non-monic x = PolynomialRing(self._Fq, "x").gen() f = x**self._delta - lc L = f.splitting_field("a") roots = [r for r, _ in f.change_ring(L).roots()] roots_dict = dict([(r, i) for i, r in enumerate(roots)]) rootsfrob = [ L.frobenius_endomorphism(self._Fq.degree())(r) for r in roots ] m = zero_matrix(len(roots)) for i, r in enumerate(roots): m[i, roots_dict[rootsfrob[i]]] = 1 return R(R(m.characteristic_polynomial()) // (T - 1))
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))
def p072(): # We want to find all rational numbers between 0 and 1 with a # denominator of at most 1,000,000. # As the d denominator increases, the new rational numbers counted # will be equal in number to the integers coprime to d. # So, euler phi function. return sum(euler_phi(d) for d in range(2, 1_000_001))
def p073(): # We want the rational numbers with denominators of at most 12000 # between 1/3 and 1/2. # One approaches is to count the ones up to 1/2, then count the # ones up to 1/3, then subtract. # Due to symmetry, the rationals less than 1/2 will be half of those # counted by euler_phi - 1. # For the ones less than 1/3, I can brute force it. # There's theory behind this called Farey sequences, but brute # forcing is quicker than reading it. less_than_half = (sum(euler_phi(d) for d in range(2, 12001)) - 1) / 2 rationals = set() for d in range(2, 12001): for n in range(1, d): if n / d > 1 / 3: break rationals.add(n / d) # sage will treat this like a fraction less_than_third = len(rationals) return less_than_half - less_than_third
def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): r""" Creation of hypergeometric motives. INPUT: three possibilities are offered, each describing a quotient of products of cyclotomic polynomials. - ``cyclotomic`` -- a pair of lists of nonnegative integers, each integer `k` represents a cyclotomic polynomial `\Phi_k` - ``alpha_beta`` -- a pair of lists of rationals, each rational represents a root of unity - ``gamma_list`` -- a pair of lists of nonnegative integers, each integer `n` represents a polynomial `x^n - 1` In the last case, it is also allowed to send just one list of signed integers where signs indicate to which part the integer belongs to. EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(cyclotomic=([2],[1])) Hypergeometric data for [1/2] and [0] sage: Hyp(alpha_beta=([1/2],[0])) Hypergeometric data for [1/2] and [0] sage: Hyp(alpha_beta=([1/5,2/5,3/5,4/5],[0,0,0,0])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] sage: Hyp(gamma_list=([5],[1,1,1,1,1])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] sage: Hyp(gamma_list=([5,-1,-1,-1,-1,-1])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] """ if gamma_list is not None: if isinstance(gamma_list[0], (list, tuple)): pos, neg = gamma_list gamma_list = pos + [-u for u in neg] cyclotomic = gamma_list_to_cyclotomic(gamma_list) if cyclotomic is not None: cyclo_up, cyclo_down = cyclotomic if any(x in cyclo_up for x in cyclo_down): raise ValueError('overlapping parameters not allowed') deg = sum(euler_phi(x) for x in cyclo_down) up_deg = sum(euler_phi(x) for x in cyclo_up) if up_deg != deg: msg = 'not the same degree: {} != {}'.format(up_deg, deg) raise ValueError(msg) cyclo_up.sort() cyclo_down.sort() alpha = cyclotomic_to_alpha(cyclo_up) beta = cyclotomic_to_alpha(cyclo_down) elif alpha_beta is not None: alpha, beta = alpha_beta if len(alpha) != len(beta): raise ValueError('alpha and beta not of the same length') alpha = sorted(u - floor(u) for u in alpha) beta = sorted(u - floor(u) for u in beta) cyclo_up = alpha_to_cyclotomic(alpha) cyclo_down = alpha_to_cyclotomic(beta) deg = sum(euler_phi(x) for x in cyclo_down) self._cyclo_up = tuple(cyclo_up) self._cyclo_down = tuple(cyclo_down) self._alpha = tuple(alpha) self._beta = tuple(beta) self._deg = deg self._gamma_array = cyclotomic_to_gamma(cyclo_up, cyclo_down) self._trace_coeffs = {} up = QQ.prod(capital_M(d) for d in cyclo_up) down = QQ.prod(capital_M(d) for d in cyclo_down) self._M_value = up / down if 0 in alpha: self._swap = HypergeometricData(alpha_beta=(beta, alpha)) if self.weight() % 2: self._sign_param = 1 else: if (deg % 2) != (0 in alpha): self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_down) else: self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_up)
def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): r""" Creation of hypergeometric motives. INPUT: three possibilities are offered, each describing a quotient of products of cyclotomic polynomials. - ``cyclotomic`` -- a pair of lists of nonnegative integers, each integer `k` represents a cyclotomic polynomial `\Phi_k` - ``alpha_beta`` -- a pair of lists of rationals, each rational represents a root of unity - ``gamma_list`` -- a pair of lists of nonnegative integers, each integer `n` represents a polynomial `x^n - 1` In the last case, it is also allowed to send just one list of signed integers where signs indicate to which part the integer belongs to. EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(cyclotomic=([2],[1])) Hypergeometric data for [1/2] and [0] sage: Hyp(alpha_beta=([1/2],[0])) Hypergeometric data for [1/2] and [0] sage: Hyp(alpha_beta=([1/5,2/5,3/5,4/5],[0,0,0,0])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] sage: Hyp(gamma_list=([5],[1,1,1,1,1])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] sage: Hyp(gamma_list=([5,-1,-1,-1,-1,-1])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] """ if gamma_list is not None: if isinstance(gamma_list[0], (list, tuple)): pos, neg = gamma_list gamma_list = pos + [-u for u in neg] cyclotomic = gamma_list_to_cyclotomic(gamma_list) if cyclotomic is not None: cyclo_up, cyclo_down = cyclotomic if any(x in cyclo_up for x in cyclo_down): raise ValueError('overlapping parameters not allowed') deg = sum(euler_phi(x) for x in cyclo_down) up_deg = sum(euler_phi(x) for x in cyclo_up) if up_deg != deg: msg = 'not the same degree: {} != {}'.format(up_deg, deg) raise ValueError(msg) cyclo_up.sort() cyclo_down.sort() alpha = cyclotomic_to_alpha(cyclo_up) beta = cyclotomic_to_alpha(cyclo_down) elif alpha_beta is not None: alpha, beta = alpha_beta if len(alpha) != len(beta): raise ValueError('alpha and beta not of the same length') alpha = sorted(u - floor(u) for u in alpha) beta = sorted(u - floor(u) for u in beta) cyclo_up = alpha_to_cyclotomic(alpha) cyclo_down = alpha_to_cyclotomic(beta) deg = sum(euler_phi(x) for x in cyclo_down) self._cyclo_up = cyclo_up self._cyclo_down = cyclo_down self._alpha = alpha self._beta = beta self._deg = deg if self.weight() % 2: self._sign_param = 1 else: if deg % 2: self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_down) else: self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_up)