Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Local Representation Conditions """ ########################################################################## ## Class for keeping track of the local conditions for representability ## ## of numbers by a quadratic form over ZZ (and eventually QQ also). ## ##########################################################################
from copy import deepcopy
from sage.rings.integer_ring import ZZ from sage.arith.all import prime_divisors, valuation, is_square from sage.quadratic_forms.extras import least_quadratic_nonresidue from sage.rings.infinity import infinity from sage.misc.functional import numerator, denominator from sage.rings.rational_field import QQ
class QuadraticFormLocalRepresentationConditions(): """ Creates a class for dealing with the local conditions of a quadratic form, and checking local representability of numbers.
EXAMPLES::
sage: Q4 = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q4.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except []. For these and the reals, we have: Reals: [0, +Infinity] sage: Q4.is_locally_represented_number(1) True sage: Q4.is_locally_universal_at_all_primes() True sage: Q4.is_locally_universal_at_all_places() False sage: L = [m for m in range(-5, 100) if Q4.is_locally_represented_number(m)] sage: L == list(range(100)) True
::
sage: Q3 = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q3.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except [2]. For these and the reals, we have: Reals: [0, +Infinity] p = 2: [0, 0, 0, +Infinity, 0, 0, 0, 0] sage: E = [m for m in range(100) if not Q3.is_locally_represented_number(m)] sage: E1 = [m for m in range(1,100) if m / 2**(2*floor(valuation(m,2)/2)) % 8 == 7] sage: E == E1 True sage: E [7, 15, 23, 28, 31, 39, 47, 55, 60, 63, 71, 79, 87, 92, 95]
::
sage: Q2 = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q2.local_representation_conditions() This 2-dimensional form represents the p-adic integers of even valuation for all primes p except [2]. For these and the reals, we have: Reals: [0, +Infinity] p = 2: [0, +Infinity, 0, +Infinity, 0, +Infinity, 0, +Infinity] sage: Q2.is_locally_universal_at_all_places() False sage: Q2.is_locally_universal_at_all_primes() False sage: L = [m for m in range(-5, 25) if Q2.is_locally_represented_number(m)] sage: L1 = [0] + [m for m in range(1,25) \ if len([p for p in prime_factors(squarefree_part(ZZ(m))) if (p % 4) == 3]) % 2 == 0] sage: L == L1 True sage: L [0, 1, 2, 4, 5, 8, 9, 10, 13, 16, 17, 18, 20, 21]
::
sage: Q1 = DiagonalQuadraticForm(ZZ, [1]) sage: Q1.local_representation_conditions() This 1-dimensional form only represents square multiples of 1. sage: L = [m for m in range(100) if Q1.is_locally_represented_number(m)] sage: L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
::
sage: Q0 = DiagonalQuadraticForm(ZZ, []) sage: Q0.local_representation_conditions() This 0-dimensional form only represents zero. sage: L = [m for m in range(100) if Q0.is_locally_represented_number(m)] sage: L [0]
"""
def __init__(self, Q): """ Takes a QuadraticForm and computes its local conditions (if they don't already exist). The recompute_flag overrides the previously computed conditions if they exist, and stores the new conditions.
INPUT:
Q -- Quadratic form over ZZ
OUTPUT:
a QuadraticFormLocalRepresentationConditions object
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions sage: QuadraticFormLocalRepresentationConditions(Q) This form represents the p-adic integers Z_p for all primes p except []. For these and the reals, we have: Reals: [0, +Infinity]
"""
## Check that the form Q is integer-valued (we can relax this later) raise TypeError("We require that the quadratic form be defined over ZZ (integer-values) for now.")
## Basic structure initialization
## Deal with the special cases of 0 and 1-dimensional forms else:
## Compute the local conditions at the real numbers (i.e. "p = infinity") ## ----------------------------------------------------------------------
## Compute the local conditions for representability: ## --------------------------------------------------
## Make a table of local normal forms for each p | N
## Check local representability conditions for each prime
## Check the representability in each Z_p squareclass
## If we're not represented, write "infinity" to signify ## that this squareclass is fully obstructed
## Test if the conditions at p give exactly Z_p when dim >=3, or ## if we represent the elements of even valuation >= 2 when dim = 2. ## Check that all entries are zero or 'None'
## Add the results for this prime if there is a congruence obstruction
def __repr__(self): """ Print the local conditions.
INPUT:
none
OUTPUT:
string
TO DO: Improve the output for the real numbers, and special output for locally universality. Also give names to the squareclasses, so it's clear what the output means! =)
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.__repr__() 'This 2-dimensional form represents the p-adic integers of even\nvaluation for all primes p except [2].\nFor these and the reals, we have:\n Reals: [0, +Infinity]\n p = 2: [0, +Infinity, 0, +Infinity, 0, +Infinity, 0, +Infinity]\n'
""" else:
else:
def __eq__(self, right): """ Determines if two sets of local conditions are equal.
INPUT:
right -- a QuadraticFormLocalRepresentationConditions object
OUTPUT:
boolean
EXAMPLES::
sage: Q1 = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q2 = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q3 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q4 = DiagonalQuadraticForm(ZZ, [1,1,1,1])
sage: Q1.local_representation_conditions() == Q2.local_representation_conditions() False sage: Q1.local_representation_conditions() == Q3.local_representation_conditions() False sage: Q1.local_representation_conditions() == Q4.local_representation_conditions() False sage: Q2.local_representation_conditions() == Q3.local_representation_conditions() False sage: Q3.local_representation_conditions() == Q4.local_representation_conditions() True """ return False
## Check the dimensions agree when they affect the kind of representation conditions.
## Check equality by dimension return True return self.coeff == right.coeff ## Compare coefficients in dimension 1 (since ZZ has only one unit square) else: and (self.local_repn_array == right.local_repn_array)
def squareclass_vector(self, p): """ Gives a vector of integers which are normalized representatives for the `p`-adic rational squareclasses (or the real squareclasses) at the prime `p`.
INPUT:
`p` -- a positive prime number or "infinity".
OUTPUT:
a list of integers
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.squareclass_vector(5) [1, 2, 5, 10]
""" return [1, -1] else:
def local_conditions_vector_for_prime(self, p): """ Returns a local representation vector for the (possibly infinite) prime `p`.
INPUT:
`p` -- a positive prime number. (Is 'infinity' allowed here?)
OUTPUT:
a list of integers
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.local_conditions_vector_for_prime(2) [2, 0, 0, 0, +Infinity, 0, 0, 0, 0] sage: C.local_conditions_vector_for_prime(3) [3, 0, 0, 0, 0, None, None, None, None]
""" ## Check if p is non-generic
## Otherwise, generate a vector at this (finite) prime return [2, 0, 0, 0, 0, 0, 0, 0, 0] else:
elif self.dim == 2: if p == 2: return [2, 0, 0, 0, 0, infinity, infinity, infinity, infinity] else: return [p, 0, 0, infinity, infinity, None, None, None, None]
elif self.dim == 1: v = [p, None, None, None, None, None, None, None, None] sqclass = self.squareclass_vector(p)
for i in range(len(sq_class)): if QQ(self.coeff / sqclass[i]).is_padic_square(p): ## Note:This should happen only once! nu = valuation(self.coeff / sqclass[i], p) / 2 else: v[i+1] = infinity
elif self.dim == 0: if p == 2: return [2, infinity, infinity, infinity, infinity, infinity, infinity, infinity, infinity] else: return [p, infinity, infinity, infinity, infinity, None, None, None, None]
raise RuntimeError("Error... The dimension stored should be a non-negative integer!")
def is_universal_at_prime(self, p): """ Determines if the (integer-valued/rational) quadratic form represents all of `Z_p`.
INPUT:
`p` -- a positive prime number or "infinity".
OUTPUT:
boolean
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.is_universal_at_prime(2) False sage: C.is_universal_at_prime(3) True sage: C.is_universal_at_prime(infinity) False
""" ## Check if the prime behaves generically for n >= 3.
## Check if the prime behaves generically for n <= 2. return False
## Check if the prime is "infinity" (for the reals) raise RuntimeError("Error... The first vector should be for the real numbers!")
## Check non-generic "finite" primes
def is_universal_at_all_finite_primes(self): """ Determines if the quadratic form represents `Z_p` for all finite/non-archimedean primes.
INPUT:
none
OUTPUT:
boolean
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.is_universal_at_all_finite_primes() False
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.is_universal_at_all_finite_primes() True
""" ## Check if dim <= 2.
## Check that all non-generic finite primes are universal
def is_universal_at_all_places(self): """ Determines if the quadratic form represents `Z_p` for all finite/non-archimedean primes, and represents all real numbers.
INPUT:
none
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.is_universal_at_all_places() False
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.is_universal_at_all_places() False
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,-1]) sage: C = QuadraticFormLocalRepresentationConditions(Q) # long time (8.5 s) sage: C.is_universal_at_all_places() # long time True
""" ## Check if dim <= 2.
## Check that all non-generic finite primes are universal return True
def is_locally_represented_at_place(self, m, p): """ Determines if the rational number m is locally represented by the quadratic form at the (possibly infinite) prime `p`.
INPUT:
`m` -- an integer
`p` -- a positive prime number or "infinity".
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.is_locally_represented_at_place(7, 2) False sage: C.is_locally_represented_at_place(1, 3) True sage: C.is_locally_represented_at_place(-1, infinity) False sage: C.is_locally_represented_at_place(1, infinity) True sage: C.is_locally_represented_at_place(0, infinity) True
""" ## Sanity Check raise TypeError("Oops! m = " + str(m) + " is not a rational number!")
## Representing zero
## 0-dim'l forms return False
## 1-dim'l forms m1 = QQ(m) / self.coeff if p == infinity: return (m1 > 0) else: return (valuation(m1, p) >= 0) and m1.is_padic_square(p)
## >= 2-dim'l forms
## Check the real place else: ## m == 0 return True
## Check at a finite place #print "m =", m, " s =", s, " m/s =", (QQ(m)/s)
def is_locally_represented(self, m): """ Determines if the rational number `m` is locally represented by the quadratic form (allowing vectors with coefficients in `Z_p` at all places).
INPUT:
`m` -- an integer
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.quadratic_form__local_representation_conditions import QuadraticFormLocalRepresentationConditions
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.is_locally_represented(7) False sage: C.is_locally_represented(28) False sage: C.is_locally_represented(11) True sage: C.is_locally_represented(QQ(1)/QQ(2)) False
""" ## Representing zero
## 0-dim'l forms
## 1-dim'l forms
## Check the generic primes (when n = 2 or n >= 3) return False
## Check the non-generic primes (when n = 2 or n >= 3)
## If we got here, we're locally represented!
## -------------------- End of QuadraticFormLocalRepresentationConditions Class ----------------------
def local_representation_conditions(self, recompute_flag=False, silent_flag=False): """ WARNING: THIS ONLY WORKS CORRECTLY FOR FORMS IN >=3 VARIABLES, WHICH ARE LOCALLY UNIVERSAL AT ALMOST ALL PRIMES!
This class finds the local conditions for a number to be integrally represented by an integer-valued quadratic form. These conditions are stored in "self.__local_representability_conditions" and consist of a list of 9 element vectors, with one for each prime with a local obstruction (though only the first 5 are meaningful unless `p=2` ). The first element is always the prime `p` where the local obstruction occurs, and the next 8 (or 4) entries represent square-classes in the `p`-adic integers `Z_p`, and are labeled by the `Q_p` square-classes `t*(Q_p)^2` with `t` given as follows:
`p > 2` ==> [ * 1 u p u p * * * * ]
`p = 2` ==> [ * 1 3 5 7 2 6 10 14 ]
The integer appearing in each place tells us how `p`-divisible a number needs to be in that square-class in order to be locally represented by Q. A negative number indicates that the entire `Q_p` square-class is not represented, while a positive number `x` indicates that `t*p^{(2*x)} (Z_p)^2` is locally represented but `t*p^{(2*(x-1))}` `(Z_p)^2` is not.
As an example, the vector
[2 3 0 0 0 0 2 0 infinity]
tells us that all positive integers are locally represented at p=2 except those of the forms:
`2^6 * u * r^2` with `u = 1 (mod 8)`
`2^5 * u * r^2` with `u = 3 (mod 8)`
`2 * u * r^2` with `u = 7 (mod 8)`
At the real numbers, the vector which looks like
[infinity, 0, infinity, None, None, None, None, None, None]
means that Q is negative definite (i.e. the 0 tells us all positive reals are represented). The real vector always appears, and is listed before the other ones.
INPUT:
none
OUTPUT:
A list of 9-element vectors describing the representation obstructions at primes dividing the level.
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, []) sage: Q.local_representation_conditions() This 0-dimensional form only represents zero.
sage: Q = DiagonalQuadraticForm(ZZ, [5]) sage: Q.local_representation_conditions() This 1-dimensional form only represents square multiples of 5.
sage: Q1 = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q1.local_representation_conditions() This 2-dimensional form represents the p-adic integers of even valuation for all primes p except [2]. For these and the reals, we have: Reals: [0, +Infinity] p = 2: [0, +Infinity, 0, +Infinity, 0, +Infinity, 0, +Infinity]
sage: Q1 = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q1.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except [2]. For these and the reals, we have: Reals: [0, +Infinity] p = 2: [0, 0, 0, +Infinity, 0, 0, 0, 0]
sage: Q1 = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q1.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except []. For these and the reals, we have: Reals: [0, +Infinity]
sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,3,3]) sage: Q1.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except [3]. For these and the reals, we have: Reals: [0, +Infinity] p = 3: [0, 1, 0, 0]
sage: Q2 = DiagonalQuadraticForm(ZZ, [2,3,3,3]) sage: Q2.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except [3]. For these and the reals, we have: Reals: [0, +Infinity] p = 3: [1, 0, 0, 0]
sage: Q3 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q3.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except []. For these and the reals, we have: Reals: [0, +Infinity]
""" ## Recompute the local conditions if they don't exist or the recompute_flag is set.
## Return the local conditions if the silent_flag is not set.
def is_locally_universal_at_prime(self, p): """ Determines if the (integer-valued/rational) quadratic form represents all of `Z_p`.
INPUT:
`p` -- a positive prime number or "infinity".
OUTPUT:
boolean
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.is_locally_universal_at_prime(2) True sage: Q.is_locally_universal_at_prime(3) True sage: Q.is_locally_universal_at_prime(5) True sage: Q.is_locally_universal_at_prime(infinity) False
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_universal_at_prime(2) False sage: Q.is_locally_universal_at_prime(3) True sage: Q.is_locally_universal_at_prime(5) True sage: Q.is_locally_universal_at_prime(infinity) False
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,-1]) sage: Q.is_locally_universal_at_prime(infinity) True
"""
def is_locally_universal_at_all_primes(self): """ Determines if the quadratic form represents `Z_p` for all finite/non-archimedean primes.
INPUT:
none
OUTPUT:
boolean
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.is_locally_universal_at_all_primes() True
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.is_locally_universal_at_all_primes() True
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_universal_at_all_primes() False
"""
def is_locally_universal_at_all_places(self): """ Determines if the quadratic form represents `Z_p` for all finite/non-archimedean primes, and represents all real numbers.
INPUT:
none
OUTPUT:
boolean
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.is_locally_universal_at_all_places() False
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.is_locally_universal_at_all_places() False
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,-1]) sage: Q.is_locally_universal_at_all_places() # long time (8.5 s) True
"""
def is_locally_represented_number_at_place(self, m, p): """ Determines if the rational number m is locally represented by the quadratic form at the (possibly infinite) prime `p`.
INPUT:
`m` -- an integer
`p` -- a prime number > 0 or 'infinity'
OUTPUT:
boolean
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_represented_number_at_place(7, infinity) True sage: Q.is_locally_represented_number_at_place(7, 2) False sage: Q.is_locally_represented_number_at_place(7, 3) True sage: Q.is_locally_represented_number_at_place(7, 5) True sage: Q.is_locally_represented_number_at_place(-1, infinity) False sage: Q.is_locally_represented_number_at_place(-1, 2) False
::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,-1]) sage: Q.is_locally_represented_number_at_place(7, infinity) # long time (8.5 s) True sage: Q.is_locally_represented_number_at_place(7, 2) # long time True sage: Q.is_locally_represented_number_at_place(7, 3) # long time True sage: Q.is_locally_represented_number_at_place(7, 5) # long time True
"""
def is_locally_represented_number(self, m): """ Determines if the rational number m is locally represented by the quadratic form.
INPUT:
`m` -- an integer
OUTPUT:
boolean
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_represented_number(2) True sage: Q.is_locally_represented_number(7) False sage: Q.is_locally_represented_number(-1) False sage: Q.is_locally_represented_number(28) False sage: Q.is_locally_represented_number(0) True
""" |