def enum_projective_rational_field(X, B): r""" Enumerates projective, rational points on scheme ``X`` of height up to bound ``B``. INPUT: - ``X`` - a scheme or set of abstract rational points of a scheme. - ``B`` - a positive integer bound. OUTPUT: - a list containing the projective points of ``X`` of height up to ``B``, sorted. EXAMPLES:: sage: P.<X,Y,Z> = ProjectiveSpace(2, QQ) sage: C = P.subscheme([X+Y-Z]) sage: from sage.schemes.projective.projective_rational_point import enum_projective_rational_field sage: enum_projective_rational_field(C(QQ), 6) [(-5 : 6 : 1), (-4 : 5 : 1), (-3 : 4 : 1), (-2 : 3 : 1), (-3/2 : 5/2 : 1), (-1 : 1 : 0), (-1 : 2 : 1), (-2/3 : 5/3 : 1), (-1/2 : 3/2 : 1), (-1/3 : 4/3 : 1), (-1/4 : 5/4 : 1), (-1/5 : 6/5 : 1), (0 : 1 : 1), (1/6 : 5/6 : 1), (1/5 : 4/5 : 1), (1/4 : 3/4 : 1), (1/3 : 2/3 : 1), (2/5 : 3/5 : 1), (1/2 : 1/2 : 1), (3/5 : 2/5 : 1), (2/3 : 1/3 : 1), (3/4 : 1/4 : 1), (4/5 : 1/5 : 1), (5/6 : 1/6 : 1), (1 : 0 : 1), (6/5 : -1/5 : 1), (5/4 : -1/4 : 1), (4/3 : -1/3 : 1), (3/2 : -1/2 : 1), (5/3 : -2/3 : 1), (2 : -1 : 1), (5/2 : -3/2 : 1), (3 : -2 : 1), (4 : -3 : 1), (5 : -4 : 1), (6 : -5 : 1)] sage: enum_projective_rational_field(C,6) == enum_projective_rational_field(C(QQ),6) True :: sage: P3.<W,X,Y,Z> = ProjectiveSpace(3, QQ) sage: enum_projective_rational_field(P3, 1) [(-1 : -1 : -1 : 1), (-1 : -1 : 0 : 1), (-1 : -1 : 1 : 0), (-1 : -1 : 1 : 1), (-1 : 0 : -1 : 1), (-1 : 0 : 0 : 1), (-1 : 0 : 1 : 0), (-1 : 0 : 1 : 1), (-1 : 1 : -1 : 1), (-1 : 1 : 0 : 0), (-1 : 1 : 0 : 1), (-1 : 1 : 1 : 0), (-1 : 1 : 1 : 1), (0 : -1 : -1 : 1), (0 : -1 : 0 : 1), (0 : -1 : 1 : 0), (0 : -1 : 1 : 1), (0 : 0 : -1 : 1), (0 : 0 : 0 : 1), (0 : 0 : 1 : 0), (0 : 0 : 1 : 1), (0 : 1 : -1 : 1), (0 : 1 : 0 : 0), (0 : 1 : 0 : 1), (0 : 1 : 1 : 0), (0 : 1 : 1 : 1), (1 : -1 : -1 : 1), (1 : -1 : 0 : 1), (1 : -1 : 1 : 0), (1 : -1 : 1 : 1), (1 : 0 : -1 : 1), (1 : 0 : 0 : 0), (1 : 0 : 0 : 1), (1 : 0 : 1 : 0), (1 : 0 : 1 : 1), (1 : 1 : -1 : 1), (1 : 1 : 0 : 0), (1 : 1 : 0 : 1), (1 : 1 : 1 : 0), (1 : 1 : 1 : 1)] ALGORITHM: We just check all possible projective points in correct dimension of projective space to see if they lie on ``X``. AUTHORS: - John Cremona and Charlie Turner (06-2010) """ from sage.schemes.projective.projective_space import is_ProjectiveSpace if (is_Scheme(X)): if (not is_ProjectiveSpace(X.ambient_space())): raise TypeError( "ambient space must be projective space over the rational field" ) X = X(X.base_ring()) else: if (not is_ProjectiveSpace(X.codomain().ambient_space())): raise TypeError( "codomain must be projective space over the rational field") n = X.codomain().ambient_space().ngens() zero = (0, ) * n pts = [] for c in cartesian_product_iterator([srange(-B, B + 1) for _ in range(n)]): if gcd(c) == 1 and c > zero: try: pts.append(X(c)) except TypeError: pass pts.sort() return pts
def _Omega_numerator_(a, x, y, t): r""" Return the numerator of `\Omega_{\ge}` of the expression specified by the input. To be more precise, calculate .. MATH:: \Omega_{\ge} \frac{\mu^a}{ (1 - x_1 \mu) \dots (1 - x_n \mu) (1 - y_1 / \mu) \dots (1 - y_m / \mu)} and return its numerator. This function is meant to be a helper function of :func:`MacMahonOmega`. INPUT: - ``a`` -- an integer - ``x`` and ``y`` -- a tuple of tuples of Laurent polynomials The flattened ``x`` contains `x_1,...,x_n`, the flattened ``y`` the `y_1,...,y_m`. The non-flatness of these parameters is to be interface-consistent with :func:`_Omega_factors_denominator_`. - ``t`` -- a temporary Laurent polynomial variable used for substituting OUTPUT: A Laurent polynomial The output is normalized such that the corresponding denominator (:func:`_Omega_factors_denominator_`) has constant term `1`. EXAMPLES:: sage: from sage.rings.polynomial.omega import _Omega_numerator_, _Omega_factors_denominator_ sage: L.<x0, x1, x2, x3, y0, y1, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_(0, ((x0,),), ((y0,),), t) 1 sage: _Omega_numerator_(0, ((x0,), (x1,)), ((y0,),), t) -x0*x1*y0 + 1 sage: _Omega_numerator_(0, ((x0,),), ((y0,), (y1,)), t) 1 sage: _Omega_numerator_(0, ((x0,), (x1,), (x2,)), ((y0,),), t) x0*x1*x2*y0^2 + x0*x1*x2*y0 - x0*x1*y0 - x0*x2*y0 - x1*x2*y0 + 1 sage: _Omega_numerator_(0, ((x0,), (x1,)), ((y0,), (y1,)), t) x0^2*x1*y0*y1 + x0*x1^2*y0*y1 - x0*x1*y0*y1 - x0*x1*y0 - x0*x1*y1 + 1 sage: _Omega_numerator_(-2, ((x0,),), ((y0,),), t) x0^2 sage: _Omega_numerator_(-1, ((x0,),), ((y0,),), t) x0 sage: _Omega_numerator_(1, ((x0,),), ((y0,),), t) -x0*y0 + y0 + 1 sage: _Omega_numerator_(2, ((x0,),), ((y0,),), t) -x0*y0^2 - x0*y0 + y0^2 + y0 + 1 TESTS:: sage: _Omega_factors_denominator_((), ()) () sage: _Omega_numerator_(0, (), (), t) 1 sage: _Omega_numerator_(+2, (), (), t) 1 sage: _Omega_numerator_(-2, (), (), t) 0 sage: _Omega_factors_denominator_(((x0,),), ()) (-x0 + 1,) sage: _Omega_numerator_(0, ((x0,),), (), t) 1 sage: _Omega_numerator_(+2, ((x0,),), (), t) 1 sage: _Omega_numerator_(-2, ((x0,),), (), t) x0^2 sage: _Omega_factors_denominator_((), ((y0,),)) () sage: _Omega_numerator_(0, (), ((y0,),), t) 1 sage: _Omega_numerator_(+2, (), ((y0,),), t) y0^2 + y0 + 1 sage: _Omega_numerator_(-2, (), ((y0,),), t) 0 :: sage: L.<X, Y, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_(2, ((X,),), ((Y,),), t) -X*Y^2 - X*Y + Y^2 + Y + 1 """ from sage.arith.srange import srange from sage.misc.misc_c import prod x_flat = sum(x, tuple()) y_flat = sum(y, tuple()) n = len(x_flat) m = len(y_flat) xy = x_flat + y_flat import logging logger = logging.getLogger(__name__) logger.info('Omega_numerator: a=%s, n=%s, m=%s', a, n, m) if m == 0: result = 1 - (prod(_Omega_factors_denominator_(x, y)) * sum( homogenous_symmetric_function(j, xy) for j in srange(-a)) if a < 0 else 0) elif n == 0: result = sum( homogenous_symmetric_function(j, xy) for j in srange(a + 1)) else: result = _Omega_numerator_P_(a, x_flat[:-1], y_flat, t).subs({t: x_flat[-1]}) L = t.parent() result = L(result) logger.info('_Omega_numerator_: %s terms', result.number_of_terms()) return result
def _Omega_numerator_P_(a, x, y, t): r""" Helper function for :func:`_Omega_numerator_`. This is an implementation of the function `P` of [APR2001]_. INPUT: - ``a`` -- an integer - ``x`` and ``y`` -- a tuple of Laurent polynomials The tuple ``x`` here is the flattened ``x`` of :func:`_Omega_numerator_` but without its last entry. - ``t`` -- a temporary Laurent polynomial variable In the (final) result, ``t`` has to be substituted by the last entry of the flattened ``x`` of :func:`_Omega_numerator_`. OUTPUT: A Laurent polynomial TESTS:: sage: from sage.rings.polynomial.omega import _Omega_numerator_P_ sage: L.<x0, x1, y0, y1, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_P_(0, (x0,), (y0,), t).subs({t: x1}) -x0*x1*y0 + 1 """ # This function takes Laurent polynomials as inputs. It would # be possible to input only the sizes of ``x`` and ``y`` and # perform a substitution afterwards; in this way caching of this # function would make sense. However, the way it is now allows # automatic collection and simplification of the summands, which # makes it more efficient for higher powers at the input of # :func:`Omega_ge`. # Caching occurs in :func:`Omega_ge`. import logging logger = logging.getLogger(__name__) from sage.arith.srange import srange from sage.misc.misc_c import prod n = len(x) if n == 0: x0 = t result = x0**(-a) + \ (prod(1 - x0*yy for yy in y) * sum(homogenous_symmetric_function(j, y) * (1-x0**(j-a)) for j in srange(a)) if a > 0 else 0) else: Pprev = _Omega_numerator_P_(a, x[:n - 1], y, t) x2 = x[n - 1] logger.debug('Omega_numerator: P(%s): substituting...', n) x1 = t p1 = Pprev p2 = Pprev.subs({t: x2}) logger.debug('Omega_numerator: P(%s): preparing...', n) dividend = x1 * (1-x2) * prod(1 - x2*yy for yy in y) * p1 - \ x2 * (1-x1) * prod(1 - x1*yy for yy in y) * p2 logger.debug('Omega_numerator: P(%s): dividing...', n) q, r = dividend.quo_rem(x1 - x2) assert r == 0 result = q logger.debug('Omega_numerator: P(%s) has %s terms', n, result.number_of_terms()) return result
def Omega_ge(a, exponents): r""" Return `\Omega_{\ge}` of the expression specified by the input. To be more precise, calculate .. MATH:: \Omega_{\ge} \frac{\mu^a}{ (1 - z_0 \mu^{e_0}) \dots (1 - z_{n-1} \mu^{e_{n-1}})} and return its numerator and a factorization of its denominator. Note that `z_0`, ..., `z_{n-1}` only appear in the output, but not in the input. INPUT: - ``a`` -- an integer - ``exponents`` -- a tuple of integers OUTPUT: A pair representing a quotient as follows: Its first component is the numerator as a Laurent polynomial, its second component a factorization of the denominator as a tuple of Laurent polynomials, where each Laurent polynomial `z` represents a factor `1 - z`. The parents of these Laurent polynomials is always a Laurent polynomial ring in `z_0`, ..., `z_{n-1}` over `\ZZ`, where `n` is the length of ``exponents``. EXAMPLES:: sage: from sage.rings.polynomial.omega import Omega_ge sage: Omega_ge(0, (1, -2)) (1, (z0, z0^2*z1)) sage: Omega_ge(0, (1, -3)) (1, (z0, z0^3*z1)) sage: Omega_ge(0, (1, -4)) (1, (z0, z0^4*z1)) sage: Omega_ge(0, (2, -1)) (z0*z1 + 1, (z0, z0*z1^2)) sage: Omega_ge(0, (3, -1)) (z0*z1^2 + z0*z1 + 1, (z0, z0*z1^3)) sage: Omega_ge(0, (4, -1)) (z0*z1^3 + z0*z1^2 + z0*z1 + 1, (z0, z0*z1^4)) sage: Omega_ge(0, (1, 1, -2)) (-z0^2*z1*z2 - z0*z1^2*z2 + z0*z1*z2 + 1, (z0, z1, z0^2*z2, z1^2*z2)) sage: Omega_ge(0, (2, -1, -1)) (z0*z1*z2 + z0*z1 + z0*z2 + 1, (z0, z0*z1^2, z0*z2^2)) sage: Omega_ge(0, (2, 1, -1)) (-z0*z1*z2^2 - z0*z1*z2 + z0*z2 + 1, (z0, z1, z0*z2^2, z1*z2)) :: sage: Omega_ge(0, (2, -2)) (-z0*z1 + 1, (z0, z0*z1, z0*z1)) sage: Omega_ge(0, (2, -3)) (z0^2*z1 + 1, (z0, z0^3*z1^2)) sage: Omega_ge(0, (3, 1, -3)) (-z0^3*z1^3*z2^3 + 2*z0^2*z1^3*z2^2 - z0*z1^3*z2 + z0^2*z2^2 - 2*z0*z2 + 1, (z0, z1, z0*z2, z0*z2, z0*z2, z1^3*z2)) :: sage: Omega_ge(0, (3, 6, -1)) (-z0*z1*z2^8 - z0*z1*z2^7 - z0*z1*z2^6 - z0*z1*z2^5 - z0*z1*z2^4 + z1*z2^5 - z0*z1*z2^3 + z1*z2^4 - z0*z1*z2^2 + z1*z2^3 - z0*z1*z2 + z0*z2^2 + z1*z2^2 + z0*z2 + z1*z2 + 1, (z0, z1, z0*z2^3, z1*z2^6)) TESTS:: sage: Omega_ge(0, (2, 2, 1, 1, 1, -1, -1))[0].number_of_terms() # long time 1695 sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # not tested (too long, 1 min) 27837 :: sage: Omega_ge(1, (2,)) (1, (z0,)) """ import logging logger = logging.getLogger(__name__) logger.info('Omega_ge: a=%s, exponents=%s', a, exponents) from sage.arith.all import lcm, srange from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.number_field.number_field import CyclotomicField if not exponents or any(e == 0 for e in exponents): raise NotImplementedError rou = sorted(set(abs(e) for e in exponents) - set([1])) ellcm = lcm(rou) B = CyclotomicField(ellcm, 'zeta') zeta = B.gen() z_names = tuple('z{}'.format(i) for i in range(len(exponents))) L = LaurentPolynomialRing(B, ('t', ) + z_names, len(z_names) + 1) t = L.gens()[0] Z = LaurentPolynomialRing(ZZ, z_names, len(z_names)) powers = {i: L(zeta**(ellcm // i)) for i in rou} powers[2] = L(-1) powers[1] = L(1) exponents_and_values = tuple( (e, tuple(powers[abs(e)]**j * z for j in srange(abs(e)))) for z, e in zip(L.gens()[1:], exponents)) x = tuple(v for e, v in exponents_and_values if e > 0) y = tuple(v for e, v in exponents_and_values if e < 0) def subs_power(expression, var, exponent): r""" Substitute ``var^exponent`` by ``var`` in ``expression``. It is assumed that ``var`` only occurs with exponents divisible by ``exponent``. """ p = tuple(var.dict().popitem()[0]).index( 1) # var is the p-th generator def subs_e(e): e = list(e) assert e[p] % exponent == 0 e[p] = e[p] // exponent return tuple(e) parent = expression.parent() result = parent( {subs_e(e): c for e, c in iteritems(expression.dict())}) return result def de_power(expression): expression = Z(expression) for e, var in zip(exponents, Z.gens()): if abs(e) == 1: continue expression = subs_power(expression, var, abs(e)) return expression logger.debug('Omega_ge: preparing denominator') factors_denominator = tuple( de_power(1 - factor) for factor in _Omega_factors_denominator_(x, y)) logger.debug('Omega_ge: preparing numerator') numerator = de_power(_Omega_numerator_(a, x, y, t)) logger.info('Omega_ge: completed') return numerator, factors_denominator
def _Omega_numerator_P_(a, x, y, t): r""" Helper function for :func:`_Omega_numerator_`. This is an implementation of the function `P` of [APR2001]_. INPUT: - ``a`` -- an integer - ``x`` and ``y`` -- a tuple of Laurent polynomials The tuple ``x`` here is the flattened ``x`` of :func:`_Omega_numerator_` but without its last entry. - ``t`` -- a temporary Laurent polynomial variable In the (final) result, ``t`` has to be substituted by the last entry of the flattened ``x`` of :func:`_Omega_numerator_`. OUTPUT: A Laurent polynomial TESTS:: sage: from sage.rings.polynomial.omega import _Omega_numerator_P_ sage: L.<x0, x1, y0, y1, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_P_(0, (x0,), (y0,), t).subs({t: x1}) -x0*x1*y0 + 1 """ # This function takes Laurent polynomials as inputs. It would # be possible to input only the sizes of ``x`` and ``y`` and # perform a substitution afterwards; in this way caching of this # function would make sense. However, the way it is now allows # automatic collection and simplification of the summands, which # makes it more efficient for higher powers at the input of # :func:`Omega_ge`. # Caching occurs in :func:`Omega_ge`. import logging logger = logging.getLogger(__name__) from sage.arith.srange import srange from sage.misc.misc_c import prod n = len(x) if n == 0: x0 = t result = x0**(-a) + \ (prod(1 - x0*yy for yy in y) * sum(homogenous_symmetric_function(j, y) * (1-x0**(j-a)) for j in srange(a)) if a > 0 else 0) else: Pprev = _Omega_numerator_P_(a, x[:n-1], y, t) x2 = x[n-1] logger.debug('Omega_numerator: P(%s): substituting...', n) x1 = t p1 = Pprev p2 = Pprev.subs({t: x2}) logger.debug('Omega_numerator: P(%s): preparing...', n) dividend = x1 * (1-x2) * prod(1 - x2*yy for yy in y) * p1 - \ x2 * (1-x1) * prod(1 - x1*yy for yy in y) * p2 logger.debug('Omega_numerator: P(%s): dividing...', n) q, r = dividend.quo_rem(x1 - x2) assert r == 0 result = q logger.debug('Omega_numerator: P(%s) has %s terms', n, result.number_of_terms()) return result
def _Omega_numerator_(a, x, y, t): r""" Return the numerator of `\Omega_{\ge}` of the expression specified by the input. To be more precise, calculate .. MATH:: \Omega_{\ge} \frac{\mu^a}{ (1 - x_1 \mu) \dots (1 - x_n \mu) (1 - y_1 / \mu) \dots (1 - y_m / \mu)} and return its numerator. This function is meant to be a helper function of :func:`MacMahonOmega`. INPUT: - ``a`` -- an integer - ``x`` and ``y`` -- a tuple of tuples of Laurent polynomials The flattened ``x`` contains `x_1,...,x_n`, the flattened ``y`` the `y_1,...,y_m`. The non-flatness of these parameters is to be interface-consistent with :func:`_Omega_factors_denominator_`. - ``t`` -- a temporary Laurent polynomial variable used for substituting OUTPUT: A Laurent polynomial The output is normalized such that the corresponding denominator (:func:`_Omega_factors_denominator_`) has constant term `1`. EXAMPLES:: sage: from sage.rings.polynomial.omega import _Omega_numerator_, _Omega_factors_denominator_ sage: L.<x0, x1, x2, x3, y0, y1, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_(0, ((x0,),), ((y0,),), t) 1 sage: _Omega_numerator_(0, ((x0,), (x1,)), ((y0,),), t) -x0*x1*y0 + 1 sage: _Omega_numerator_(0, ((x0,),), ((y0,), (y1,)), t) 1 sage: _Omega_numerator_(0, ((x0,), (x1,), (x2,)), ((y0,),), t) x0*x1*x2*y0^2 + x0*x1*x2*y0 - x0*x1*y0 - x0*x2*y0 - x1*x2*y0 + 1 sage: _Omega_numerator_(0, ((x0,), (x1,)), ((y0,), (y1,)), t) x0^2*x1*y0*y1 + x0*x1^2*y0*y1 - x0*x1*y0*y1 - x0*x1*y0 - x0*x1*y1 + 1 sage: _Omega_numerator_(-2, ((x0,),), ((y0,),), t) x0^2 sage: _Omega_numerator_(-1, ((x0,),), ((y0,),), t) x0 sage: _Omega_numerator_(1, ((x0,),), ((y0,),), t) -x0*y0 + y0 + 1 sage: _Omega_numerator_(2, ((x0,),), ((y0,),), t) -x0*y0^2 - x0*y0 + y0^2 + y0 + 1 TESTS:: sage: _Omega_factors_denominator_((), ()) () sage: _Omega_numerator_(0, (), (), t) 1 sage: _Omega_numerator_(+2, (), (), t) 1 sage: _Omega_numerator_(-2, (), (), t) 0 sage: _Omega_factors_denominator_(((x0,),), ()) (-x0 + 1,) sage: _Omega_numerator_(0, ((x0,),), (), t) 1 sage: _Omega_numerator_(+2, ((x0,),), (), t) 1 sage: _Omega_numerator_(-2, ((x0,),), (), t) x0^2 sage: _Omega_factors_denominator_((), ((y0,),)) () sage: _Omega_numerator_(0, (), ((y0,),), t) 1 sage: _Omega_numerator_(+2, (), ((y0,),), t) y0^2 + y0 + 1 sage: _Omega_numerator_(-2, (), ((y0,),), t) 0 :: sage: L.<X, Y, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_(2, ((X,),), ((Y,),), t) -X*Y^2 - X*Y + Y^2 + Y + 1 """ from sage.arith.srange import srange from sage.misc.misc_c import prod x_flat = sum(x, tuple()) y_flat = sum(y, tuple()) n = len(x_flat) m = len(y_flat) xy = x_flat + y_flat import logging logger = logging.getLogger(__name__) logger.info('Omega_numerator: a=%s, n=%s, m=%s', a, n, m) if m == 0: result = 1 - (prod(_Omega_factors_denominator_(x, y)) * sum(homogenous_symmetric_function(j, xy) for j in srange(-a)) if a < 0 else 0) elif n == 0: result = sum(homogenous_symmetric_function(j, xy) for j in srange(a+1)) else: result = _Omega_numerator_P_(a, x_flat[:-1], y_flat, t).subs({t: x_flat[-1]}) L = t.parent() result = L(result) logger.info('_Omega_numerator_: %s terms', result.number_of_terms()) return result
def Omega_ge(a, exponents): r""" Return `\Omega_{\ge}` of the expression specified by the input. To be more precise, calculate .. MATH:: \Omega_{\ge} \frac{\mu^a}{ (1 - z_0 \mu^{e_0}) \dots (1 - z_{n-1} \mu^{e_{n-1}})} and return its numerator and a factorization of its denominator. Note that `z_0`, ..., `z_{n-1}` only appear in the output, but not in the input. INPUT: - ``a`` -- an integer - ``exponents`` -- a tuple of integers OUTPUT: A pair representing a quotient as follows: Its first component is the numerator as a Laurent polynomial, its second component a factorization of the denominator as a tuple of Laurent polynomials, where each Laurent polynomial `z` represents a factor `1 - z`. The parents of these Laurent polynomials is always a Laurent polynomial ring in `z_0`, ..., `z_{n-1}` over `\ZZ`, where `n` is the length of ``exponents``. EXAMPLES:: sage: from sage.rings.polynomial.omega import Omega_ge sage: Omega_ge(0, (1, -2)) (1, (z0, z0^2*z1)) sage: Omega_ge(0, (1, -3)) (1, (z0, z0^3*z1)) sage: Omega_ge(0, (1, -4)) (1, (z0, z0^4*z1)) sage: Omega_ge(0, (2, -1)) (z0*z1 + 1, (z0, z0*z1^2)) sage: Omega_ge(0, (3, -1)) (z0*z1^2 + z0*z1 + 1, (z0, z0*z1^3)) sage: Omega_ge(0, (4, -1)) (z0*z1^3 + z0*z1^2 + z0*z1 + 1, (z0, z0*z1^4)) sage: Omega_ge(0, (1, 1, -2)) (-z0^2*z1*z2 - z0*z1^2*z2 + z0*z1*z2 + 1, (z0, z1, z0^2*z2, z1^2*z2)) sage: Omega_ge(0, (2, -1, -1)) (z0*z1*z2 + z0*z1 + z0*z2 + 1, (z0, z0*z1^2, z0*z2^2)) sage: Omega_ge(0, (2, 1, -1)) (-z0*z1*z2^2 - z0*z1*z2 + z0*z2 + 1, (z0, z1, z0*z2^2, z1*z2)) :: sage: Omega_ge(0, (2, -2)) (-z0*z1 + 1, (z0, z0*z1, z0*z1)) sage: Omega_ge(0, (2, -3)) (z0^2*z1 + 1, (z0, z0^3*z1^2)) sage: Omega_ge(0, (3, 1, -3)) (-z0^3*z1^3*z2^3 + 2*z0^2*z1^3*z2^2 - z0*z1^3*z2 + z0^2*z2^2 - 2*z0*z2 + 1, (z0, z1, z0*z2, z0*z2, z0*z2, z1^3*z2)) :: sage: Omega_ge(0, (3, 6, -1)) (-z0*z1*z2^8 - z0*z1*z2^7 - z0*z1*z2^6 - z0*z1*z2^5 - z0*z1*z2^4 + z1*z2^5 - z0*z1*z2^3 + z1*z2^4 - z0*z1*z2^2 + z1*z2^3 - z0*z1*z2 + z0*z2^2 + z1*z2^2 + z0*z2 + z1*z2 + 1, (z0, z1, z0*z2^3, z1*z2^6)) TESTS:: sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # long time 27837 :: sage: Omega_ge(1, (2,)) (1, (z0,)) """ import logging logger = logging.getLogger(__name__) logger.info('Omega_ge: a=%s, exponents=%s', a, exponents) from sage.arith.all import lcm, srange from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.number_field.number_field import CyclotomicField if not exponents or any(e == 0 for e in exponents): raise NotImplementedError rou = sorted(set(abs(e) for e in exponents) - set([1])) ellcm = lcm(rou) B = CyclotomicField(ellcm, 'zeta') zeta = B.gen() z_names = tuple('z{}'.format(i) for i in range(len(exponents))) L = LaurentPolynomialRing(B, ('t',) + z_names, len(z_names) + 1) t = L.gens()[0] Z = LaurentPolynomialRing(ZZ, z_names, len(z_names)) powers = {i: L(zeta**(ellcm//i)) for i in rou} powers[2] = L(-1) powers[1] = L(1) exponents_and_values = tuple( (e, tuple(powers[abs(e)]**j * z for j in srange(abs(e)))) for z, e in zip(L.gens()[1:], exponents)) x = tuple(v for e, v in exponents_and_values if e > 0) y = tuple(v for e, v in exponents_and_values if e < 0) def subs_power(expression, var, exponent): r""" Substitute ``var^exponent`` by ``var`` in ``expression``. It is assumed that ``var`` only occurs with exponents divisible by ``exponent``. """ p = tuple(var.dict().popitem()[0]).index(1) # var is the p-th generator def subs_e(e): e = list(e) assert e[p] % exponent == 0 e[p] = e[p] // exponent return tuple(e) parent = expression.parent() result = parent({subs_e(e): c for e, c in iteritems(expression.dict())}) return result def de_power(expression): expression = Z(expression) for e, var in zip(exponents, Z.gens()): if abs(e) == 1: continue expression = subs_power(expression, var, abs(e)) return expression logger.debug('Omega_ge: preparing denominator') factors_denominator = tuple(de_power(1 - factor) for factor in _Omega_factors_denominator_(x, y)) logger.debug('Omega_ge: preparing numerator') numerator = de_power(_Omega_numerator_(a, x, y, t)) logger.info('Omega_ge: completed') return numerator, factors_denominator
def enum_projective_rational_field(X,B): r""" Enumerates projective, rational points on scheme ``X`` of height up to bound ``B``. INPUT: - ``X`` - a scheme or set of abstract rational points of a scheme. - ``B`` - a positive integer bound. OUTPUT: - a list containing the projective points of ``X`` of height up to ``B``, sorted. EXAMPLES:: sage: P.<X,Y,Z> = ProjectiveSpace(2, QQ) sage: C = P.subscheme([X+Y-Z]) sage: from sage.schemes.projective.projective_rational_point import enum_projective_rational_field sage: enum_projective_rational_field(C(QQ), 6) [(-5 : 6 : 1), (-4 : 5 : 1), (-3 : 4 : 1), (-2 : 3 : 1), (-3/2 : 5/2 : 1), (-1 : 1 : 0), (-1 : 2 : 1), (-2/3 : 5/3 : 1), (-1/2 : 3/2 : 1), (-1/3 : 4/3 : 1), (-1/4 : 5/4 : 1), (-1/5 : 6/5 : 1), (0 : 1 : 1), (1/6 : 5/6 : 1), (1/5 : 4/5 : 1), (1/4 : 3/4 : 1), (1/3 : 2/3 : 1), (2/5 : 3/5 : 1), (1/2 : 1/2 : 1), (3/5 : 2/5 : 1), (2/3 : 1/3 : 1), (3/4 : 1/4 : 1), (4/5 : 1/5 : 1), (5/6 : 1/6 : 1), (1 : 0 : 1), (6/5 : -1/5 : 1), (5/4 : -1/4 : 1), (4/3 : -1/3 : 1), (3/2 : -1/2 : 1), (5/3 : -2/3 : 1), (2 : -1 : 1), (5/2 : -3/2 : 1), (3 : -2 : 1), (4 : -3 : 1), (5 : -4 : 1), (6 : -5 : 1)] sage: enum_projective_rational_field(C,6) == enum_projective_rational_field(C(QQ),6) True :: sage: P3.<W,X,Y,Z> = ProjectiveSpace(3, QQ) sage: enum_projective_rational_field(P3, 1) [(-1 : -1 : -1 : 1), (-1 : -1 : 0 : 1), (-1 : -1 : 1 : 0), (-1 : -1 : 1 : 1), (-1 : 0 : -1 : 1), (-1 : 0 : 0 : 1), (-1 : 0 : 1 : 0), (-1 : 0 : 1 : 1), (-1 : 1 : -1 : 1), (-1 : 1 : 0 : 0), (-1 : 1 : 0 : 1), (-1 : 1 : 1 : 0), (-1 : 1 : 1 : 1), (0 : -1 : -1 : 1), (0 : -1 : 0 : 1), (0 : -1 : 1 : 0), (0 : -1 : 1 : 1), (0 : 0 : -1 : 1), (0 : 0 : 0 : 1), (0 : 0 : 1 : 0), (0 : 0 : 1 : 1), (0 : 1 : -1 : 1), (0 : 1 : 0 : 0), (0 : 1 : 0 : 1), (0 : 1 : 1 : 0), (0 : 1 : 1 : 1), (1 : -1 : -1 : 1), (1 : -1 : 0 : 1), (1 : -1 : 1 : 0), (1 : -1 : 1 : 1), (1 : 0 : -1 : 1), (1 : 0 : 0 : 0), (1 : 0 : 0 : 1), (1 : 0 : 1 : 0), (1 : 0 : 1 : 1), (1 : 1 : -1 : 1), (1 : 1 : 0 : 0), (1 : 1 : 0 : 1), (1 : 1 : 1 : 0), (1 : 1 : 1 : 1)] ALGORITHM: We just check all possible projective points in correct dimension of projective space to see if they lie on ``X``. AUTHORS: - John Cremona and Charlie Turner (06-2010) """ from sage.schemes.projective.projective_space import is_ProjectiveSpace if(is_Scheme(X)): if (not is_ProjectiveSpace(X.ambient_space())): raise TypeError("ambient space must be projective space over the rational field") X = X(X.base_ring()) else: if (not is_ProjectiveSpace(X.codomain().ambient_space())): raise TypeError("codomain must be projective space over the rational field") n = X.codomain().ambient_space().ngens() zero = (0,) * n pts = [] for c in cartesian_product_iterator([srange(-B,B+1) for _ in range(n)]): if gcd(c) == 1 and c > zero: try: pts.append(X(c)) except TypeError: pass pts.sort() return pts