def search_global_symbols(n, D): rank = 2 + n sign = 2 - n csymbols = list() # a list of canonical symbols to avoid duplicates D = (-1)**n * D symbols = all_symbols(sign, rank, D) global_symbols = [] for sym in symbols: #print sym for p in sym.keys(): prank = sum([s[1] for s in sym[p]]) v = sum([s[0] * s[1] for s in sym[p]]) Dp = D // (p**v) if prank != rank: eps = (Dp * Integer(prod([s[2] for s in sym[p]]))).kronecker(p) if p == 2: if eps == -1: eps = 3 sym[p].insert(0, [0, rank - prank, eps, 0, 0]) else: if eps == -1: for x in Zmod(p): if not x.is_square(): eps = x break sym[p].insert(0, [0, rank - prank, eps]) symbol = GenusSymbol_global_ring(MatrixSpace(ZZ, rank, rank).one()) symbol._local_symbols = [ Genus_Symbol_p_adic_ring(p, syms) for p, syms in sym.iteritems() ] symbol._signature = (2, n) #print symbol._local_symbols isglob = is_GlobalGenus(symbol) if isglob: #print "GLOBAL SYMBOL:" #print symbol._local_symbols #return symbol #for s in symbol._local_symbols: # s = s.canonical_symbol() append = True for j, s in enumerate(symbol._local_symbols): if s._prime == 2: sc = deepcopy(symbol) sc._local_symbols[j] = sc._local_symbols[ j].canonical_symbol() if csymbols.count(sc) > 0: append = False else: csymbols.append(sc) break if append: global_symbols.append(symbol) return global_symbols
def search_global_symbols(n,D): rank=2+n sign=2-n csymbols=list() # a list of canonical symbols to avoid duplicates D=(-1)**n*D symbols = all_symbols(sign,rank,D) global_symbols = [] for sym in symbols: #print sym for p in sym.keys(): prank = sum([s[1] for s in sym[p]]) v = sum([ s[0]*s[1] for s in sym[p] ]) Dp=D//(p**v) if prank != rank: eps= (Dp*Integer(prod([ s[2] for s in sym[p] ]))).kronecker(p) if p==2: if eps==-1: eps=3 sym[p].insert(0,[0,rank - prank, eps,0,0]) else: if eps==-1: for x in Zmod(p): if not x.is_square(): eps=x break sym[p].insert(0,[0,rank - prank, eps]) symbol=GenusSymbol_global_ring(MatrixSpace(ZZ,rank,rank).one()) symbol._local_symbols=[Genus_Symbol_p_adic_ring(p,syms) for p,syms in sym.iteritems()] symbol._signature=(2,n) #print symbol._local_symbols isglob=is_GlobalGenus(symbol) if isglob: #print "GLOBAL SYMBOL:" #print symbol._local_symbols #return symbol #for s in symbol._local_symbols: # s = s.canonical_symbol() append=True for j,s in enumerate(symbol._local_symbols): if s._prime==2: sc=deepcopy(symbol) sc._local_symbols[j]=sc._local_symbols[j].canonical_symbol() if csymbols.count(sc)>0: append=False else: csymbols.append(sc) break if append: global_symbols.append(symbol) return global_symbols
def is_global(M, r, s, return_symbol=False): r""" Test if the FiniteQuadraticModule M can be represented by a Z-lattice of signature ``(r,s)``. INPUT: -``M`` -- FiniteQuadraticModule - ``r`` -- positive integer - ``s`` -- positive integer OUTPUT: - boolean """ J = M.jordan_decomposition() symbols = {} n = r + s sig = r - s for A in J: p = A[1][0] if not symbols.has_key(p): symbols[p] = list() sym = list(A[1][1:len(A[1])]) if p == 2: if len(A[1]) == 4: sym.append(0) sym.append(0) else: if sym[3].kronecker(2) == sym[2]: det = sym[3] % 8 else: if sym[2] == -1: det = 3 else: det = 1 sym = [sym[0], sym[1], det, 1, sym[3] % 8] #print sym #if sym[1]==1: # if sym[2].kronecker(2)==sym[4].kronecker(2): # sym[2]=sym[4] # else: # return False #print p, sym symbols[p].append(sym) D = M.order() * (-1)**s print D for p in symbols.keys(): prank = sum([sym[1] for sym in symbols[p]]) v = sum([sym[0] * sym[1] for sym in symbols[p]]) Dp = D // (p**v) print Dp if prank != n: eps = (Dp).kronecker(p) * Integer( prod([sym[2] for sym in symbols[p]])) print eps if p == 2: if eps == -1: eps = 3 symbols[p].append([0, n - prank, eps, 0, 0]) else: #if eps==-1: # for x in Zmod(p): # if not x.is_square(): # eps=x # break symbols[p].append([0, n - prank, eps]) symbol = GenusSymbol_global_ring(MatrixSpace(ZZ, r + s, r + s).one()) symbol._local_symbols = [ Genus_Symbol_p_adic_ring(p, syms) for p, syms in symbols.iteritems() ] symbol._signature = (r, s) #print r,s, symbol._local_symbols isglob = is_GlobalGenus(symbol) if return_symbol: return symbol, isglob else: return isglob
def search_global_symbols(n, D): rank = 2 + n sign = 2 - n csymbols = list() # a list of canonical symbols to avoid duplicates symbols = list() #print D D = (-1)**n * D fac = Integer(D).factor() symbols = list() for p, v in fac: psymbols = list() parts = partitions(v) Dp = D // (p**v) for vs in parts: #print "partition:", vs l = list() # list of p-symbols corresponding to the partition vs if len(vs) <= rank: exponents = Set(list(vs)) # now we set up a list ll for each vv in the partition vs # that contains an entry for each possibility # and then update l with ll (see below) if p == 2: for vv in exponents: mult = vs.count(vv) ll = list() for t in [0, 1]: # even(0) or odd(1) type for det in [1, 3, 5, 7]: # the possible determinants if mult % 2 == 0 and t == 0: ll.append([vv, mult, det, 0, 0]) if mult == 1: odds = [det] elif mult == 2: if det in [1, 7]: odds = [0, 2, 6] else: odds = [2, 4, 6] else: odds = [ o for o in range(8) if o % 2 == mult % 2 ] for oddity in odds: if t == 1: ll.append([vv, mult, det, 1, oddity]) #else: #ll.append([vv,1,det,0,0]) #if mult % 2 == 0 and mult>2: # for x in range(1,Integer(mult)/Integer(2)): # if mult-2*x==2 and det in [1,7] and oddity not in [0,2,6]: # continue # elif mult-2*x==2 and det in [3,5] and oddity not in [2,4,6]: # continue # ll.append([[vv,2*x,det,0,0],[vv,mult-2*x,det,1,oddity]]) #print "ll:\n",ll if len(l) == 0: for t in ll: if type(t[0]) == list: l.append({p: t}) else: l.append({p: [t]}) else: newl = list() for t in ll: for sym in l: newsym = deepcopy(sym) #print newsym if type(t[0]) == list: newsym[p] = newsym[p] + t else: newsym[p].append(t) #print newsym newl.append(newsym) #print l l = newl #print "l:\n",l else: for vv in exponents: ll = [[vv, vs.count(vv), 1], [vv, vs.count(vv), -1]] if len(l) == 0: for t in ll: l.append({p: [t]}) else: newl = list() for t in ll: for sym in l: sym[p].append(t) newl.append(sym) l = newl #print "l=\n",l #print "psymbols=\n",psymbols #print psymbols+l psymbols = psymbols + l if len(symbols) == 0: symbols = psymbols else: symbols_new = list() for sym in symbols: for psym in psymbols: newsym = deepcopy(sym) newsym.update(psym) symbols_new.append(newsym) symbols = symbols_new global_symbols = [] for sym in symbols: #print sym for p in sym.keys(): prank = sum([s[1] for s in sym[p]]) v = sum([s[0] * s[1] for s in sym[p]]) Dp = D // (p**v) if prank != rank: eps = (Dp * Integer(prod([s[2] for s in sym[p]]))).kronecker(p) if p == 2: if eps == -1: eps = 3 sym[p].insert(0, [0, rank - prank, eps, 0, 0]) else: if eps == -1: for x in Zmod(p): if not x.is_square(): eps = x break sym[p].insert(0, [0, rank - prank, eps]) symbol = GenusSymbol_global_ring(MatrixSpace(ZZ, rank, rank).one()) symbol._local_symbols = [ Genus_Symbol_p_adic_ring(p, syms) for p, syms in sym.items() ] symbol._signature = (2, n) #print symbol._local_symbols isglob = is_GlobalGenus(symbol) if isglob: #print "GLOBAL SYMBOL:" #print symbol._local_symbols #return symbol #for s in symbol._local_symbols: # s = s.canonical_symbol() append = True for j, s in enumerate(symbol._local_symbols): if s._prime == 2: sc = deepcopy(symbol) sc._local_symbols[j] = sc._local_symbols[ j].canonical_symbol() if csymbols.count(sc) > 0: append = False else: csymbols.append(sc) break if append: global_symbols.append(symbol) return global_symbols
def genus(self, signature_pair): r""" Return the genus defined by ``self`` and the ``signature_pair``. If no such genus exists, raise a ``ValueError``. REFERENCES: [Nik1977]_ Corollary 1.9.4 and 1.16.3. EXAMPLES:: sage: L = IntegralLattice("D4").direct_sum(IntegralLattice("A2")) sage: D = L.discriminant_group() sage: genus = D.genus(L.signature_pair()) sage: genus Genus of None Signature: (6, 0) Genus symbol at 2: 1^4:2^-2 Genus symbol at 3: 1^-5 3^-1 sage: genus == L.genus() True Let `H` be an even unimodular lattice of signature `(9, 1)`. Then `L = D_4 + A_2` is primitively embedded in `H`. We compute the discriminant form of the orthogonal complement of `L` in `H`:: sage: DK = D.twist(-1) sage: DK Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1/3] We know that `K` has signature `(5, 1)` and thus we can compute the genus of `K` as:: sage: DK.genus((3,1)) Genus of None Signature: (3, 1) Genus symbol at 2: 1^2:2^-2 Genus symbol at 3: 1^-3 3^1 We can also compute the genus of an odd lattice from its discriminant form:: sage: L = IntegralLattice(matrix.diagonal(range(1,5))) sage: D = L.discriminant_group() sage: D.genus((4,0)) Genus of None Signature: (4, 0) Genus symbol at 2: [1^-2 2^1 4^1]_6 Genus symbol at 3: 1^-3 3^1 TESTS:: sage: L.genus() == D.genus((4,0)) True sage: D.genus((1,0)) Traceback (most recent call last): ... ValueError: this discriminant form and signature do not define a genus A systematic test of lattices of small ranks and determinants:: sage: from sage.quadratic_forms.genera.genus import genera sage: signatures = [(1,0),(1,1),(1,2),(3,0),(0,4)] sage: dets = range(1,33) sage: genera = flatten([genera(s, d, even=False) for d in dets for s in signatures]) # long time sage: all(g == g.discriminant_form().genus(g.signature_pair()) for g in genera) # long time True """ from sage.quadratic_forms.genera.genus import (Genus_Symbol_p_adic_ring, GenusSymbol_global_ring, p_adic_symbol, is_GlobalGenus, _blocks) from sage.misc.misc_c import prod s_plus = signature_pair[0] s_minus = signature_pair[1] rank = s_plus + s_minus if len(self.invariants()) > rank: raise ValueError("this discriminant form and " + "signature do not define a genus") disc = self.cardinality() determinant = (-1)**s_minus * disc local_symbols = [] for p in (2 * disc).prime_divisors(): D = self.primary_part(p) if len(D.invariants()) != 0: G_p = D.gram_matrix_quadratic().inverse() # get rid of denominators without changing the local equivalence class G_p *= G_p.denominator()**2 G_p = G_p.change_ring(ZZ) local_symbol = p_adic_symbol(G_p, p, D.invariants()[-1].valuation(p)) else: local_symbol = [] rk = rank - len(D.invariants()) if rk > 0: if p == 2: det = determinant.prime_to_m_part(2) det *= prod([di[2] for di in local_symbol]) det = det % 8 local_symbol.append([ZZ(0), rk, det, ZZ(0), ZZ(0)]) else: det = legendre_symbol(determinant.prime_to_m_part(p), p) det = (det * prod([di[2] for di in local_symbol])) local_symbol.append([ZZ(0), rk, det]) local_symbol.sort() local_symbol = Genus_Symbol_p_adic_ring(p, local_symbol) local_symbols.append(local_symbol) # This genus has the right discriminant group # but it may be empty genus = GenusSymbol_global_ring(signature_pair, local_symbols) sym2 = local_symbols[0].symbol_tuple_list() if sym2[0][0] != 0: sym2 = [[ZZ(0), ZZ(0), ZZ(1), ZZ(0), ZZ(0)]] + sym2 if len(sym2) <= 1 or sym2[1][0] != 1: sym2 = sym2[:1] + [[ZZ(1), ZZ(0), ZZ(1), ZZ(0), ZZ(0)]] + sym2[1:] if len(sym2) <= 2 or sym2[2][0] != 2: sym2 = sym2[:2] + [[ZZ(2), ZZ(0), ZZ(1), ZZ(0), ZZ(0)]] + sym2[2:] if self.value_module_qf().n == 1: # in this case the blocks of scales 1, 2, 4 are under determined # make sure the first 3 symbols are of scales 1, 2, 4 # i.e. their valuations are 0, 1, 2 # the form is odd block0 = [b for b in _blocks(sym2[0]) if b[3] == 1] o = sym2[1][3] # no restrictions on determinant and # oddity beyond existence # but we know if even or odd block1 = [b for b in _blocks(sym2[1]) if b[3] == o] d = sym2[2][2] o = sym2[2][3] t = sym2[2][4] # if the jordan block of scale 2 is even we know it if o == 0: block2 = [sym2[2]] # if it is odd we know det and oddity mod 4 at least else: block2 = [b for b in _blocks(sym2[2]) if b[3] == o and (b[2] - d) % 4 == 0 and (b[4] - t) % 4 == 0 and (b[2] - d) % 8 == (b[4] - t) % 8 # if the oddity is altered by 4 then so is the determinant ] elif self.value_module_qf().n == 2: # the form is even block0 = [b for b in _blocks(sym2[0]) if b[3] == 0] # if the jordan block of scale 2 is even we know it d = sym2[1][2] o = sym2[1][3] t = sym2[1][4] if o == 0: block1 = [sym2[1]] else: # the block is odd and we know det and oddity mod 4 block1 = [b for b in _blocks(sym2[1]) if b[3] == o and (b[2] - d) % 4 == 0 and (b[4] - t) % 4 == 0 and (b[2] - d) % 8 == (b[4] - t) % 8 # if the oddity is altered by 4 then so is the determinant ] # this is completely determined block2 = [sym2[2]] else: raise ValueError("this is not a discriminant form") # figure out which symbol defines a genus and return that for b0 in block0: for b1 in block1: for b2 in block2: sym2[:3] = [b0, b1, b2] local_symbols[0] = Genus_Symbol_p_adic_ring(2, sym2) genus = GenusSymbol_global_ring(signature_pair, local_symbols) if is_GlobalGenus(genus): # make the symbol sparse again. i = 0 k = 0 while i < 3: if sym2[k][1] == 0: sym2.pop(k) else: k = k + 1 i = i + 1 local_symbols[0] = Genus_Symbol_p_adic_ring(2, sym2) genus = GenusSymbol_global_ring(signature_pair, local_symbols) return genus raise ValueError("this discriminant form and signature do not define a genus")
def is_global(M,r,s,return_symbol=False): r""" Test if the FiniteQuadraticModule M can be represented by a Z-lattice of signature ``(r,s)``. INPUT: -``M`` -- FiniteQuadraticModule - ``r`` -- positive integer - ``s`` -- positive integer OUTPUT: - boolean """ J=M.jordan_decomposition() symbols={} n=r+s sig=r-s for A in J: p=A[1][0] if not symbols.has_key(p): symbols[p]=list() sym=list(A[1][1:len(A[1])]) if p==2: if len(A[1])==4: sym.append(0) sym.append(0) else: if sym[3].kronecker(2)==sym[2]: det=sym[3] % 8 else: if sym[2]==-1: det=3 else: det=1 sym = [sym[0], sym[1], det, 1, sym[3] % 8] #print sym #if sym[1]==1: # if sym[2].kronecker(2)==sym[4].kronecker(2): # sym[2]=sym[4] # else: # return False #print p, sym symbols[p].append(sym) D=M.order()*(-1)**s print D for p in symbols.keys(): prank = sum([sym[1] for sym in symbols[p]]) v = sum([ sym[0]*sym[1] for sym in symbols[p] ]) Dp=D//(p**v) print Dp if prank != n: eps= (Dp).kronecker(p)*Integer(prod([ sym[2] for sym in symbols[p] ])) print eps if p==2: if eps==-1: eps=3 symbols[p].append([0,n - prank, eps,0,0]) else: #if eps==-1: # for x in Zmod(p): # if not x.is_square(): # eps=x # break symbols[p].append([0,n - prank, eps]) symbol=GenusSymbol_global_ring(MatrixSpace(ZZ,r+s,r+s).one()) symbol._local_symbols=[Genus_Symbol_p_adic_ring(p,syms) for p,syms in symbols.iteritems()] symbol._signature=(r,s) #print r,s, symbol._local_symbols isglob=is_GlobalGenus(symbol) if return_symbol: return symbol, isglob else: return isglob
def search_global_symbols(n,D): rank=2+n sign=2-n csymbols=list() # a list of canonical symbols to avoid duplicates symbols=list() #print D D=(-1)**n*D fac = Integer(D).factor() symbols=list() for p, v in fac: psymbols=list() parts=partitions(v) Dp=D//(p**v) for vs in parts: #print "partition:", vs l=list() # list of p-symbols corresponding to the partition vs if len(vs) <= rank: exponents=Set(list(vs)) # now we set up a list ll for each vv in the partition vs # that contains an entry for each possibility # and then update l with ll (see below) if p==2: for vv in exponents: mult=vs.count(vv) ll=list() for t in [0,1]: # even(0) or odd(1) type for det in [1,3,5,7]: # the possible determinants if mult % 2 == 0 and t==0: ll.append([vv,mult,det,0,0]) if mult==1: odds=[det] elif mult==2: if det in [1,7]: odds=[0,2,6] else: odds=[2,4,6] else: odds=[o for o in range(8) if o%2==mult%2] for oddity in odds: if t==1: ll.append([vv,mult,det,1,oddity]) #else: #ll.append([vv,1,det,0,0]) #if mult % 2 == 0 and mult>2: # for x in range(1,Integer(mult)/Integer(2)): # if mult-2*x==2 and det in [1,7] and oddity not in [0,2,6]: # continue # elif mult-2*x==2 and det in [3,5] and oddity not in [2,4,6]: # continue # ll.append([[vv,2*x,det,0,0],[vv,mult-2*x,det,1,oddity]]) #print "ll:\n",ll if len(l)==0: for t in ll: if type(t[0])==list: l.append({p: t}) else: l.append({p: [t]}) else: newl=list() for t in ll: for sym in l: newsym = deepcopy(sym) #print newsym if type(t[0])==list: newsym[p]=newsym[p]+t else: newsym[p].append(t) #print newsym newl.append(newsym) #print l l=newl #print "l:\n",l else: for vv in exponents: ll=[[vv,vs.count(vv),1],[vv,vs.count(vv),-1]] if len(l)==0: for t in ll: l.append({p: [t]}) else: newl=list() for t in ll: for sym in l: sym[p].append(t) newl.append(sym) l=newl #print "l=\n",l #print "psymbols=\n",psymbols #print psymbols+l psymbols=psymbols+l if len(symbols)==0: symbols=psymbols else: symbols_new=list() for sym in symbols: for psym in psymbols: newsym=deepcopy(sym) newsym.update(psym) symbols_new.append(newsym) symbols=symbols_new global_symbols = [] for sym in symbols: #print sym for p in sym.keys(): prank = sum([s[1] for s in sym[p]]) v = sum([ s[0]*s[1] for s in sym[p] ]) Dp=D//(p**v) if prank != rank: eps= (Dp*Integer(prod([ s[2] for s in sym[p] ]))).kronecker(p) if p==2: if eps==-1: eps=3 sym[p].insert(0,[0,rank - prank, eps,0,0]) else: if eps==-1: for x in Zmod(p): if not x.is_square(): eps=x break sym[p].insert(0,[0,rank - prank, eps]) symbol=GenusSymbol_global_ring(MatrixSpace(ZZ,rank,rank).one()) symbol._local_symbols=[Genus_Symbol_p_adic_ring(p,syms) for p,syms in sym.iteritems()] symbol._signature=(2,n) #print symbol._local_symbols isglob=is_GlobalGenus(symbol) if isglob: #print "GLOBAL SYMBOL:" #print symbol._local_symbols #return symbol #for s in symbol._local_symbols: # s = s.canonical_symbol() append=True for j,s in enumerate(symbol._local_symbols): if s._prime==2: sc=deepcopy(symbol) sc._local_symbols[j]=sc._local_symbols[j].canonical_symbol() if csymbols.count(sc)>0: append=False else: csymbols.append(sc) break if append: global_symbols.append(symbol) return global_symbols