Path: blob/master/sage/quadratic_forms/count_local_2.pyx
4078 views
r"""1Optimised Cython code for counting congruence solutions2"""34include "../ext/cdefs.pxi"5include "../ext/gmp.pxi"67from sage.rings.arith import valuation, kronecker_symbol, is_prime8from sage.rings.finite_rings.integer_mod import IntegerMod, Mod9from sage.rings.finite_rings.integer_mod_ring import IntegerModRing1011from sage.rings.integer_ring import ZZ1213from sage.rings.finite_rings.integer_mod cimport IntegerMod_gmp14from sage.sets.set import Set1516171819def extract_sublist_indices(Biglist, Smalllist):20"""21Returns the indices of Biglist which index the entries of22Smalllist appearing in Biglist. (Note that Smalllist may not be a23sublist of Biglist.)2425NOTE 1: This is an internal routine which deals with re-indexing26lists, and is not exported to the QuadraticForm namespace!2728NOTE 2: This should really by applied only when BigList has no29repeated entries.3031TO DO: *** Please revisit this routine, and eliminate it! ***3233INPUT:34Biglist, Smalllist -- two lists of a common type, where Biglist has no35repeated entries.3637OUTPUT:38a list of integers >= 03940EXAMPLES::4142sage: from sage.quadratic_forms.count_local_2 import extract_sublist_indices4344sage: biglist = [1,3,5,7,8,2,4]45sage: sublist = [5,3,2]46sage: sublist == [biglist[i] for i in extract_sublist_indices(biglist, sublist)] ## Ok whenever Smalllist is a sublist of Biglist47True4849sage: extract_sublist_indices([1,2,3,6,9,11], [1,3,2,9])50[0, 2, 1, 4]5152sage: extract_sublist_indices([1,2,3,6,9,11], [1,3,10,2,9,0])53[0, 2, 1, 4]5455sage: extract_sublist_indices([1,3,5,3,8], [1,5])56Traceback (most recent call last):57...58TypeError: Biglist must not have repeated entries!59"""60## Check that Biglist has no repeated entries61Big_set = Set(Biglist)62if len(Set(Biglist)) != len(Biglist):63raise TypeError, "Biglist must not have repeated entries!"6465## Extract the indices of Biglist needed to make Sublist66index_list = []67for x in Smalllist:68try:69index_list.append(Biglist.index(x))70except ValueError: ## This happens when an entry of Smalllist is not contained in Biglist71None7273## Return the list if indices74return index_list7576777879def count_modp__by_gauss_sum(n, p, m, Qdet):80"""81Returns the number of solutions of Q(x) = m over the finite field82Z/pZ, where p is a prime number > 2 and Q is a non-degenerate83quadratic form of dimension n >= 1 and has Gram determinant Qdet.8485REFERENCE:86These are defined in Table 1 on p363 of Hanke's "Local87Densities..." paper.8889INPUT:9091- n -- an integer >= 192- p -- a prime number > 293- m -- an integer94- Qdet -- a integer which is non-zero mod p9596OUTPUT:97an integer >= 09899EXAMPLES::100101sage: from sage.quadratic_forms.count_local_2 import count_modp__by_gauss_sum102103sage: count_modp__by_gauss_sum(3, 3, 0, 1) ## for Q = x^2 + y^2 + z^2 => Gram Det = 1 (mod 3)1049105sage: count_modp__by_gauss_sum(3, 3, 1, 1) ## for Q = x^2 + y^2 + z^2 => Gram Det = 1 (mod 3)1066107sage: count_modp__by_gauss_sum(3, 3, 2, 1) ## for Q = x^2 + y^2 + z^2 => Gram Det = 1 (mod 3)10812109110sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])111sage: [Q.count_congruence_solutions(3, 1, m, None, None) == count_modp__by_gauss_sum(3, 3, m, 1) for m in range(3)]112[True, True, True]113114115sage: count_modp__by_gauss_sum(3, 3, 0, 2) ## for Q = x^2 + y^2 + 2*z^2 => Gram Det = 2 (mod 3)1169117sage: count_modp__by_gauss_sum(3, 3, 1, 2) ## for Q = x^2 + y^2 + 2*z^2 => Gram Det = 2 (mod 3)11812119sage: count_modp__by_gauss_sum(3, 3, 2, 2) ## for Q = x^2 + y^2 + 2*z^2 => Gram Det = 2 (mod 3)1206121122sage: Q = DiagonalQuadraticForm(ZZ, [1,1,2])123sage: [Q.count_congruence_solutions(3, 1, m, None, None) == count_modp__by_gauss_sum(3, 3, m, 2) for m in range(3)]124[True, True, True]125126127"""128## Check that Qdet is non-degenerate129if Qdet % p == 0:130raise RuntimeError, "Qdet must be non-zero."131132## Check that p is prime > 0133if not is_prime(p) or p == 2:134raise RuntimeError, "p must be a prime number > 2."135136## Check that n >= 1137if n < 1:138raise RuntimeError, "the dimension n must be >= 1."139140## Compute the Gauss sum141neg1 = -1142if (m % p == 0):143if (n % 2 != 0):144count = (p**(n-1))145else:146count = (p**(n-1)) + (p-1) * (p**((n-2)/2)) * kronecker_symbol(((neg1**(n/2)) * Qdet) % p, p)147else:148if (n % 2 != 0):149count = (p**(n-1)) + (p**((n-1)/2)) * kronecker_symbol(((neg1**((n-1)/2)) * Qdet * m) % p, p)150else:151count = (p**(n-1)) - (p**((n-2)/2)) * kronecker_symbol(((neg1**(n/2)) * Qdet) % p, p)152153## Return the result154return count155156157158159160161cdef CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec):162"""163This Cython routine is documented in its Python wrapper method164QuadraticForm.count_congruence_solutions_by_type().165"""166cdef long n, i167cdef long a, b ## Used to quickly evaluate Q(v)168cdef long ptr ## Used to increment the vector169cdef long solntype ## Used to store the kind of solution we find170171172## Some shortcuts and definitions173n = Q.dim()174R = p ** k175Q1 = Q.base_change_to(IntegerModRing(R))176177178## Cython Variables179cdef IntegerMod_gmp zero, one180zero = IntegerMod_gmp(IntegerModRing(R), 0)181one = IntegerMod_gmp(IntegerModRing(R), 1)182183184185## Initialize the counting vector186count_vector = [0 for i in range(6)]187188## Initialize v = (0, ... , 0)189v = [Mod(0, R) for i in range(n)]190191192## Some declarations to speed up the loop193R_n = R ** n194m1 = Mod(m, R)195196## Count the local solutions197for i from 0 <= i < R_n:198199## Perform a carry (when value = R-1) until we can increment freely200ptr = len(v)201while ((ptr > 0) and (v[ptr-1] == R-1)):202v[ptr-1] += 1203ptr += -1204205## Only increment if we're not already at the zero vector =)206if (ptr > 0):207v[ptr-1] += 1208209210## Evaluate Q(v) quickly211tmp_val = Mod(0, R)212for a from 0 <= a < n:213for b from a <= b < n:214tmp_val += Q1[a,b] * v[a] * v[b]215216## Sort the solution by it's type217#if (Q1(v) == m1):218if (tmp_val == m1):219solntype = local_solution_type_cdef(Q1, p, v, zvec, nzvec)220if (solntype != 0):221count_vector[solntype] += 1222223224## Generate the Bad-type and Total counts225count_vector[3] = count_vector[4] + count_vector[5]226count_vector[0] = count_vector[1] + count_vector[2] + count_vector[3]227228## Return the solution counts229return count_vector230231232233234def CountAllLocalTypesNaive(Q, p, k, m, zvec, nzvec):235"""236This is an internal routine, which is called by237:meth:`sage.quadratic_forms.quadratic_form.QuadraticForm.count_congruence_solutions_by_type238QuadraticForm.count_congruence_solutions_by_type`. See the documentation of239that method for more details.240241INPUT:242243- `Q` -- quadratic form over `\ZZ`244- `p` -- prime number > 0245- `k` -- an integer > 0246- `m` -- an integer (depending only on mod `p^k`)247- ``zvec``, ``nzvec`` -- a list of integers in ``range(Q.dim())``, or ``None``248249OUTPUT:250a list of six integers `\ge 0` representing the solution types: ``[All,251Good, Zero, Bad, BadI, BadII]``252253254EXAMPLES::255256sage: from sage.quadratic_forms.count_local_2 import CountAllLocalTypesNaive257sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3])258sage: CountAllLocalTypesNaive(Q, 3, 1, 1, None, None)259[6, 6, 0, 0, 0, 0]260sage: CountAllLocalTypesNaive(Q, 3, 1, 2, None, None)261[6, 6, 0, 0, 0, 0]262sage: CountAllLocalTypesNaive(Q, 3, 1, 0, None, None)263[15, 12, 1, 2, 0, 2]264265"""266return CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec)267268269270271272273274cdef local_solution_type_cdef(Q, p, w, zvec, nzvec):275"""276Internal routine to check if a given solution vector w (of Q(w) =277m mod p^k) is of a certain local type and satisfies certain278congruence conditions mod p.279280NOTE: No internal checking is done to test if p is a prime >=2, or281that Q has the same size as w.282283"""284cdef long i285cdef long n286287n = Q.dim()288289290## Check if the solution satisfies the zvec "zero" congruence conditions291## (either zvec is empty or its components index the zero vector mod p)292if (zvec == None) or (len(zvec) == 0):293zero_flag = True294else:295zero_flag = False296i = 0297while ( (i < len(zvec)) and ((w[zvec[i]] % p) == 0) ): ## Increment so long as our entry is zero (mod p)298i += 1299if (i == len(zvec)): ## If we make it through all entries then the solution is zero (mod p)300zero_flag = True301302303## DIAGNOSTIC304#print "IsLocalSolutionType: Finished the Zero congruence condition test \n"305306if (zero_flag == False):307return <long> 0308309## DIAGNOSTIC310#print "IsLocalSolutionType: Passed the Zero congruence condition test \n"311312313## Check if the solution satisfies the nzvec "nonzero" congruence conditions314## (nzvec is non-empty and its components index a non-zero vector mod p)315if (nzvec == None):316nonzero_flag = True317elif (len(nzvec) == 0):318nonzero_flag = False ## Trivially no solutions in this case!319else:320nonzero_flag = False321i = 0322while ((nonzero_flag == False) and (i < len(nzvec))):323if ((w[nzvec[i]] % p) != 0):324nonzero_flag = True ## The non-zero condition is satisfied when we find one non-zero entry325i += 1326327if (nonzero_flag == False):328return <long> 0329330331## Check if the solution has the appropriate (local) type:332## -------------------------------------------------------333334## 1: Check Good-type335for i from 0 <= i < n:336if (((w[i] % p) != 0) and ((Q[i,i] % p) != 0)):337return <long> 1338if (p == 2):339for i from 0 <= i < (n - 1):340if (((Q[i,i+1] % p) != 0) and (((w[i] % p) != 0) or ((w[i+1] % p) != 0))):341return <long> 1342343344## 2: Check Zero-type345Zero_flag = True346for i from 0 <= i < n:347if ((w[i] % p) != 0):348Zero_flag = False349if (Zero_flag == True):350return <long> 2351352353## Check if wS1 is zero or not354wS1_nonzero_flag = False355for i from 0 <= i < n:356357## Compute the valuation of each index, allowing for off-diagonal terms358if (Q[i,i] == 0):359if (i == 0):360val = valuation(Q[i,i+1], p) ## Look at the term to the right361elif (i == n - 1):362val = valuation(Q[i-1,i], p) ## Look at the term above363else:364val = valuation(Q[i,i+1] + Q[i-1,i], p) ## Finds the valuation of the off-diagonal term since only one isn't zero365else:366val = valuation(Q[i,i], p)367368## Test each index369if ((val == 1) and ((w[i] % p) != 0)):370wS1_nonzero_flag = True371372373## 4: Check Bad-type I374if (wS1_nonzero_flag == True):375#print " Bad I Soln : " + str(w)376return <long> 4377378379## 5: Check Bad-type II380if (wS1_nonzero_flag == False):381#print " Bad II Soln : " + str(w)382return <long> 5383384385## Error if we get here! =o386print " Solution vector is " + str(w)387print " and Q is \n" + str(Q) + "\n"388raise RuntimeError, "Error in IsLocalSolutionType: Should not execute this line... =( \n"389390391392