def __init__(self, N): """ EXAMPLES:: sage: L = sage.modular.modsym.g1list.G1list(6); L # indirect doctest List of coset representatives for Gamma_1(6) in SL_2(Z) """ self.__N = N self.__list = [(u, v) for u in range(N) for v in range(N) if GCD(GCD(u, v), N) == 1]
def short_primitive_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): """ Return a list of lists of short primitive vectors `v`, sorted by length, with Q(`v`) < len_bound. The list in output `[i]` indexes all vectors of length `i`. If the up_to_sign_flag is set to True, then only one of the vectors of the pair `[v, -v]` is listed. Note: This processes the PARI/GP output to always give elements of type `ZZ`. OUTPUT: a list of lists of vectors. EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.short_vector_list_up_to_length(5, True) [[(0, 0, 0, 0)], [(1, 0, 0, 0)], [], [(0, 1, 0, 0)], [(1, 1, 0, 0), (1, -1, 0, 0), (2, 0, 0, 0)]] sage: Q.short_primitive_vector_list_up_to_length(5, True) [[], [(1, 0, 0, 0)], [], [(0, 1, 0, 0)], [(1, 1, 0, 0), (1, -1, 0, 0)]] """ ## Get a list of short vectors full_vec_list = self.short_vector_list_up_to_length( len_bound, up_to_sign_flag) ## Make a new list of the primitive vectors prim_vec_list = [[v for v in L if GCD(list(v)) == 1] for L in full_vec_list ] ## TO DO: Arrange for GCD to take a vector argument! ## Return the list of primitive vectors return prim_vec_list
def gcd(self): """ Returns the greatest common divisor of the coefficients of the quadratic form (as a polynomial). EXAMPLES:: sage: Q = QuadraticForm(ZZ, 4, range(1, 21, 2)) sage: Q.gcd() 1 :: sage: Q = QuadraticForm(ZZ, 4, range(0, 20, 2)) sage: Q.gcd() 2 """ if self.base_ring() != ZZ: raise TypeError("Oops! The given quadratic form must be defined over ZZ.") return GCD(self.coefficients())
def order(self): """ Return the order of this element. OUTPUT: An integer or ``infinity``. EXAMPLES:: sage: F = AbelianGroup(3,[7,8,9]) sage: Fd = F.dual_group() sage: A,B,C = Fd.gens() sage: (B*C).order() 72 sage: F = AbelianGroup(3,[7,8,9]); F Multiplicative Abelian group isomorphic to C7 x C8 x C9 sage: F.gens()[2].order() 9 sage: a,b,c = F.gens() sage: (b*c).order() 72 sage: G = AbelianGroup(3,[7,8,9]) sage: type((G.0 * G.1).order())==Integer True """ M = self.parent() order = M.gens_orders() L = self.exponents() N = LCM([ order[i] / GCD(order[i], L[i]) for i in range(len(order)) if L[i] != 0 ]) if N == 0: return infinity else: return ZZ(N)
def complementary_subform_to_vector(self, v): """ Finds the `(n-1)`-dim'l quadratic form orthogonal to the vector `v`. Note: This is usually not a direct summand! Technical Notes: There is a minor difference in the cancellation code here (form the C++ version) since the notation Q `[i,j]` indexes coefficients of the quadratic polynomial here, not the symmetric matrix. Also, it produces a better splitting now, for the full lattice (as opposed to a sublattice in the C++ code) since we now extend `v` to a unimodular matrix. INPUT: `v` -- a list of self.dim() integers OUTPUT: a QuadraticForm over `ZZ` EXAMPLES:: sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q1.complementary_subform_to_vector([1,0,0,0]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 5 0 ] [ * * 7 ] :: sage: Q1.complementary_subform_to_vector([1,1,0,0]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 12 0 0 ] [ * 5 0 ] [ * * 7 ] :: sage: Q1.complementary_subform_to_vector([1,1,1,1]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 624 -480 -672 ] [ * 880 -1120 ] [ * * 1008 ] """ n = self.dim() ## Copy the quadratic form Q = deepcopy(self) ## Find the first non-zero component of v, and call it nz (Note: 0 <= nz < n) nz = 0 while (nz < n) and (v[nz] == 0): nz += 1 ## Abort if v is the zero vector if nz == n: raise TypeError("Oops, v cannot be the zero vector! =(") ## Make the change of basis matrix new_basis = extend_to_primitive(matrix(ZZ, n, 1, v)) ## Change Q (to Q1) to have v as its nz-th basis vector Q1 = Q(new_basis) ## Pick out the value Q(v) of the vector d = Q1[0, 0] ## For each row/column, perform elementary operations to cancel them out. for i in range(1, n): ## Check if the (i,0)-entry is divisible by d, ## and stretch its row/column if not. if Q1[i, 0] % d != 0: Q1 = Q1.multiply_variable(d / GCD(d, Q1[i, 0] // 2), i) ## Now perform the (symmetric) elementary operations to cancel out the (i,0) entries/ Q1 = Q1.add_symmetric(-(Q1[i, 0] / 2) / (GCD(d, Q1[i, 0] // 2)), i, 0) ## Check that we're done! done_flag = True for i in range(1, n): if Q1[0, i] != 0: done_flag = False if not done_flag: raise RuntimeError( "There is a problem cancelling out the matrix entries! =O") ## Return the complementary matrix return Q1.extract_variables(range(1, n))
def CyclicCodeFromGeneratingPolynomial(n,g,ignore=True): r""" If g is a polynomial over GF(q) which divides `x^n-1` then this constructs the code "generated by g" (ie, the code associated with the principle ideal `gR` in the ring `R = GF(q)[x]/(x^n-1)` in the usual way). The option "ignore" says to ignore the condition that (a) the characteristic of the base field does not divide the length (the usual assumption in the theory of cyclic codes), and (b) `g` must divide `x^n-1`. If ignore=True, instead of returning an error, a code generated by `gcd(x^n-1,g)` is created. EXAMPLES:: sage: P.<x> = PolynomialRing(GF(3),"x") sage: g = x-1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C Linear code of length 4, dimension 3 over Finite Field of size 3 sage: P.<x> = PolynomialRing(GF(4,"a"),"x") sage: g = x^3+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(9,g); C Linear code of length 9, dimension 6 over Finite Field in a of size 2^2 sage: P.<x> = PolynomialRing(GF(2),"x") sage: g = x^3+x+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(7,g); C Linear code of length 7, dimension 4 over Finite Field of size 2 sage: C.generator_matrix() [1 1 0 1 0 0 0] [0 1 1 0 1 0 0] [0 0 1 1 0 1 0] [0 0 0 1 1 0 1] sage: g = x+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C Linear code of length 4, dimension 3 over Finite Field of size 2 sage: C.generator_matrix() [1 1 0 0] [0 1 1 0] [0 0 1 1] On the other hand, CyclicCodeFromPolynomial(4,x) will produce a ValueError including a traceback error message: "`x` must divide `x^4 - 1`". You will also get a ValueError if you type :: sage: P.<x> = PolynomialRing(GF(4,"a"),"x") sage: g = x^2+1 followed by CyclicCodeFromGeneratingPolynomial(6,g). You will also get a ValueError if you type :: sage: P.<x> = PolynomialRing(GF(3),"x") sage: g = x^2-1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(5,g); C Linear code of length 5, dimension 4 over Finite Field of size 3 followed by C = CyclicCodeFromGeneratingPolynomial(5,g,False), with a traceback message including "`x^2 + 2` must divide `x^5 - 1`". """ P = g.parent() x = P.gen() F = g.base_ring() p = F.characteristic() if not(ignore) and p.divides(n): raise ValueError('The characteristic %s must not divide %s'%(p,n)) if not(ignore) and not(g.divides(x**n-1)): raise ValueError('%s must divide x^%s - 1'%(g,n)) gn = GCD([g,x**n-1]) d = gn.degree() coeffs = Sequence(gn.list()) r1 = Sequence(coeffs+[0]*(n - d - 1)) Sn = SymmetricGroup(n) s = Sn.gens()[0] # assumes 1st gen of S_n is (1,2,...,n) rows = [permutation_action(s**(-i),r1) for i in range(n-d)] MS = MatrixSpace(F,n-d,n) return LinearCode(MS(rows))
def _is_a_splitting(S1, S2, n, return_automorphism=False): """ Check wether ``(S1,S2)`` is a splitting of `\ZZ/n\ZZ`. A splitting of `R = \ZZ/n\ZZ` is a pair of subsets of `R` which is a partition of `R \\backslash \{0\}` and such that there exists an element `r` of `R` such that `r S_1 = S_2` and `r S_2 = S_1` (where `r S` is the point-wise multiplication of the elements of `S` by `r`). Splittings are useful for computing idempotents in the quotient ring `Q = GF(q)[x]/(x^n-1)`. INPUT: - ``S1, S2`` -- disjoint sublists partitioning ``[1, 2, ..., n-1]`` - ``n`` (integer) - ``return_automorphism`` (boolean) -- whether to return the automorphism exchanging `S_1` and `S_2`. OUTPUT: If ``return_automorphism is False`` (default) the function returns boolean values. Otherwise, it returns a pair ``(b, r)`` where ``b`` is a boolean indicating whether `S1`, `S2` is a splitting of `n`, and `r` is such that `r S_1 = S_2` and `r S_2 = S_1` (if `b` is ``False``, `r` is equal to ``None``). EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: _is_a_splitting([1,2],[3,4],5) True sage: _is_a_splitting([1,2],[3,4],5,return_automorphism=True) (True, 4) sage: _is_a_splitting([1,3],[2,4,5,6],7) False sage: _is_a_splitting([1,3,4],[2,5,6],7) False sage: for P in SetPartitions(6,[3,3]): ....: res,aut= _is_a_splitting(P[0],P[1],7,return_automorphism=True) ....: if res: ....: print((aut, P[0], P[1])) (6, {1, 2, 3}, {4, 5, 6}) (3, {1, 2, 4}, {3, 5, 6}) (6, {1, 3, 5}, {2, 4, 6}) (6, {1, 4, 5}, {2, 3, 6}) We illustrate now how to find idempotents in quotient rings:: sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: F = GF(q) sage: P.<x> = PolynomialRing(F,"x") sage: I = Ideal(P,[x^n-1]) sage: Q.<x> = QuotientRing(P,I) sage: i1 = -sum([x^i for i in S1]); i1 2*x^9 + 2*x^5 + 2*x^4 + 2*x^3 + 2*x sage: i2 = -sum([x^i for i in S2]); i2 2*x^10 + 2*x^8 + 2*x^7 + 2*x^6 + 2*x^2 sage: i1^2 == i1 True sage: i2^2 == i2 True sage: (1-i1)^2 == 1-i1 True sage: (1-i2)^2 == 1-i2 True We return to dealing with polynomials (rather than elements of quotient rings), so we can construct cyclic codes:: sage: P.<x> = PolynomialRing(F,"x") sage: i1 = -sum([x^i for i in S1]) sage: i2 = -sum([x^i for i in S2]) sage: i1_sqrd = (i1^2).quo_rem(x^n-1)[1] sage: i1_sqrd == i1 True sage: i2_sqrd = (i2^2).quo_rem(x^n-1)[1] sage: i2_sqrd == i2 True sage: C1 = codes.CyclicCode(length = n, generator_pol = gcd(i1, x^n - 1)) sage: C2 = codes.CyclicCode(length = n, generator_pol = gcd(1-i2, x^n - 1)) sage: C1.dual_code().systematic_generator_matrix() == C2.systematic_generator_matrix() True This is a special case of Theorem 6.4.3 in [HP2003]_. """ R = IntegerModRing(n) S1 = set(R(x) for x in S1) S2 = set(R(x) for x in S2) # we first check whether (S1,S2) is a partition of R - {0} if (len(S1) + len(S2) != n - 1 or len(S1) != len(S2) or R.zero() in S1 or R.zero() in S2 or not S1.isdisjoint(S2)): if return_automorphism: return False, None else: return False # now that we know that (S1,S2) is a partition, we look for an invertible # element b that maps S1 to S2 by multiplication for b in range(2, n): if GCD(b, n) == 1 and all(b * x in S2 for x in S1): if return_automorphism: return True, b else: return True if return_automorphism: return False, None else: return False
def has_equivalent_Jordan_decomposition_at_prime(self, other, p): """ Determines if the given quadratic form has a Jordan decomposition equivalent to that of self. INPUT: a QuadraticForm OUTPUT: boolean EXAMPLES:: sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 1, 0, 3]) sage: Q2 = QuadraticForm(ZZ, 3, [1, 0, 0, 2, -2, 6]) sage: Q3 = QuadraticForm(ZZ, 3, [1, 0, 0, 1, 0, 11]) sage: [Q1.level(), Q2.level(), Q3.level()] [44, 44, 44] sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,2) False sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,11) False sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,2) False sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,11) True sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,2) True sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,11) False """ ## Sanity Checks #if not isinstance(other, QuadraticForm): if not isinstance(other, type(self)): raise TypeError( "Oops! The first argument must be of type QuadraticForm.") if not is_prime(p): raise TypeError("Oops! The second argument must be a prime number.") ## Get the relevant local normal forms quickly self_jordan = self.jordan_blocks_by_scale_and_unimodular(p, safe_flag=False) other_jordan = other.jordan_blocks_by_scale_and_unimodular(p, safe_flag=False) ## DIAGNOSTIC #print "self_jordan = ", self_jordan #print "other_jordan = ", other_jordan ## Check for the same number of Jordan components if len(self_jordan) != len(other_jordan): return False ## Deal with odd primes: Check that the Jordan component scales, dimensions, and discriminants are the same if p != 2: for i in range(len(self_jordan)): if (self_jordan[i][0] != other_jordan[i][0]) \ or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) \ or (legendre_symbol(self_jordan[i][1].det() * other_jordan[i][1].det(), p) != 1): return False ## All tests passed for an odd prime. return True ## For p = 2: Check that all Jordan Invariants are the same. elif p == 2: ## Useful definition t = len(self_jordan) ## Define t = Number of Jordan components ## Check that all Jordan Invariants are the same (scale, dim, and norm) for i in range(t): if (self_jordan[i][0] != other_jordan[i][0]) \ or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) \ or (valuation(GCD(self_jordan[i][1].coefficients()), p) != valuation(GCD(other_jordan[i][1].coefficients()), p)): return False ## DIAGNOSTIC #print "Passed the Jordan invariant test." ## Use O'Meara's isometry test 93:29 on p277. ## ------------------------------------------ ## List of norms, scales, and dimensions for each i scale_list = [ZZ(2)**self_jordan[i][0] for i in range(t)] norm_list = [ ZZ(2)**(self_jordan[i][0] + valuation(GCD(self_jordan[i][1].coefficients()), 2)) for i in range(t) ] dim_list = [(self_jordan[i][1].dim()) for i in range(t)] ## List of Hessian determinants and Hasse invariants for each Jordan (sub)chain ## (Note: This is not the same as O'Meara's Gram determinants, but ratios are the same!) -- NOT SO GOOD... ## But it matters in condition (ii), so we multiply all by 2 (instead of dividing by 2 since only square-factors matter, and it's easier.) j = 0 self_chain_det_list = [ self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j]) ] other_chain_det_list = [ other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j]) ] self_hasse_chain_list = [ self_jordan[j][1].scale_by_factor( ZZ(2)**self_jordan[j][0]).hasse_invariant__OMeara(2) ] other_hasse_chain_list = [ other_jordan[j][1].scale_by_factor( ZZ(2)**other_jordan[j][0]).hasse_invariant__OMeara(2) ] for j in range(1, t): self_chain_det_list.append(self_chain_det_list[j - 1] * self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])) other_chain_det_list.append(other_chain_det_list[j - 1] * other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])) self_hasse_chain_list.append(self_hasse_chain_list[j-1] \ * hilbert_symbol(self_chain_det_list[j-1], self_jordan[j][1].Gram_det(), 2) \ * self_jordan[j][1].hasse_invariant__OMeara(2)) other_hasse_chain_list.append(other_hasse_chain_list[j-1] \ * hilbert_symbol(other_chain_det_list[j-1], other_jordan[j][1].Gram_det(), 2) \ * other_jordan[j][1].hasse_invariant__OMeara(2)) ## SANITY CHECK -- check that the scale powers are strictly increasing for i in range(1, len(scale_list)): if scale_list[i - 1] >= scale_list[i]: raise RuntimeError( "Oops! There is something wrong with the Jordan Decomposition -- the given scales are not strictly increasing!" ) ## DIAGNOSTIC #print "scale_list = ", scale_list #print "norm_list = ", norm_list #print "dim_list = ", dim_list #print #print "self_chain_det_list = ", self_chain_det_list #print "other_chain_det_list = ", other_chain_det_list #print "self_hasse_chain_list = ", self_hasse_chain_list #print "other_hasse_chain_det_list = ", other_hasse_chain_list ## Test O'Meara's two conditions for i in range(t - 1): ## Condition (i): Check that their (unit) ratio is a square (but it suffices to check at most mod 8). modulus = norm_list[i] * norm_list[i + 1] / (scale_list[i]**2) if modulus > 8: modulus = 8 if (modulus > 1) and (( (self_chain_det_list[i] / other_chain_det_list[i]) % modulus) != 1): #print "Failed when i =", i, " in condition 1." return False ## Check O'Meara's condition (ii) when appropriate if norm_list[i + 1] % (4 * norm_list[i]) == 0: if self_hasse_chain_list[i] * hilbert_symbol(norm_list[i] * other_chain_det_list[i], -self_chain_det_list[i], 2) \ != other_hasse_chain_list[i] * hilbert_symbol(norm_list[i], -other_chain_det_list[i], 2): ## Nipp conditions #print "Failed when i =", i, " in condition 2." return False ## All tests passed for the prime 2. return True else: raise TypeError("Oops! This should not have happened.")
def local_normal_form(self, p): """ Returns the a locally integrally equivalent quadratic form over the p-adic integers Z_p which gives the Jordan decomposition. The Jordan components are written as sums of blocks of size <= 2 and are arranged by increasing scale, and then by increasing norm. (This is equivalent to saying that we put the 1x1 blocks before the 2x2 blocks in each Jordan component.) INPUT: `p` -- a positive prime number. OUTPUT: a quadratic form over ZZ WARNING: Currently this only works for quadratic forms defined over ZZ. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [10,4,1]) sage: Q.local_normal_form(5) Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 6 ] :: sage: Q.local_normal_form(3) Quadratic form in 2 variables over Integer Ring with coefficients: [ 10 0 ] [ * 15 ] sage: Q.local_normal_form(2) Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 6 ] """ ## Sanity Checks if (self.base_ring() != IntegerRing()): raise NotImplementedError( "Oops! This currently only works for quadratic forms defined over IntegerRing(). =(" ) if not ((p >= 2) and is_prime(p)): raise TypeError("Oops! p is not a positive prime number. =(") ## Some useful local variables Q = copy.deepcopy(self) Q.__init__(self.base_ring(), self.dim(), self.coefficients()) ## Prepare the final form to return Q_Jordan = copy.deepcopy(self) Q_Jordan.__init__(self.base_ring(), 0) while Q.dim() > 0: n = Q.dim() ## Step 1: Find the minimally p-divisible matrix entry, preferring diagonals ## ------------------------------------------------------------------------- (min_i, min_j) = Q.find_entry_with_minimal_scale_at_prime(p) if min_i == min_j: min_val = valuation(2 * Q[min_i, min_j], p) else: min_val = valuation(Q[min_i, min_j], p) ## Error if we still haven't seen non-zero coefficients! if (min_val == Infinity): raise RuntimeError("Oops! The original matrix is degenerate. =(") ## Step 2: Arrange for the upper leftmost entry to have minimal valuation ## ---------------------------------------------------------------------- if (min_i == min_j): block_size = 1 Q.swap_variables(0, min_i, in_place=True) else: ## Work in the upper-left 2x2 block, and replace it by its 2-adic equivalent form Q.swap_variables(0, min_i, in_place=True) Q.swap_variables(1, min_j, in_place=True) ## 1x1 => make upper left the smallest if (p != 2): block_size = 1 Q.add_symmetric(1, 0, 1, in_place=True) ## 2x2 => replace it with the appropriate 2x2 matrix else: block_size = 2 ## DIAGNOSTIC #print "\n Finished Step 2 \n"; #print "\n Q is: \n" + str(Q) + "\n"; #print " p is: " + str(p) #print " min_val is: " + str( min_val) #print " block_size is: " + str(block_size) #print "\n Starting Step 3 \n" ## Step 3: Clear out the remaining entries ## --------------------------------------- min_scale = p**min_val ## This is the minimal valuation of the Hessian matrix entries. ##DIAGNOSTIC #print "Starting Step 3:" #print "----------------" #print " min_scale is: " + str(min_scale) ## Perform cancellation over Z by ensuring divisibility if (block_size == 1): a = 2 * Q[0, 0] for j in range(block_size, n): b = Q[0, j] g = GCD(a, b) ## DIAGNSOTIC #print "Cancelling from a 1x1 block:" #print "----------------------------" #print " Cancelling entry with index (" + str(upper_left) + ", " + str(j) + ")" #print " entry = " + str(b) #print " gcd = " + str(g) #print " a = " + str(a) #print " b = " + str(b) #print " a/g = " + str(a/g) + " (used for stretching)" #print " -b/g = " + str(-b/g) + " (used for cancelling)" ## Sanity Check: a/g is a p-unit if valuation(g, p) != valuation(a, p): raise RuntimeError( "Oops! We have a problem with our rescaling not preserving p-integrality!" ) Q.multiply_variable( ZZ(a / g), j, in_place=True ) ## Ensures that the new b entry is divisible by a Q.add_symmetric(ZZ(-b / g), j, 0, in_place=True) ## Performs the cancellation elif (block_size == 2): a1 = 2 * Q[0, 0] a2 = Q[0, 1] b1 = Q[1, 0] ## This is the same as a2 b2 = 2 * Q[1, 1] big_det = (a1 * b2 - a2 * b1) small_det = big_det / (min_scale * min_scale) ## Cancels out the rows/columns of the 2x2 block for j in range(block_size, n): a = Q[0, j] b = Q[1, j] ## Ensures an integral result (scale jth row/column by big_det) Q.multiply_variable(big_det, j, in_place=True) ## Performs the cancellation (by producing -big_det * jth row/column) Q.add_symmetric(ZZ(-(a * b2 - b * a2)), j, 0, in_place=True) Q.add_symmetric(ZZ(-(-a * b1 + b * a1)), j, 1, in_place=True) ## Now remove the extra factor (non p-unit factor) in big_det we introduced above Q.divide_variable(ZZ(min_scale * min_scale), j, in_place=True) ## DIAGNOSTIC #print "Cancelling out a 2x2 block:" #print "---------------------------" #print " a1 = " + str(a1) #print " a2 = " + str(a2) #print " b1 = " + str(b1) #print " b2 = " + str(b2) #print " big_det = " + str(big_det) #print " min_scale = " + str(min_scale) #print " small_det = " + str(small_det) #print " Q = \n", Q ## Uses Cassels's proof to replace the remaining 2 x 2 block if (((1 + small_det) % 8) == 0): Q[0, 0] = 0 Q[1, 1] = 0 Q[0, 1] = min_scale elif (((5 + small_det) % 8) == 0): Q[0, 0] = min_scale Q[1, 1] = min_scale Q[0, 1] = min_scale else: raise RuntimeError( "Error in LocalNormal: Impossible behavior for a 2x2 block! \n" ) ## Check that the cancellation worked, extract the upper-left block, and trim Q to handle the next block. for i in range(block_size): for j in range(block_size, n): if Q[i, j] != 0: raise RuntimeError( "Oops! The cancellation didn't work properly at entry (" + str(i) + ", " + str(j) + ").") Q_Jordan = Q_Jordan + Q.extract_variables(range(block_size)) Q = Q.extract_variables(range(block_size, n)) return Q_Jordan
def CyclicCodeFromGeneratingPolynomial(n, g, ignore=True): r""" If g is a polynomial over GF(q) which divides `x^n-1` then this constructs the code "generated by g" (ie, the code associated with the principle ideal `gR` in the ring `R = GF(q)[x]/(x^n-1)` in the usual way). The option "ignore" says to ignore the condition that (a) the characteristic of the base field does not divide the length (the usual assumption in the theory of cyclic codes), and (b) `g` must divide `x^n-1`. If ignore=True, instead of returning an error, a code generated by `gcd(x^n-1,g)` is created. EXAMPLES:: sage: P.<x> = PolynomialRing(GF(3),"x") sage: g = x-1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C Linear code of length 4, dimension 3 over Finite Field of size 3 sage: P.<x> = PolynomialRing(GF(4,"a"),"x") sage: g = x^3+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(9,g); C Linear code of length 9, dimension 6 over Finite Field in a of size 2^2 sage: P.<x> = PolynomialRing(GF(2),"x") sage: g = x^3+x+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(7,g); C Linear code of length 7, dimension 4 over Finite Field of size 2 sage: C.generator_matrix() [1 1 0 1 0 0 0] [0 1 1 0 1 0 0] [0 0 1 1 0 1 0] [0 0 0 1 1 0 1] sage: g = x+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C Linear code of length 4, dimension 3 over Finite Field of size 2 sage: C.generator_matrix() [1 1 0 0] [0 1 1 0] [0 0 1 1] On the other hand, CyclicCodeFromPolynomial(4,x) will produce a ValueError including a traceback error message: "`x` must divide `x^4 - 1`". You will also get a ValueError if you type :: sage: P.<x> = PolynomialRing(GF(4,"a"),"x") sage: g = x^2+1 followed by CyclicCodeFromGeneratingPolynomial(6,g). You will also get a ValueError if you type :: sage: P.<x> = PolynomialRing(GF(3),"x") sage: g = x^2-1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(5,g); C Linear code of length 5, dimension 4 over Finite Field of size 3 followed by C = CyclicCodeFromGeneratingPolynomial(5,g,False), with a traceback message including "`x^2 + 2` must divide `x^5 - 1`". """ P = g.parent() x = P.gen() F = g.base_ring() p = F.characteristic() if not (ignore) and p.divides(n): raise ValueError('The characteristic %s must not divide %s' % (p, n)) if not (ignore) and not (g.divides(x**n - 1)): raise ValueError('%s must divide x^%s - 1' % (g, n)) gn = GCD([g, x**n - 1]) d = gn.degree() coeffs = Sequence(gn.list()) r1 = Sequence(coeffs + [0] * (n - d - 1)) Sn = SymmetricGroup(n) s = Sn.gens()[0] # assumes 1st gen of S_n is (1,2,...,n) rows = [permutation_action(s**(-i), r1) for i in range(n - d)] MS = MatrixSpace(F, n - d, n) return LinearCode(MS(rows))
def gcd(self): return GCD([n for n in self._data.itervalues()])