def generate_isogenies(self): if self._inseparable_degree != 1: current_curve = self._separable_domain_extended current_kernel = self._separable_kernel else: current_curve = self.extended_curve() current_kernel = self._kernel degree_factors = list(factor(self._degree)) primes = [i[0] for i in degree_factors for _ in range(i[1])] isogenies = list() for l in primes: isogeny = prime_isogeny(current_curve, current_kernel, l) if isinstance(isogeny, tuple): current_curve = isogeny[0] current_kernel = map_points(isogeny, current_kernel) else: current_curve = isogeny.codomain() current_kernel = map_points(isogeny, current_kernel) isogenies.append(isogeny) self._isogeny_factors = isogenies
def prime_candidates(self): r""" Determine those primes `p` where `\mu_B` might not be a `(p)`-minimal polynomial. OUTPUT: A list of primes. EXAMPLES:: sage: from sage.matrix.compute_J_ideal import ComputeMinimalPolynomials sage: B = matrix(ZZ, [[1, 0, 1], [1, -2, -1], [10, 0, 0]]) sage: C = ComputeMinimalPolynomials(B) sage: C.prime_candidates() [2, 3, 5] sage: C.p_minimal_polynomials(2) {2: x^2 + 3*x + 2} sage: C.p_minimal_polynomials(3) {} sage: C.p_minimal_polynomials(5) {} This means that `3` and `5` were candidates, but actually, `\mu_B` turns out to be a `(3)`-minimal polynomial and a `(5)`-minimal polynomial. """ from sage.arith.misc import factor F, T = self._B.frobenius(2) return [p for (p, t) in factor(T.det())]
def endomorphism_index(self): j = self._j_invariant field = j.parent() t = self._domain.trace_of_frobenius() self._trace = t Dv = t**2 - 4 * self._domain.base_field().order() D = Dv.squarefree_part() v = Dv // D if D % 4 != 1: v = v // 4 ls = [(i[0], i[1] // 2) for i in list(factor(v)) if i[1] >= 2] u = 1 for a in ls: l = a[0] Phi = ClassicalModularPolynomialDatabase()[l] dist = len(find_descending_path(j, Phi, l, special=False)) - 1 ex = a[1] - dist u *= l**ex self._index = u
def coefficient(self, m): if m <= 0: # TODO: we are assuming the form is a cusp form return 0 elif m == 1: return 1 from sage.arith.misc import factor fact = factor(m) if len(fact) == 1: p, j = fact[0] a_p = self._apdict[p] # prime power if j == 1: return a_p else: return (a_p * self.coefficient(p**(j - 1)) - self.character()(p) * p**(self.weight() - 1) * self.coefficient(p**(j - 2))) else: from sage.misc.all import prod return prod(self.coefficient(p**k) for p, k in fact)
def covector_txt(covec, m=0, factor_coeff=False): r""" Return a txt description of the covector. INPUT: - ``covec`` -- a dictionary in the format of :meth:`extract_a_solution` - ``m`` -- the stopping degree of the factorization of the covector - ``factor_coeff`` -- (default:``False``) a boolean; whether to factor the coefficients for the output OUTPUT: A text string whose rows describe the coefficients of the covector, e.g. (12)^{2}(2)(1)^{3}(112):-15 means that the covector contains a summand `-15\lambda_{12122111112}`. The components are given as factored strings with the final term having degree as close to `m` as possible. The coefficients are integers. """ rows = [] for X in covec: Xs = X.leading_support() if factor_coeff: coeff = str(factor(covec[X])) else: coeff = str(covec[X]) fstr, final = factorstr_withfinal(Xs, m) rows.append(("%s:%s" % (fstr, coeff), final, Xs)) sortkey = lambda row: (getattr(row[2], '_grade', 1), row[1], row[2]) sortedrows = [fstr for fstr, final, Xs in sorted(rows, key=sortkey)] return "\n".join(sortedrows)
def null_ideal(self, b=0): r""" Return the `(b)`-ideal `N_{(b)}(B)=\{f\in D[X] \mid f(B)\in M_n(bD)\}`. INPUT: - ``b`` -- an element of `D` (default: 0) OUTPUT: An ideal in `D[X]`. EXAMPLES:: sage: from sage.matrix.compute_J_ideal import ComputeMinimalPolynomials sage: B = matrix(ZZ, [[1, 0, 1], [1, -2, -1], [10, 0, 0]]) sage: C = ComputeMinimalPolynomials(B) sage: C.null_ideal() Principal ideal (x^3 + x^2 - 12*x - 20) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(2) Ideal (2, x^2 + x) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(4) Ideal (4, x^2 + 3*x + 2) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(8) Ideal (8, x^3 + x^2 - 12*x - 20, 2*x^2 + 6*x + 4) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(3) Ideal (3, x^3 + x^2 - 12*x - 20) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(6) Ideal (6, 2*x^3 + 2*x^2 - 24*x - 40, 3*x^2 + 3*x) of Univariate Polynomial Ring in x over Integer Ring """ from sage.arith.misc import factor mu_B_coefficients = [] generators = [] if b == 0: mu_B_coefficients = [1] else: for (p, t) in factor(b): cofactor = b // p**t p_polynomials = self.p_minimal_polynomials(p, t) generators += [ cofactor * p**(t - s) * nu for s, nu in iteritems(p_polynomials) ] if not p_polynomials or max(iterkeys(p_polynomials)) < t: mu_B_coefficients.append(cofactor) assert all((g(self._B) % b).is_zero() for g in generators), \ "Polynomials not in %s-ideal" % (b,) if mu_B_coefficients: (mu_B_coefficient, ) = self._D.ideal(mu_B_coefficients).gens() generators = [mu_B_coefficient * self.mu_B] + generators if b != 0: generators = [self._DX(b)] + generators return self._DX.ideal(generators)
def MacMahonOmega(var, expression, denominator=None, op=operator.ge, Factorization_sort=False, Factorization_simplify=True): r""" Return `\Omega_{\mathrm{op}}` of ``expression`` with respect to ``var``. To be more precise, calculate .. MATH:: \Omega_{\mathrm{op}} \frac{n}{d_1 \dots d_n} for the numerator `n` and the factors `d_1`, ..., `d_n` of the denominator, all of which are Laurent polynomials in ``var`` and return a (partial) factorization of the result. INPUT: - ``var`` -- a variable or a representation string of a variable - ``expression`` -- a :class:`~sage.structure.factorization.Factorization` of Laurent polynomials or, if ``denominator`` is specified, a Laurent polynomial interpreted as the numerator of the expression - ``denominator`` -- a Laurent polynomial or a :class:`~sage.structure.factorization.Factorization` (consisting of Laurent polynomial factors) or a tuple/list of factors (Laurent polynomials) - ``op`` -- (default: ``operator.ge``) an operator At the moment only ``operator.ge`` is implemented. - ``Factorization_sort`` (default: ``False``) and ``Factorization_simplify`` (default: ``True``) -- are passed on to :class:`sage.structure.factorization.Factorization` when creating the result OUTPUT: A (partial) :class:`~sage.structure.factorization.Factorization` of the result whose factors are Laurent polynomials .. NOTE:: The numerator of the result may not be factored. REFERENCES: - [Mac1915]_ - [APR2001]_ EXAMPLES:: sage: L.<mu, x, y, z, w> = LaurentPolynomialRing(ZZ) sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu]) 1 * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu, 1 - z/mu]) 1 * (-x + 1)^-1 * (-x*y + 1)^-1 * (-x*z + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y*mu, 1 - z/mu]) (-x*y*z + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-x*z + 1)^-1 * (-y*z + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu^2]) 1 * (-x + 1)^-1 * (-x^2*y + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^2, 1 - y/mu]) (x*y + 1) * (-x + 1)^-1 * (-x*y^2 + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y*mu, 1 - z/mu^2]) (-x^2*y*z - x*y^2*z + x*y*z + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-x^2*z + 1)^-1 * (-y^2*z + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu^3]) 1 * (-x + 1)^-1 * (-x^3*y + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu^4]) 1 * (-x + 1)^-1 * (-x^4*y + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^3, 1 - y/mu]) (x*y^2 + x*y + 1) * (-x + 1)^-1 * (-x*y^3 + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^4, 1 - y/mu]) (x*y^3 + x*y^2 + x*y + 1) * (-x + 1)^-1 * (-x*y^4 + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^2, 1 - y/mu, 1 - z/mu]) (x*y*z + x*y + x*z + 1) * (-x + 1)^-1 * (-x*y^2 + 1)^-1 * (-x*z^2 + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^2, 1 - y*mu, 1 - z/mu]) (-x*y*z^2 - x*y*z + x*z + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-x*z^2 + 1)^-1 * (-y*z + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y*mu, 1 - z*mu, 1 - w/mu]) (x*y*z*w^2 + x*y*z*w - x*y*w - x*z*w - y*z*w + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-z + 1)^-1 * (-x*w + 1)^-1 * (-y*w + 1)^-1 * (-z*w + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y*mu, 1 - z/mu, 1 - w/mu]) (x^2*y*z*w + x*y^2*z*w - x*y*z*w - x*y*z - x*y*w + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-x*z + 1)^-1 * (-x*w + 1)^-1 * (-y*z + 1)^-1 * (-y*w + 1)^-1 sage: MacMahonOmega(mu, mu^-2, [1 - x*mu, 1 - y/mu]) x^2 * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^-1, [1 - x*mu, 1 - y/mu]) x * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu, [1 - x*mu, 1 - y/mu]) (-x*y + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2, [1 - x*mu, 1 - y/mu]) (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 We demonstrate the different allowed input variants:: sage: MacMahonOmega(mu, ....: Factorization([(mu, 2), (1 - x*mu, -1), (1 - y/mu, -1)])) (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2, ....: Factorization([(1 - x*mu, 1), (1 - y/mu, 1)])) (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2, [1 - x*mu, 1 - y/mu]) (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2, (1 - x*mu)*(1 - y/mu)) # not tested because not fully implemented (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2 / ((1 - x*mu)*(1 - y/mu))) # not tested because not fully implemented (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 TESTS:: sage: MacMahonOmega(mu, 1, [1 - x*mu]) 1 * (-x + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x/mu]) 1 sage: MacMahonOmega(mu, 0, [1 - x*mu]) 0 sage: MacMahonOmega(mu, L(1), []) 1 sage: MacMahonOmega(mu, L(0), []) 0 sage: MacMahonOmega(mu, 2, []) 2 sage: MacMahonOmega(mu, 2*mu, []) 2 sage: MacMahonOmega(mu, 2/mu, []) 0 :: sage: MacMahonOmega(mu, Factorization([(1/mu, 1), (1 - x*mu, -1), ....: (1 - y/mu, -2)], unit=2)) 2*x * (-x + 1)^-1 * (-x*y + 1)^-2 sage: MacMahonOmega(mu, Factorization([(mu, -1), (1 - x*mu, -1), ....: (1 - y/mu, -2)], unit=2)) 2*x * (-x + 1)^-1 * (-x*y + 1)^-2 sage: MacMahonOmega(mu, Factorization([(mu, -1), (1 - x, -1)])) 0 sage: MacMahonOmega(mu, Factorization([(2, -1)])) 1 * 2^-1 :: sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - z, 1 - y/mu]) 1 * (-z + 1)^-1 * (-x + 1)^-1 * (-x*y + 1)^-1 :: sage: MacMahonOmega(mu, 1, [1 - x*mu], op=operator.lt) Traceback (most recent call last): ... NotImplementedError: At the moment, only Omega_ge is implemented. sage: MacMahonOmega(mu, 1, Factorization([(1 - x*mu, -1)])) Traceback (most recent call last): ... ValueError: Factorization (-mu*x + 1)^-1 of the denominator contains negative exponents. sage: MacMahonOmega(2*mu, 1, [1 - x*mu]) Traceback (most recent call last): ... ValueError: 2*mu is not a variable. sage: MacMahonOmega(mu, 1, Factorization([(0, 2)])) Traceback (most recent call last): ... ZeroDivisionError: Denominator contains a factor 0. sage: MacMahonOmega(mu, 1, [2 - x*mu]) Traceback (most recent call last): ... NotImplementedError: Factor 2 - x*mu is not normalized. sage: MacMahonOmega(mu, 1, [1 - x*mu - mu^2]) Traceback (most recent call last): ... NotImplementedError: Cannot handle factor 1 - x*mu - mu^2. :: sage: L.<mu, x, y, z, w> = LaurentPolynomialRing(QQ) sage: MacMahonOmega(mu, 1/mu, ....: Factorization([(1 - x*mu, 1), (1 - y/mu, 2)], unit=2)) 1/2*x * (-x + 1)^-1 * (-x*y + 1)^-2 """ from sage.arith.misc import factor from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring \ import LaurentPolynomialRing, LaurentPolynomialRing_univariate from sage.structure.factorization import Factorization if op != operator.ge: raise NotImplementedError( 'At the moment, only Omega_ge is implemented.') if denominator is None: if isinstance(expression, Factorization): numerator = expression.unit() * \ prod(f**e for f, e in expression if e > 0) denominator = tuple(f for f, e in expression if e < 0 for _ in range(-e)) else: numerator = expression.numerator() denominator = expression.denominator() else: numerator = expression # at this point we have numerator/denominator if isinstance(denominator, (list, tuple)): factors_denominator = denominator else: if not isinstance(denominator, Factorization): denominator = factor(denominator) if not denominator.is_integral(): raise ValueError( 'Factorization {} of the denominator ' 'contains negative exponents.'.format(denominator)) numerator *= ZZ(1) / denominator.unit() factors_denominator = tuple(factor for factor, exponent in denominator for _ in range(exponent)) # at this point we have numerator/factors_denominator P = var.parent() if isinstance(P, LaurentPolynomialRing_univariate) and P.gen() == var: L = P L0 = L.base_ring() elif var in P.gens(): var = repr(var) L0 = LaurentPolynomialRing( P.base_ring(), tuple(v for v in P.variable_names() if v != var)) L = LaurentPolynomialRing(L0, var) var = L.gen() else: raise ValueError('{} is not a variable.'.format(var)) other_factors = [] to_numerator = [] decoded_factors = [] for factor in factors_denominator: factor = L(factor) D = factor.dict() if not D: raise ZeroDivisionError('Denominator contains a factor 0.') elif len(D) == 1: exponent, coefficient = next(iteritems(D)) if exponent == 0: other_factors.append(L0(factor)) else: to_numerator.append(factor) elif len(D) == 2: if D.get(0, 0) != 1: raise NotImplementedError( 'Factor {} is not normalized.'.format(factor)) D.pop(0) exponent, coefficient = next(iteritems(D)) decoded_factors.append((-coefficient, exponent)) else: raise NotImplementedError( 'Cannot handle factor {}.'.format(factor)) numerator = L(numerator) / prod(to_numerator) result_numerator, result_factors_denominator = \ _Omega_(numerator.dict(), decoded_factors) if result_numerator == 0: return Factorization([], unit=result_numerator) return Factorization([(result_numerator, 1)] + list( (f, -1) for f in other_factors) + list( (1 - f, -1) for f in result_factors_denominator), sort=Factorization_sort, simplify=Factorization_simplify)
def null_ideal(self, b=0): r""" Return the `(b)`-ideal `N_{(b)}(B)=\{f\in D[X] \mid f(B)\in M_n(bD)\}`. INPUT: - ``b`` -- an element of `D` (default: 0) OUTPUT: An ideal in `D[X]`. EXAMPLES:: sage: from sage.matrix.compute_J_ideal import ComputeMinimalPolynomials sage: B = matrix(ZZ, [[1, 0, 1], [1, -2, -1], [10, 0, 0]]) sage: C = ComputeMinimalPolynomials(B) sage: C.null_ideal() Principal ideal (x^3 + x^2 - 12*x - 20) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(2) Ideal (2, x^2 + x) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(4) Ideal (4, x^2 + 3*x + 2) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(8) Ideal (8, x^3 + x^2 - 12*x - 20, 2*x^2 + 6*x + 4) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(3) Ideal (3, x^3 + x^2 - 12*x - 20) of Univariate Polynomial Ring in x over Integer Ring sage: C.null_ideal(6) Ideal (6, 2*x^3 + 2*x^2 - 24*x - 40, 3*x^2 + 3*x) of Univariate Polynomial Ring in x over Integer Ring """ from sage.arith.misc import factor mu_B_coefficients = [] generators = [] if b == 0: mu_B_coefficients = [1] else: for (p, t) in factor(b): cofactor = b // p**t p_polynomials = self.p_minimal_polynomials(p, t) generators += [cofactor*p**(t-s)*nu for s, nu in iteritems(p_polynomials)] if not p_polynomials or max(iterkeys(p_polynomials)) < t: mu_B_coefficients.append(cofactor) assert all((g(self._B) % b).is_zero() for g in generators), \ "Polynomials not in %s-ideal" % (b,) if mu_B_coefficients: (mu_B_coefficient,) = self._D.ideal(mu_B_coefficients).gens() generators = [mu_B_coefficient * self.mu_B] + generators if b != 0: generators = [self._DX(b)] + generators return self._DX.ideal(generators)
def find_monomials(polynomial, poly_degree, r, s, form="list", sort_type="zero", early_finish=True, rolling_output=True, out_file=None): """This function finds all monomials that, in relation to the given monomial, fit the criteria of the problem. ***ATTENTION: DESPITE THE VARIABLE DECLARATIONS AT THE BEGINNING OF THE FUNCTION, THIS FUNCTION WILL NOT WORK CORRECTLY IF ALL VARIABLES IN THE INPUT POLYNOMIAL HAVE NOT ALREADY BEEN DECLARED.*** Args: polynomial(symb exp): The polynomial to which monomials will be matched. poly_degree(int): The degree of the input polynomial. r(int): The r value for the input polynomial. s(int): The s value for the input polynomial. form(str): If form is "list", the function will return a list of monomials. If form is "tup", the function will return a list of tuples with the form: (monomial, coefficient). sort_type(str): If sort_type is "zero", monomials are sorted by distance of the coefficient from zero. If sort type is "value", monomials are sorted by the coefficient's value. Returns: monomials(list): Returns either a list of monomials or a list of tuples depending on the value of form. Sorted by value or distance from zero of coefficients depending on the value of sort_type. If there are no working monomials, the function returns an empty list. """ if out_file != None: try: file = open(out_file, "w+") except: out_file = None print "File failed to open, printing to stdout..." print #Double check that variables are declared to prevent errors when forming monomials. for num in xrange(1, r + 1): var("x" + str(num)) for num in xrange(1, s + 1): var("y" + str(num)) # Declare ring as R ringlists = ring_lists(r, s) R, ringlists[1] = PolynomialRing(RationalField(), r + s, ringlists[0]).objgens() #Monomials must be checked against the expanded monomial # polynomial_expanded = polynomial.expand() #--- This was the old way polynomial_expanded = type_change(polynomial, ring=R) """This variable will be used to create a monomial "template" with all the essential variables and variables in place of exponent values. """ test_monomial = create_template_monomial(r, s) """This block creates a list of placeholders for x and y variable exponents in the order they appear. """ list_of_both_powers = create_power_list(r, s) """This block finds all possible exponent combinations for x and y variables in a list form, then finds all possible permutations of that list. """ list_of_power_values = create_power_values(r, s, poly_degree) """Now, every list of exponent possibilites is subbed into the monomial template, then checked against the expanded polynomial. If it is present in the expanded form, it is added to the final list. """ workable_monomials = [] for power_values in list_of_power_values: for power_set in multiset_permutations(power_values): temp_test_monomial = test_monomial power_set = list(power_set) if r > 0 and s > 0: testing_list = check_monomial_rs(r, s, power_set, temp_test_monomial, list_of_both_powers, polynomial_expanded, R) elif r > 0 and s == 0: testing_list = check_monomial_r(r, s, power_set, temp_test_monomial, list_of_both_powers, polynomial_expanded, R) elif r == 0 and s > 0: testing_list = check_monomial_s(r, s, power_set, temp_test_monomial, list_of_both_powers, polynomial_expanded, R) else: raise ValueError( "Invalid r and s inputs. r and s may not be bellow zero and may not both be zero" ) if testing_list[0] == 1: workable_monomials.append( (testing_list[2] * testing_list[1], int(testing_list[2]))) if rolling_output == True: if out_file != None: file.write(str(testing_list[2] * testing_list[1])) file.write("\n") else: print testing_list[2] * testing_list[1] #The following block tests to see if the function can finish early if early_finish == True: fin = 1 for fac in list(factor(int(testing_list[2]))): if r + s > 9: prime_range = xrange(-5, 6) else: prime_range = xrange(-3, 4) if fac[0] not in prime_range: fin = 0 if fin == 1: if form == "list": for i in xrange(0, len(workable_monomials)): workable_monomials[i] = workable_monomials[i][ 0] return workable_monomials #Changes output depending on preferences set at the outset. if len(workable_monomials) > 0: if sort_type == "zero": workable_monomials = sorted(workable_monomials, key=lambda tup: abs(tup[1])) else: workable_monomials = sorted(workable_monomials, key=lambda tup: tup[1]) if form == "list": for i in xrange(0, len(workable_monomials)): workable_monomials[i] = workable_monomials[i][0] return workable_monomials
def darmon_point(P, E, beta, prec, ramification_at_infinity=None, input_data=None, magma=None, working_prec=None, recognize_point=True, **kwargs): r''' EXAMPLES: We first need to import the module:: sage: from darmonpoints.darmonpoints import darmon_point A first example (Stark--Heegner point):: sage: from darmonpoints.darmonpoints import darmon_point sage: darmon_point(7,EllipticCurve('35a1'),41,20, cohomological=False, use_magma=False, use_ps_dists = True) Starting computation of the Darmon point ... (-70*alpha + 449 : 2100*alpha - 13444 : 1) A quaternionic (Greenberg) point:: sage: darmon_point(13,EllipticCurve('78a1'),5,20) # long time # optional - magma A Darmon point over a cubic (1,1) field:: sage: F.<r> = NumberField(x^3 - x^2 - x + 2) sage: E = EllipticCurve([-r -1, -r, -r - 1,-r - 1, 0]) sage: N = E.conductor() sage: P = F.ideal(r^2 - 2*r - 1) sage: beta = -3*r^2 + 9*r - 6 sage: darmon_point(P,E,beta,20) # long time # optional - magma ''' # global G, Coh, phiE, Phi, dK, J, J1, cycleGn, nn, Jlist config = ConfigParser.ConfigParser() config.read('config.ini') param_dict = config_section_map(config, 'General') param_dict.update(config_section_map(config, 'DarmonPoint')) param_dict.update(kwargs) param = Bunch(**param_dict) # Get general parameters outfile = param.get('outfile') use_ps_dists = param.get('use_ps_dists', False) use_shapiro = param.get('use_shapiro', False) use_sage_db = param.get('use_sage_db', False) magma_seed = param.get('magma_seed', 1515316) parallelize = param.get('parallelize', False) Up_method = param.get('up_method', 'naive') use_magma = param.get('use_magma', True) progress_bar = param.get('progress_bar', True) sign_at_infinity = param.get('sign_at_infinity', ZZ(1)) # Get darmon_point specific parameters idx_orientation = param.get('idx_orientation') idx_embedding = param.get('idx_embedding', 0) algorithm = param.get('algorithm') quaternionic = param.get('quaternionic') cohomological = param.get('cohomological', True) if Up_method == "bigmatrix" and use_shapiro == True: import warnings warnings.warn( 'Use of "bigmatrix" for Up iteration is incompatible with Shapiro Lemma trick. Using "naive" method for Up.' ) Up_method = 'naive' if working_prec is None: working_prec = max([2 * prec + 10, 30]) if use_magma: page_path = os.path.dirname(__file__) + '/KleinianGroups-1.0/klngpspec' if magma is None: from sage.interfaces.magma import Magma magma = Magma() quit_when_done = True else: quit_when_done = False magma.attach_spec(page_path) else: quit_when_done = False sys.setrecursionlimit(10**6) F = E.base_ring() beta = F(beta) DB, Np, Ncartan = get_heegner_params(P, E, beta) if quaternionic is None: quaternionic = (DB != 1) if cohomological is None: cohomological = quaternionic if quaternionic and not cohomological: raise ValueError( "Need cohomological algorithm when dealing with quaternions") if use_ps_dists is None: use_ps_dists = False if cohomological else True try: p = ZZ(P) except TypeError: p = ZZ(P.norm()) if not p.is_prime(): raise ValueError('P (= %s) should be a prime, of inertia degree 1' % P) if F == QQ: dK = ZZ(beta) extra_conductor_sq = dK / fundamental_discriminant(dK) assert ZZ(extra_conductor_sq).is_square() extra_conductor = extra_conductor_sq.sqrt() dK = dK / extra_conductor_sq assert dK == fundamental_discriminant(dK) if dK % 4 == 0: dK = ZZ(dK / 4) beta = dK else: dK = beta # Compute the completion of K at p x = QQ['x'].gen() K = F.extension(x * x - dK, names='alpha') if F == QQ: dK = K.discriminant() else: dK = K.relative_discriminant() hK = K.class_number() sgninfty = 'plus' if sign_at_infinity == 1 else 'minus' if hasattr(E, 'cremona_label'): Ename = E.cremona_label() elif hasattr(E, 'ainvs'): Ename = E.ainvs() else: Ename = 'unknown' fname = 'moments_%s_%s_%s_%s.sobj' % (P, Ename, sgninfty, prec) if use_sage_db: print("Moments will be stored in database as %s" % (fname)) if outfile == 'log': outfile = '%s_%s_%s_%s_%s_%s.log' % ( P, Ename, dK, sgninfty, prec, datetime.datetime.now().strftime("%Y%m%d-%H%M%S")) outfile = outfile.replace('/', 'div') outfile = '/tmp/darmonpoint_' + outfile fwrite("Starting computation of the Darmon point", outfile) fwrite('D_B = %s %s' % (DB, factor(DB)), outfile) fwrite('Np = %s' % Np, outfile) if Ncartan is not None: fwrite('Ncartan = %s' % Ncartan, outfile) fwrite('dK = %s (class number = %s)' % (dK, hK), outfile) fwrite('Calculation with p = %s and prec = %s' % (P, prec), outfile) fwrite('Elliptic curve %s: %s' % (Ename, E), outfile) if outfile is not None: print("Partial results will be saved in %s" % outfile) if input_data is None: if cohomological: # Define the S-arithmetic group if F != QQ and ramification_at_infinity is None: if F.signature()[0] > 1: if F.signature()[1] == 1: ramification_at_infinity = F.real_places( prec=Infinity) # Totally 'definite' else: raise ValueError( 'Please specify the ramification at infinity') elif F.signature()[0] == 1: if len(F.ideal(DB).factor()) % 2 == 0: ramification_at_infinity = [] # Split at infinity else: ramification_at_infinity = F.real_places( prec=Infinity) # Ramified at infinity else: ramification_at_infinity = None if F == QQ: abtuple = QuaternionAlgebra(DB).invariants() else: abtuple = quaternion_algebra_invariants_from_ramification( F, DB, ramification_at_infinity, magma=magma) G = BigArithGroup(P, abtuple, Np, base=F, outfile=outfile, seed=magma_seed, use_sage_db=use_sage_db, magma=magma, use_shapiro=use_shapiro, nscartan=Ncartan) # Define the cycle ( in H_1(G,Div^0 Hp) ) Coh = ArithCoh(G) while True: try: cycleGn, nn, ell = construct_homology_cycle( p, G.Gn, beta, working_prec, lambda q: Coh.hecke_matrix(q).minpoly(), outfile=outfile, elliptic_curve=E) break except PrecisionError: working_prec *= 2 verbose( 'Encountered precision error, trying with higher precision (= %s)' % working_prec) except ValueError: fwrite( 'ValueError occurred when constructing homology cycle. Returning the S-arithmetic group.', outfile) if quit_when_done: magma.quit() return G except AssertionError as e: fwrite( 'Assertion occurred when constructing homology cycle. Returning the S-arithmetic group.', outfile) fwrite('%s' % str(e), outfile) if quit_when_done: magma.quit() return G eisenstein_constant = -ZZ(E.reduction(ell).count_points()) fwrite( 'r = %s, so a_r(E) - r - 1 = %s' % (ell, eisenstein_constant), outfile) fwrite('exponent = %s' % nn, outfile) phiE = Coh.get_cocycle_from_elliptic_curve(E, sign=sign_at_infinity) if hasattr(E, 'ap'): sign_ap = E.ap(P) else: try: sign_ap = ZZ(P.norm() + 1 - E.reduction(P).count_points()) except ValueError: sign_ap = ZZ(P.norm() + 1 - Curve(E).change_ring( P.residue_field()).count_points(1)[0]) Phi = get_overconvergent_class_quaternionic( P, phiE, G, prec, sign_at_infinity, sign_ap, use_ps_dists=use_ps_dists, use_sage_db=use_sage_db, parallelize=parallelize, method=Up_method, progress_bar=progress_bar, Ename=Ename) # Integration with moments tot_time = walltime() J = integrate_H1(G, cycleGn, Phi, 1, method='moments', prec=working_prec, parallelize=parallelize, twist=True, progress_bar=progress_bar) verbose('integration tot_time = %s' % walltime(tot_time)) if use_sage_db: G.save_to_db() else: # not cohomological nn = 1 eisenstein_constant = 1 if algorithm is None: if Np == 1: algorithm = 'darmon_pollack' else: algorithm = 'guitart_masdeu' w = K.maximal_order().ring_generators()[0] r0, r1 = w.coordinates_in_terms_of_powers()(K.gen()) QQp = Qp(p, working_prec) Cp = QQp.extension(w.minpoly().change_ring(QQp), names='g') v0 = K.hom([r0 + r1 * Cp.gen()]) # Optimal embeddings of level one fwrite("Computing optimal embeddings of level one...", outfile) Wlist = find_optimal_embeddings(K, use_magma=use_magma, extra_conductor=extra_conductor) fwrite("Found %s such embeddings." % len(Wlist), outfile) if idx_embedding is not None: if idx_embedding >= len(Wlist): fwrite( 'There are not enough embeddings. Taking the index modulo %s' % len(Wlist), outfile) idx_embedding = idx_embedding % len(Wlist) fwrite('Taking only embedding number %s' % (idx_embedding), outfile) Wlist = [Wlist[idx_embedding]] # Find the orientations orients = K.maximal_order().ring_generators()[0].minpoly().roots( Zmod(Np), multiplicities=False) fwrite("Possible orientations: %s" % orients, outfile) if len(Wlist) == 1 or idx_orientation == -1: fwrite("Using all orientations, since hK = 1", outfile) chosen_orientation = None else: fwrite("Using orientation = %s" % orients[idx_orientation], outfile) chosen_orientation = orients[idx_orientation] emblist = [] for i, W in enumerate(Wlist): tau, gtau, sign, limits = find_tau0_and_gtau( v0, Np, W, algorithm=algorithm, orientation=chosen_orientation, extra_conductor=extra_conductor) fwrite( 'n_evals = %s' % sum( (num_evals(t1, t2) for t1, t2 in limits)), outfile) emblist.append((tau, gtau, sign, limits)) # Get the cohomology class from E Phi = get_overconvergent_class_matrices(P, E, prec, sign_at_infinity, use_ps_dists=use_ps_dists, use_sage_db=use_sage_db, parallelize=parallelize, progress_bar=progress_bar) J = 1 Jlist = [] for i, emb in enumerate(emblist): fwrite( "Computing %s-th period, attached to the embedding: %s" % (i, Wlist[i].list()), outfile) tau, gtau, sign, limits = emb n_evals = sum((num_evals(t1, t2) for t1, t2 in limits)) fwrite( "Computing one period...(total of %s evaluations)" % n_evals, outfile) newJ = prod((double_integral_zero_infty(Phi, t1, t2) for t1, t2 in limits))**ZZ(sign) Jlist.append(newJ) J *= newJ else: # input_data is not None Phi, J = input_data[1:3] fwrite('Integral done. Now trying to recognize the point', outfile) fwrite('J_psi = %s' % J, outfile) fwrite('g belongs to %s' % J.parent(), outfile) #Try to recognize a generator if quaternionic: local_embedding = G.base_ring_local_embedding(working_prec) twopowlist = [ 4, 3, 2, 1, QQ(1) / 2, QQ(3) / 2, QQ(1) / 3, QQ(2) / 3, QQ(1) / 4, QQ(3) / 4, QQ(5) / 2, QQ(4) / 3 ] else: local_embedding = Qp(p, working_prec) twopowlist = [ 4, 3, 2, 1, QQ(1) / 2, QQ(3) / 2, QQ(1) / 3, QQ(2) / 3, QQ(1) / 4, QQ(3) / 4, QQ(5) / 2, QQ(4) / 3 ] known_multiple = QQ( nn * eisenstein_constant ) # It seems that we are not getting it with present algorithm. while known_multiple % p == 0: known_multiple = ZZ(known_multiple / p) if not recognize_point: fwrite('known_multiple = %s' % known_multiple, outfile) if quit_when_done: magma.quit() return J, Jlist candidate, twopow, J1 = recognize_J(E, J, K, local_embedding=local_embedding, known_multiple=known_multiple, twopowlist=twopowlist, prec=prec, outfile=outfile) if candidate is not None: HCF = K.hilbert_class_field(names='r1') if hK > 1 else K if hK == 1: try: verbose('candidate = %s' % candidate) Ptsmall = E.change_ring(HCF)(candidate) fwrite('twopow = %s' % twopow, outfile) fwrite( 'Computed point: %s * %s * %s' % (twopow, known_multiple, Ptsmall), outfile) fwrite('(first factor is not understood, second factor is)', outfile) fwrite( '(r satisfies %s = 0)' % (Ptsmall[0].parent().gen().minpoly()), outfile) fwrite('================================================', outfile) if quit_when_done: magma.quit() return Ptsmall except (TypeError, ValueError): verbose("Could not recognize the point.") else: verbose('candidate = %s' % candidate) fwrite('twopow = %s' % twopow, outfile) fwrite( 'Computed point: %s * %s * (x,y)' % (twopow, known_multiple), outfile) fwrite('(first factor is not understood, second factor is)', outfile) try: pols = [HCF(c).relative_minpoly() for c in candidate[:2]] except AttributeError: pols = [HCF(c).minpoly() for c in candidate[:2]] fwrite('Where x satisfies %s' % pols[0], outfile) fwrite('and y satisfies %s' % pols[1], outfile) fwrite('================================================', outfile) if quit_when_done: magma.quit() return candidate else: fwrite('================================================', outfile) if quit_when_done: magma.quit() return []
def MacMahonOmega(var, expression, denominator=None, op=operator.ge, Factorization_sort=False, Factorization_simplify=True): r""" Return `\Omega_{\mathrm{op}}` of ``expression`` with respect to ``var``. To be more precise, calculate .. MATH:: \Omega_{\mathrm{op}} \frac{n}{d_1 \dots d_n} for the numerator `n` and the factors `d_1`, ..., `d_n` of the denominator, all of which are Laurent polynomials in ``var`` and return a (partial) factorization of the result. INPUT: - ``var`` -- a variable or a representation string of a variable - ``expression`` -- a :class:`~sage.structure.factorization.Factorization` of Laurent polynomials or, if ``denominator`` is specified, a Laurent polynomial interpreted as the numerator of the expression - ``denominator`` -- a Laurent polynomial or a :class:`~sage.structure.factorization.Factorization` (consisting of Laurent polynomial factors) or a tuple/list of factors (Laurent polynomials) - ``op`` -- (default: ``operator.ge``) an operator At the moment only ``operator.ge`` is implemented. - ``Factorization_sort`` (default: ``False``) and ``Factorization_simplify`` (default: ``True``) -- are passed on to :class:`sage.structure.factorization.Factorization` when creating the result OUTPUT: A (partial) :class:`~sage.structure.factorization.Factorization` of the result whose factors are Laurent polynomials .. NOTE:: The numerator of the result may not be factored. REFERENCES: - [Mac1915]_ - [APR2001]_ EXAMPLES:: sage: L.<mu, x, y, z, w> = LaurentPolynomialRing(ZZ) sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu]) 1 * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu, 1 - z/mu]) 1 * (-x + 1)^-1 * (-x*y + 1)^-1 * (-x*z + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y*mu, 1 - z/mu]) (-x*y*z + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-x*z + 1)^-1 * (-y*z + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu^2]) 1 * (-x + 1)^-1 * (-x^2*y + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^2, 1 - y/mu]) (x*y + 1) * (-x + 1)^-1 * (-x*y^2 + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y*mu, 1 - z/mu^2]) (-x^2*y*z - x*y^2*z + x*y*z + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-x^2*z + 1)^-1 * (-y^2*z + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu^3]) 1 * (-x + 1)^-1 * (-x^3*y + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y/mu^4]) 1 * (-x + 1)^-1 * (-x^4*y + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^3, 1 - y/mu]) (x*y^2 + x*y + 1) * (-x + 1)^-1 * (-x*y^3 + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^4, 1 - y/mu]) (x*y^3 + x*y^2 + x*y + 1) * (-x + 1)^-1 * (-x*y^4 + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^2, 1 - y/mu, 1 - z/mu]) (x*y*z + x*y + x*z + 1) * (-x + 1)^-1 * (-x*y^2 + 1)^-1 * (-x*z^2 + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu^2, 1 - y*mu, 1 - z/mu]) (-x*y*z^2 - x*y*z + x*z + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-x*z^2 + 1)^-1 * (-y*z + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y*mu, 1 - z*mu, 1 - w/mu]) (x*y*z*w^2 + x*y*z*w - x*y*w - x*z*w - y*z*w + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-z + 1)^-1 * (-x*w + 1)^-1 * (-y*w + 1)^-1 * (-z*w + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - y*mu, 1 - z/mu, 1 - w/mu]) (x^2*y*z*w + x*y^2*z*w - x*y*z*w - x*y*z - x*y*w + 1) * (-x + 1)^-1 * (-y + 1)^-1 * (-x*z + 1)^-1 * (-x*w + 1)^-1 * (-y*z + 1)^-1 * (-y*w + 1)^-1 sage: MacMahonOmega(mu, mu^-2, [1 - x*mu, 1 - y/mu]) x^2 * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^-1, [1 - x*mu, 1 - y/mu]) x * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu, [1 - x*mu, 1 - y/mu]) (-x*y + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2, [1 - x*mu, 1 - y/mu]) (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 We demonstrate the different allowed input variants:: sage: MacMahonOmega(mu, ....: Factorization([(mu, 2), (1 - x*mu, -1), (1 - y/mu, -1)])) (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2, ....: Factorization([(1 - x*mu, 1), (1 - y/mu, 1)])) (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2, [1 - x*mu, 1 - y/mu]) (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2, (1 - x*mu)*(1 - y/mu)) # not tested because not fully implemented (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 sage: MacMahonOmega(mu, mu^2 / ((1 - x*mu)*(1 - y/mu))) # not tested because not fully implemented (-x*y^2 - x*y + y^2 + y + 1) * (-x + 1)^-1 * (-x*y + 1)^-1 TESTS:: sage: MacMahonOmega(mu, 1, [1 - x*mu]) 1 * (-x + 1)^-1 sage: MacMahonOmega(mu, 1, [1 - x/mu]) 1 sage: MacMahonOmega(mu, 0, [1 - x*mu]) 0 sage: MacMahonOmega(mu, L(1), []) 1 sage: MacMahonOmega(mu, L(0), []) 0 sage: MacMahonOmega(mu, 2, []) 2 sage: MacMahonOmega(mu, 2*mu, []) 2 sage: MacMahonOmega(mu, 2/mu, []) 0 :: sage: MacMahonOmega(mu, Factorization([(1/mu, 1), (1 - x*mu, -1), ....: (1 - y/mu, -2)], unit=2)) 2*x * (-x + 1)^-1 * (-x*y + 1)^-2 sage: MacMahonOmega(mu, Factorization([(mu, -1), (1 - x*mu, -1), ....: (1 - y/mu, -2)], unit=2)) 2*x * (-x + 1)^-1 * (-x*y + 1)^-2 sage: MacMahonOmega(mu, Factorization([(mu, -1), (1 - x, -1)])) 0 sage: MacMahonOmega(mu, Factorization([(2, -1)])) 1 * 2^-1 :: sage: MacMahonOmega(mu, 1, [1 - x*mu, 1 - z, 1 - y/mu]) 1 * (-z + 1)^-1 * (-x + 1)^-1 * (-x*y + 1)^-1 :: sage: MacMahonOmega(mu, 1, [1 - x*mu], op=operator.lt) Traceback (most recent call last): ... NotImplementedError: At the moment, only Omega_ge is implemented. sage: MacMahonOmega(mu, 1, Factorization([(1 - x*mu, -1)])) Traceback (most recent call last): ... ValueError: Factorization (-mu*x + 1)^-1 of the denominator contains negative exponents. sage: MacMahonOmega(2*mu, 1, [1 - x*mu]) Traceback (most recent call last): ... ValueError: 2*mu is not a variable. sage: MacMahonOmega(mu, 1, Factorization([(0, 2)])) Traceback (most recent call last): ... ZeroDivisionError: Denominator contains a factor 0. sage: MacMahonOmega(mu, 1, [2 - x*mu]) Traceback (most recent call last): ... NotImplementedError: Factor 2 - x*mu is not normalized. sage: MacMahonOmega(mu, 1, [1 - x*mu - mu^2]) Traceback (most recent call last): ... NotImplementedError: Cannot handle factor 1 - x*mu - mu^2. :: sage: L.<mu, x, y, z, w> = LaurentPolynomialRing(QQ) sage: MacMahonOmega(mu, 1/mu, ....: Factorization([(1 - x*mu, 1), (1 - y/mu, 2)], unit=2)) 1/2*x * (-x + 1)^-1 * (-x*y + 1)^-2 """ from sage.arith.misc import factor from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring \ import LaurentPolynomialRing, LaurentPolynomialRing_univariate from sage.structure.factorization import Factorization if op != operator.ge: raise NotImplementedError('At the moment, only Omega_ge is implemented.') if denominator is None: if isinstance(expression, Factorization): numerator = expression.unit() * \ prod(f**e for f, e in expression if e > 0) denominator = tuple(f for f, e in expression if e < 0 for _ in range(-e)) else: numerator = expression.numerator() denominator = expression.denominator() else: numerator = expression # at this point we have numerator/denominator if isinstance(denominator, (list, tuple)): factors_denominator = denominator else: if not isinstance(denominator, Factorization): denominator = factor(denominator) if not denominator.is_integral(): raise ValueError('Factorization {} of the denominator ' 'contains negative exponents.'.format(denominator)) numerator *= ZZ(1) / denominator.unit() factors_denominator = tuple(factor for factor, exponent in denominator for _ in range(exponent)) # at this point we have numerator/factors_denominator P = var.parent() if isinstance(P, LaurentPolynomialRing_univariate) and P.gen() == var: L = P L0 = L.base_ring() elif var in P.gens(): var = repr(var) L0 = LaurentPolynomialRing( P.base_ring(), tuple(v for v in P.variable_names() if v != var)) L = LaurentPolynomialRing(L0, var) var = L.gen() else: raise ValueError('{} is not a variable.'.format(var)) other_factors = [] to_numerator = [] decoded_factors = [] for factor in factors_denominator: factor = L(factor) D = factor.dict() if not D: raise ZeroDivisionError('Denominator contains a factor 0.') elif len(D) == 1: exponent, coefficient = next(iteritems(D)) if exponent == 0: other_factors.append(L0(factor)) else: to_numerator.append(factor) elif len(D) == 2: if D.get(0, 0) != 1: raise NotImplementedError('Factor {} is not normalized.'.format(factor)) D.pop(0) exponent, coefficient = next(iteritems(D)) decoded_factors.append((-coefficient, exponent)) else: raise NotImplementedError('Cannot handle factor {}.'.format(factor)) numerator = L(numerator) / prod(to_numerator) result_numerator, result_factors_denominator = \ _Omega_(numerator.dict(), decoded_factors) if result_numerator == 0: return Factorization([], unit=result_numerator) return Factorization([(result_numerator, 1)] + list((f, -1) for f in other_factors) + list((1-f, -1) for f in result_factors_denominator), sort=Factorization_sort, simplify=Factorization_simplify)
def darmon_point(P, E, beta, prec, ramification_at_infinity = None, input_data = None, magma = None, working_prec = None, **kwargs): r''' EXAMPLES: We first need to import the module:: sage: from darmonpoints.darmonpoints import darmon_point A first example (Stark--Heegner point):: sage: from darmonpoints.darmonpoints import darmon_point sage: darmon_point(7,EllipticCurve('35a1'),41,20, cohomological=False, use_magma=False, use_ps_dists = True) Starting computation of the Darmon point ... (-70*alpha + 449 : 2100*alpha - 13444 : 1) A quaternionic (Greenberg) point:: sage: darmon_point(13,EllipticCurve('78a1'),5,20) # long time # optional - magma A Darmon point over a cubic (1,1) field:: sage: F.<r> = NumberField(x^3 - x^2 - x + 2) sage: E = EllipticCurve([-r -1, -r, -r - 1,-r - 1, 0]) sage: N = E.conductor() sage: P = F.ideal(r^2 - 2*r - 1) sage: beta = -3*r^2 + 9*r - 6 sage: darmon_point(P,E,beta,20) # long time # optional - magma ''' # global G, Coh, phiE, Phi, dK, J, J1, cycleGn, nn, Jlist config = ConfigParser.ConfigParser() config.read('config.ini') param_dict = config_section_map(config, 'General') param_dict.update(config_section_map(config, 'DarmonPoint')) param_dict.update(kwargs) param = Bunch(**param_dict) # Get general parameters outfile = param.get('outfile') use_ps_dists = param.get('use_ps_dists',False) use_shapiro = param.get('use_shapiro',True) use_sage_db = param.get('use_sage_db',False) magma_seed = param.get('magma_seed',1515316) parallelize = param.get('parallelize',False) Up_method = param.get('up_method','naive') use_magma = param.get('use_magma',True) progress_bar = param.get('progress_bar',True) sign_at_infinity = param.get('sign_at_infinity',ZZ(1)) # Get darmon_point specific parameters idx_orientation = param.get('idx_orientation') idx_embedding = param.get('idx_embedding',0) algorithm = param.get('algorithm') quaternionic = param.get('quaternionic') cohomological = param.get('cohomological',True) if Up_method == "bigmatrix" and use_shapiro == True: import warnings warnings.warn('Use of "bigmatrix" for Up iteration is incompatible with Shapiro Lemma trick. Using "naive" method for Up.') Up_method = 'naive' if working_prec is None: working_prec = max([2 * prec + 10, 30]) if use_magma: page_path = os.path.dirname(__file__) + '/KleinianGroups-1.0/klngpspec' if magma is None: from sage.interfaces.magma import Magma magma = Magma() quit_when_done = True else: quit_when_done = False magma.attach_spec(page_path) else: quit_when_done = False sys.setrecursionlimit(10**6) F = E.base_ring() beta = F(beta) DB,Np,Ncartan = get_heegner_params(P,E,beta) if quaternionic is None: quaternionic = ( DB != 1 ) if cohomological is None: cohomological = quaternionic if quaternionic and not cohomological: raise ValueError("Need cohomological algorithm when dealing with quaternions") if use_ps_dists is None: use_ps_dists = False if cohomological else True try: p = ZZ(P) except TypeError: p = ZZ(P.norm()) if not p.is_prime(): raise ValueError,'P (= %s) should be a prime, of inertia degree 1'%P if F == QQ: dK = ZZ(beta) extra_conductor_sq = dK/fundamental_discriminant(dK) assert ZZ(extra_conductor_sq).is_square() extra_conductor = extra_conductor_sq.sqrt() dK = dK / extra_conductor_sq assert dK == fundamental_discriminant(dK) if dK % 4 == 0: dK = ZZ(dK/4) beta = dK else: dK = beta # Compute the completion of K at p x = QQ['x'].gen() K = F.extension(x*x - dK,names = 'alpha') if F == QQ: dK = K.discriminant() else: dK = K.relative_discriminant() hK = K.class_number() sgninfty = 'plus' if sign_at_infinity == 1 else 'minus' if hasattr(E,'cremona_label'): Ename = E.cremona_label() elif hasattr(E,'ainvs'): Ename = E.ainvs() else: Ename = 'unknown' fname = 'moments_%s_%s_%s_%s.sobj'%(P,Ename,sgninfty,prec) if use_sage_db: print("Moments will be stored in database as %s"%(fname)) if outfile == 'log': outfile = '%s_%s_%s_%s_%s_%s.log'%(P,Ename,dK,sgninfty,prec,datetime.datetime.now().strftime("%Y%m%d-%H%M%S")) outfile = outfile.replace('/','div') outfile = '/tmp/darmonpoint_' + outfile fwrite("Starting computation of the Darmon point",outfile) fwrite('D_B = %s %s'%(DB,factor(DB)),outfile) fwrite('Np = %s'%Np,outfile) if Ncartan is not None: fwrite('Ncartan = %s'%Ncartan,outfile) fwrite('dK = %s (class number = %s)'%(dK,hK),outfile) fwrite('Calculation with p = %s and prec = %s'%(P,prec),outfile) fwrite('Elliptic curve %s: %s'%(Ename,E),outfile) if outfile is not None: print("Partial results will be saved in %s"%outfile) if input_data is None: if cohomological: # Define the S-arithmetic group if F != QQ and ramification_at_infinity is None: if F.signature()[0] > 1: if F.signature()[1] == 1: ramification_at_infinity = F.real_places(prec = Infinity) # Totally 'definite' else: raise ValueError,'Please specify the ramification at infinity' elif F.signature()[0] == 1: if len(F.ideal(DB).factor()) % 2 == 0: ramification_at_infinity = [] # Split at infinity else: ramification_at_infinity = F.real_places(prec = Infinity) # Ramified at infinity else: ramification_at_infinity = None if F == QQ: abtuple = QuaternionAlgebra(DB).invariants() else: abtuple = quaternion_algebra_invariants_from_ramification(F, DB, ramification_at_infinity) G = BigArithGroup(P,abtuple,Np,base = F,outfile = outfile,seed = magma_seed,use_sage_db = use_sage_db,magma = magma, use_shapiro = use_shapiro, nscartan=Ncartan) # Define the cycle ( in H_1(G,Div^0 Hp) ) Coh = ArithCoh(G) while True: try: cycleGn,nn,ell = construct_homology_cycle(G,beta,working_prec,lambda q: Coh.hecke_matrix(q).minpoly(), outfile = outfile, elliptic_curve = E) break except PrecisionError: working_prec *= 2 verbose('Encountered precision error, trying with higher precision (= %s)'%working_prec) except ValueError: fwrite('ValueError occurred when constructing homology cycle. Returning the S-arithmetic group.', outfile) if quit_when_done: magma.quit() return G except AssertionError as e: fwrite('Assertion occurred when constructing homology cycle. Returning the S-arithmetic group.', outfile) fwrite('%s'%str(e), outfile) if quit_when_done: magma.quit() return G eisenstein_constant = -ZZ(E.reduction(ell).count_points()) fwrite('r = %s, so a_r(E) - r - 1 = %s'%(ell,eisenstein_constant), outfile) fwrite('exponent = %s'%nn, outfile) phiE = Coh.get_cocycle_from_elliptic_curve(E, sign = sign_at_infinity) if hasattr(E,'ap'): sign_ap = E.ap(P) else: try: sign_ap = ZZ(P.norm() + 1 - E.reduction(P).count_points()) except ValueError: sign_ap = ZZ(P.norm() + 1 - Curve(E).change_ring(P.residue_field()).count_points(1)[0]) Phi = get_overconvergent_class_quaternionic(P,phiE,G,prec,sign_at_infinity,sign_ap,use_ps_dists = use_ps_dists,use_sage_db = use_sage_db,parallelize = parallelize,method = Up_method, progress_bar = progress_bar,Ename = Ename) # Integration with moments tot_time = walltime() J = integrate_H1(G,cycleGn,Phi,1,method = 'moments',prec = working_prec,parallelize = parallelize,twist = True,progress_bar = progress_bar) verbose('integration tot_time = %s'%walltime(tot_time)) if use_sage_db: G.save_to_db() else: # not cohomological nn = 1 eisenstein_constant = 1 if algorithm is None: if Np == 1: algorithm = 'darmon_pollack' else: algorithm = 'guitart_masdeu' w = K.maximal_order().ring_generators()[0] r0,r1 = w.coordinates_in_terms_of_powers()(K.gen()) QQp = Qp(p,working_prec) Cp = QQp.extension(w.minpoly().change_ring(QQp),names = 'g') v0 = K.hom([r0 + r1 * Cp.gen()]) # Optimal embeddings of level one fwrite("Computing optimal embeddings of level one...", outfile) Wlist = find_optimal_embeddings(K,use_magma = use_magma, extra_conductor = extra_conductor) fwrite("Found %s such embeddings."%len(Wlist), outfile) if idx_embedding is not None: if idx_embedding >= len(Wlist): fwrite('There are not enough embeddings. Taking the index modulo %s'%len(Wlist), outfile) idx_embedding = idx_embedding % len(Wlist) fwrite('Taking only embedding number %s'%(idx_embedding), outfile) Wlist = [Wlist[idx_embedding]] # Find the orientations orients = K.maximal_order().ring_generators()[0].minpoly().roots(Zmod(Np),multiplicities = False) fwrite("Possible orientations: %s"%orients, outfile) if len(Wlist) == 1 or idx_orientation == -1: fwrite("Using all orientations, since hK = 1", outfile) chosen_orientation = None else: fwrite("Using orientation = %s"%orients[idx_orientation], outfile) chosen_orientation = orients[idx_orientation] emblist = [] for i,W in enumerate(Wlist): tau, gtau,sign,limits = find_tau0_and_gtau(v0,Np,W,algorithm = algorithm,orientation = chosen_orientation,extra_conductor = extra_conductor) fwrite('n_evals = %s'%sum((num_evals(t1,t2) for t1,t2 in limits)), outfile) emblist.append((tau,gtau,sign,limits)) # Get the cohomology class from E Phi = get_overconvergent_class_matrices(P,E,prec,sign_at_infinity,use_ps_dists = use_ps_dists,use_sage_db = use_sage_db,parallelize = parallelize,progress_bar = progress_bar) J = 1 Jlist = [] for i,emb in enumerate(emblist): fwrite("Computing %s-th period, attached to the embedding: %s"%(i,Wlist[i].list()), outfile) tau, gtau,sign,limits = emb n_evals = sum((num_evals(t1,t2) for t1,t2 in limits)) fwrite("Computing one period...(total of %s evaluations)"%n_evals, outfile) newJ = prod((double_integral_zero_infty(Phi,t1,t2) for t1,t2 in limits))**ZZ(sign) Jlist.append(newJ) J *= newJ else: # input_data is not None Phi,J = input_data[1:3] fwrite('Integral done. Now trying to recognize the point', outfile) fwrite('J_psi = %s'%J,outfile) fwrite('g belongs to %s'%J.parent(),outfile) #Try to recognize a generator if quaternionic: local_embedding = G.base_ring_local_embedding(working_prec) twopowlist = [4, 3, 2, 1, QQ(1)/2, QQ(3)/2, QQ(1)/3, QQ(2)/3, QQ(1)/4, QQ(3)/4, QQ(5)/2, QQ(4)/3] else: local_embedding = Qp(p,working_prec) twopowlist = [4, 3, 2, 1, QQ(1)/2, QQ(3)/2, QQ(1)/3, QQ(2)/3, QQ(1)/4, QQ(3)/4, QQ(5)/2, QQ(4)/3] known_multiple = QQ(nn * eisenstein_constant) # It seems that we are not getting it with present algorithm. while known_multiple % p == 0: known_multiple = ZZ(known_multiple / p) candidate,twopow,J1 = recognize_J(E,J,K,local_embedding = local_embedding,known_multiple = known_multiple,twopowlist = twopowlist,prec = prec, outfile = outfile) if candidate is not None: HCF = K.hilbert_class_field(names = 'r1') if hK > 1 else K if hK == 1: try: verbose('candidate = %s'%candidate) Ptsmall = E.change_ring(HCF)(candidate) fwrite('twopow = %s'%twopow,outfile) fwrite('Computed point: %s * %s * %s'%(twopow,known_multiple,Ptsmall),outfile) fwrite('(first factor is not understood, second factor is)',outfile) fwrite('(r satisfies %s = 0)'%(Ptsmall[0].parent().gen().minpoly()),outfile) fwrite('================================================',outfile) if quit_when_done: magma.quit() return Ptsmall except (TypeError,ValueError): verbose("Could not recognize the point.") else: verbose('candidate = %s'%candidate) fwrite('twopow = %s'%twopow,outfile) fwrite('Computed point: %s * %s * (x,y)'%(twopow,known_multiple),outfile) fwrite('(first factor is not understood, second factor is)',outfile) try: pols = [HCF(c).relative_minpoly() for c in candidate[:2]] except AttributeError: pols = [HCF(c).minpoly() for c in candidate[:2]] fwrite('Where x satisfies %s'%pols[0],outfile) fwrite('and y satisfies %s'%pols[1],outfile) fwrite('================================================',outfile) if quit_when_done: magma.quit() return candidate else: fwrite('================================================',outfile) if quit_when_done: magma.quit() return []