def griesmer_upper_bound(n, q, d, algorithm=None): r""" Returns the Griesmer upper bound for number of elements in the largest code of minimum distance d in `\GF{q}^n`. Wraps GAP's UpperBoundGriesmer. EXAMPLES:: sage: griesmer_upper_bound(10,2,3) 128 sage: griesmer_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 128 """ if algorithm == "gap": #print "calling Guava ..." ans = gap.eval("UpperBoundGriesmer(%s,%s,%s)" % (n, d, q)) return QQ(ans) else: den = 1 s = 0 k = 0 add = 0 while s <= n: if not (add == 1): if d % den == 0: add = int(d / den) else: add = int(d / den) + 1 s = s + add den = den * q k = k + 1 return q**(k - 1)
def elias_upper_bound(n,q,d,algorithm=None): r""" Returns the Elias upper bound for number of elements in the largest code of minimum distance d in `\GF{q}^n`. Wraps GAP's UpperBoundElias. EXAMPLES:: sage: elias_upper_bound(10,2,3) 232 sage: elias_upper_bound(10,2,3,algorithm="gap") # requires optional GAP package Guava 232 """ r = 1-1/q if algorithm=="gap": #print "calling Guava ..." ans=gap.eval("UpperBoundElias(%s,%s,%s)"%(n,d,q)) return QQ(ans) else: def ff(n,d,w,q): return r*n*d*q**n/((w**2-2*r*n*w+r*n*d)*volume_hamming(n,q,w)); def get_list(n,d,q): I = [] for i in range(1,int(r*n)+1): if i**2-2*r*n*i+r*n*d>0: I.append(i) return I I = get_list(n,d,q) bnd = min([ff(n,d,w,q) for w in I]) return int(bnd)
def plotkin_upper_bound(n, q, d, algorithm=None): r""" Returns Plotkin upper bound for number of elements in the largest code of minimum distance d in `\GF{q}^n`. The algorithm="gap" option wraps Guava's UpperBoundPlotkin. EXAMPLES:: sage: plotkin_upper_bound(10,2,3) 192 sage: plotkin_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 192 """ if algorithm == "gap": ans = gap.eval("UpperBoundPlotkin(%s,%s,%s)" % (n, d, q)) #print "calling Guava ..." return QQ(ans) else: t = 1 - 1 / q if (q == 2) and (n == 2 * d) and (d % 2 == 0): return 4 * d elif (q == 2) and (n == 2 * d + 1) and (d % 2 == 1): return 4 * d + 4 elif d > t * n: return int(d / (d - t * n)) elif d < t * n + 1: fact = (d - 1) / t if RR(fact) == RR(int(fact)): fact = int(fact) + 1 return int(d / (d - t * fact)) * q**(n - fact)
def elias_upper_bound(n, q, d, algorithm=None): r""" Returns the Elias upper bound for number of elements in the largest code of minimum distance d in `\GF{q}^n`. Wraps GAP's UpperBoundElias. EXAMPLES:: sage: elias_upper_bound(10,2,3) 232 sage: elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 232 """ r = 1 - 1 / q if algorithm == "gap": #print "calling Guava ..." ans = gap.eval("UpperBoundElias(%s,%s,%s)" % (n, d, q)) return QQ(ans) else: def ff(n, d, w, q): return r * n * d * q**n / ( (w**2 - 2 * r * n * w + r * n * d) * volume_hamming(n, q, w)) def get_list(n, d, q): I = [] for i in range(1, int(r * n) + 1): if i**2 - 2 * r * n * i + r * n * d > 0: I.append(i) return I I = get_list(n, d, q) bnd = min([ff(n, d, w, q) for w in I]) return int(bnd)
def griesmer_upper_bound(n,q,d,algorithm=None): r""" Returns the Griesmer upper bound for number of elements in the largest code of minimum distance d in `\GF{q}^n`. Wraps GAP's UpperBoundGriesmer. EXAMPLES:: sage: griesmer_upper_bound(10,2,3) 128 sage: griesmer_upper_bound(10,2,3,algorithm="gap") # requires optional GAP package Guava 128 """ if algorithm=="gap": #print "calling Guava ..." ans=gap.eval("UpperBoundGriesmer(%s,%s,%s)"%(n,d,q)) return QQ(ans) else: den = 1 s = 0 k = 0 add = 0 while s <= n: if not(add == 1): if d%den==0: add = int(d/den) else: add = int(d/den)+1 s = s + add den = den * q k = k + 1 return q**(k-1)
def cpi(self, p): """ Returns the centrally primitive idempotent for the symmetric group of order n for the irreducible corresponding indexed by the partition p. EXAMPLES:: sage: QS3 = SymmetricGroupAlgebra(QQ,3) sage: QS3.cpi([2,1]) 2/3*[1, 2, 3] - 1/3*[2, 3, 1] - 1/3*[3, 1, 2] sage: QS3.cpi([3]) 1/6*[1, 2, 3] + 1/6*[1, 3, 2] + 1/6*[2, 1, 3] + 1/6*[2, 3, 1] + 1/6*[3, 1, 2] + 1/6*[3, 2, 1] sage: QS3.cpi([1,1,1]) 1/6*[1, 2, 3] - 1/6*[1, 3, 2] - 1/6*[2, 1, 3] + 1/6*[2, 3, 1] + 1/6*[3, 1, 2] - 1/6*[3, 2, 1] """ if p not in partition.Partitions_n(self.n): raise TypeError, "p must be a partition of %s" % self.n character_table = eval( gap.eval("Display(Irr(SymmetricGroup(%d)));" % self.n)) cpi = self(0) np = partition.Partitions_n(self.n).list() np.reverse() p_index = np.index(p) big_coeff = character_table[p_index][0] / factorial(self.n) for g in permutation.StandardPermutations_n(self.n): cpi += big_coeff * character_table[p_index][np.index( g.inverse().cycle_type())] * self(g) return cpi
def plotkin_upper_bound(n,q,d, algorithm=None): r""" Returns Plotkin upper bound for number of elements in the largest code of minimum distance d in `\GF{q}^n`. The algorithm="gap" option wraps Guava's UpperBoundPlotkin. EXAMPLES:: sage: plotkin_upper_bound(10,2,3) 192 sage: plotkin_upper_bound(10,2,3,algorithm="gap") # requires optional GAP package Guava 192 """ if algorithm=="gap": ans=gap.eval("UpperBoundPlotkin(%s,%s,%s)"%(n,d,q)) #print "calling Guava ..." return QQ(ans) else: t = 1 - 1/q if (q==2) and (n == 2*d) and (d%2 == 0): return 4*d elif (q==2) and (n == 2*d + 1) and (d%2 == 1): return 4*d + 4 elif d > t*n: return int(d/( d - t*n)) elif d < t*n + 1: fact = (d-1) / t if RR(fact)==RR(int(fact)): fact = int(fact) + 1 return int(d/( d - t * fact)) * q**(n - fact)
def codesize_upper_bound(n,d,q,algorithm=None): r""" This computes the minimum value of the upper bound using the algorithms of Singleton, Hamming, Plotkin and Elias. If algorithm="gap" then this returns the best known upper bound `A(n,d)=A_q(n,d)` for the size of a code of length n, minimum distance d over a field of size q. The function first checks for trivial cases (like d=1 or n=d), and if the value is in the built-in table. Then it calculates the minimum value of the upper bound using the algorithms of Singleton, Hamming, Johnson, Plotkin and Elias. If the code is binary, `A(n, 2\ell-1) = A(n+1,2\ell)`, so the function takes the minimum of the values obtained from all algorithms for the parameters `(n, 2\ell-1)` and `(n+1, 2\ell)`. This wraps GUAVA's UpperBound( n, d, q ). EXAMPLES:: sage: codesize_upper_bound(10,3,2) 93 sage: codesize_upper_bound(10,3,2,algorithm="gap") # requires optional GAP package Guava 85 """ if algorithm=="gap": return int(gap.eval("UpperBound(%s,%s,%s)"%( n, d, q ))) else: eub = elias_upper_bound(n,q,d) gub = griesmer_upper_bound(n,q,d) hub = hamming_upper_bound(n,q,d) pub = plotkin_upper_bound(n,q,d) sub = singleton_upper_bound(n,q,d) return min([eub,gub,hub,pub,sub])
def elias_upper_bound(n,q,d,algorithm=None): r""" Returns the Elias upper bound. Returns the Elias upper bound for number of elements in the largest code of minimum distance `d` in `\GF{q}^n`, cf. [HP2003]_. If the method is "gap", it wraps GAP's ``UpperBoundElias``. EXAMPLES:: sage: codes.bounds.elias_upper_bound(10,2,3) 232 sage: codes.bounds.elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 232 """ _check_n_q_d(n, q, d, field_based=False) r = 1-1/q if algorithm=="gap": gap.load_package("guava") ans=gap.eval("UpperBoundElias(%s,%s,%s)"%(n,d,q)) return QQ(ans) else: def ff(n,d,w,q): return r*n*d*q**n/((w**2-2*r*n*w+r*n*d)*volume_hamming(n,q,w)); def get_list(n,d,q): I = [] for i in range(1,int(r*n)+1): if i**2-2*r*n*i+r*n*d>0: I.append(i) return I I = get_list(n,d,q) bnd = min([ff(n,d,w,q) for w in I]) return int(bnd)
def cpi(self, p): """ Returns the centrally primitive idempotent for the symmetric group of order n for the irreducible corresponding indexed by the partition p. EXAMPLES:: sage: QS3 = SymmetricGroupAlgebra(QQ,3) sage: QS3.cpi([2,1]) 2/3*[1, 2, 3] - 1/3*[2, 3, 1] - 1/3*[3, 1, 2] sage: QS3.cpi([3]) 1/6*[1, 2, 3] + 1/6*[1, 3, 2] + 1/6*[2, 1, 3] + 1/6*[2, 3, 1] + 1/6*[3, 1, 2] + 1/6*[3, 2, 1] sage: QS3.cpi([1,1,1]) 1/6*[1, 2, 3] - 1/6*[1, 3, 2] - 1/6*[2, 1, 3] + 1/6*[2, 3, 1] + 1/6*[3, 1, 2] - 1/6*[3, 2, 1] """ if p not in partition.Partitions_n(self.n): raise TypeError, "p must be a partition of %s"%self.n character_table = eval(gap.eval("Display(Irr(SymmetricGroup(%d)));"%self.n)) cpi = self(0) np = partition.Partitions_n(self.n).list() np.reverse() p_index = np.index(p) big_coeff = character_table[p_index][0]/factorial(self.n) for g in permutation.StandardPermutations_n(self.n): cpi += big_coeff * character_table[p_index][np.index(g.inverse().cycle_type())] * self(g) return cpi
def RandomLinearCodeGuava(n,k,F): r""" The method used is to first construct a `k \times n` matrix of the block form `(I,A)`, where `I` is a `k \times k` identity matrix and `A` is a `k \times (n-k)` matrix constructed using random elements of `F`. Then the columns are permuted using a randomly selected element of the symmetric group `S_n`. INPUT: - ``n,k`` -- integers with `n>k>1`. OUTPUT: Returns a "random" linear code with length `n`, dimension `k` over field `F`. EXAMPLES:: sage: C = codes.RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_packages (Guava package) Linear code of length 30, dimension 15 over Finite Field of size 2 sage: C = codes.RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_packages (Guava package) Linear code of length 10, dimension 5 over Finite Field in a of size 2^2 AUTHOR: David Joyner (11-2005) """ current_randstate().set_seed_gap() q = F.order() gap.eval("C:=RandomLinearCode("+str(n)+","+str(k)+", GF("+str(q)+"))") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i,j)),F) for j in range(1,n+1)] for i in range(1,k+1)] MS = MatrixSpace(F,k,n) return LinearCode(MS(G))
def RandomLinearCodeGuava(n,k,F): r""" The method used is to first construct a `k \times n` matrix of the block form `(I,A)`, where `I` is a `k \times k` identity matrix and `A` is a `k \times (n-k)` matrix constructed using random elements of `F`. Then the columns are permuted using a randomly selected element of the symmetric group `S_n`. INPUT: Integers `n,k`, with `n>k>1`. OUTPUT: Returns a "random" linear code with length n, dimension k over field F. EXAMPLES:: sage: C = RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_packages (Guava package) Linear code of length 30, dimension 15 over Finite Field of size 2 sage: C = RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_packages (Guava package) Linear code of length 10, dimension 5 over Finite Field in a of size 2^2 AUTHOR: David Joyner (11-2005) """ current_randstate().set_seed_gap() q = F.order() gap.eval("C:=RandomLinearCode("+str(n)+","+str(k)+", GF("+str(q)+"))") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i,j)),F) for j in range(1,n+1)] for i in range(1,k+1)] MS = MatrixSpace(F,k,n) return LinearCode(MS(G))
def cardinality(self): """ EXAMPLES:: sage: S = [1,2,3,4,5] sage: UnorderedTuples(S,2).cardinality() 15 """ ans=gap.eval("NrUnorderedTuples(%s,%s)"%(self._index_list,ZZ(self.k))) return ZZ(ans)
def cardinality(self): """ EXAMPLES:: sage: S = [1,2,3,4,5] sage: UnorderedTuples(S,2).cardinality() 15 """ ans=gap.eval("NrUnorderedTuples(%s,%s)"%(self._index_list,ZZ(self.k))) return ZZ(ans)
def griesmer_upper_bound(n,q,d,algorithm=None): r""" Returns the Griesmer upper bound. Returns the Griesmer upper bound for the number of elements in a largest linear code of minimum distance `d` in `\GF{q}^n`, cf. [HP2003]_. If the method is "gap", it wraps GAP's ``UpperBoundGriesmer``. The bound states: .. MATH:: `n\geq \sum_{i=0}^{k-1} \lceil d/q^i \rceil.` EXAMPLES: The bound is reached for the ternary Golay codes:: sage: codes.bounds.griesmer_upper_bound(12,3,6) 729 sage: codes.bounds.griesmer_upper_bound(11,3,5) 729 :: sage: codes.bounds.griesmer_upper_bound(10,2,3) 128 sage: codes.bounds.griesmer_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 128 TESTS:: sage: codes.bounds.griesmer_upper_bound(11,3,6) 243 sage: codes.bounds.griesmer_upper_bound(11,3,6) 243 """ _check_n_q_d(n, q, d) if algorithm=="gap": gap.load_package("guava") ans=gap.eval("UpperBoundGriesmer(%s,%s,%s)"%(n,d,q)) return QQ(ans) else: #To compute the bound, we keep summing up the terms on the RHS #until we start violating the inequality. from sage.functions.other import ceil den = 1 s = 0 k = 0 while s <= n: s += ceil(d/den) den *= q k = k + 1 return q**(k-1)
def list(self): """ EXAMPLES:: sage: S = [1,2] sage: UnorderedTuples(S,3).list() [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]] sage: UnorderedTuples(["a","b","c"],2).list() [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], ['c', 'c']] """ ans=gap.eval("UnorderedTuples(%s,%s)"%(self._index_list,ZZ(self.k))) return map(lambda l: map(lambda i: self.S[i], l), eval(ans))
def list(self): """ EXAMPLES:: sage: S = [1,2] sage: UnorderedTuples(S,3).list() [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]] sage: UnorderedTuples(["a","b","c"],2).list() [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], ['c', 'c']] """ ans=gap.eval("UnorderedTuples(%s,%s)"%(self._index_list,ZZ(self.k))) return map(lambda l: map(lambda i: self.S[i], l), eval(ans))
def list(self): """ EXAMPLES:: sage: S = [1,2] sage: UnorderedTuples(S,3).list() [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]] sage: UnorderedTuples(["a","b","c"],2).list() [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], ['c', 'c']] """ ans=gap.eval("UnorderedTuples(%s,%s)"%(self._index_list,ZZ(self.k))) return [[self.S[i] for i in l] for l in eval(ans)]
def cardinality(self): """ Returns the size of combinations(mset,k). IMPLEMENTATION: Wraps GAP's NrCombinations. EXAMPLES:: sage: mset = [1,1,2,3,4,4,5] sage: Combinations(mset,2).cardinality() 12 """ items = map(self.mset.index, self.mset) return ZZ(gap.eval("NrCombinations({},{})".format( items,ZZ(self.k))) )
def cardinality(self): """ Returns the size of combinations(mset,k). IMPLEMENTATION: Wraps GAP's NrCombinations. EXAMPLES:: sage: mset = [1,1,2,3,4,4,5] sage: Combinations(mset,2).cardinality() 12 """ items = map(self.mset.index, self.mset) return ZZ(gap.eval("NrCombinations(%s,%s)" % (items, ZZ(self.k))))
def list(self): """ EXAMPLES:: sage: S = [1,2] sage: UnorderedTuples(S,3).list() [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]] sage: UnorderedTuples(["a","b","c"],2).list() [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], ['c', 'c']] """ ans = gap.eval("UnorderedTuples(%s,%s)" % (self._index_list, ZZ(self.k))) return [[self.S[i] for i in l] for l in eval(ans)]
def cardinality(self): """ Returns the size of combinations(mset,k). IMPLEMENTATION: Wraps GAP's NrCombinations. EXAMPLES:: sage: mset = [1,1,2,3,4,4,5] sage: Combinations(mset,2).cardinality() 12 """ items = [self.mset.index(_) for _ in self.mset] return ZZ(gap.eval("NrCombinations({},{})".format(items, ZZ(self.k))))
def cpi(self, p): """ Return the centrally primitive idempotent for the symmetric group of order `n` corresponding to the irreducible representation indexed by the partition ``p``. EXAMPLES:: sage: QS3 = SymmetricGroupAlgebra(QQ,3) sage: QS3.cpi([2,1]) 2/3*[1, 2, 3] - 1/3*[2, 3, 1] - 1/3*[3, 1, 2] sage: QS3.cpi([3]) 1/6*[1, 2, 3] + 1/6*[1, 3, 2] + 1/6*[2, 1, 3] + 1/6*[2, 3, 1] + 1/6*[3, 1, 2] + 1/6*[3, 2, 1] sage: QS3.cpi([1,1,1]) 1/6*[1, 2, 3] - 1/6*[1, 3, 2] - 1/6*[2, 1, 3] + 1/6*[2, 3, 1] + 1/6*[3, 1, 2] - 1/6*[3, 2, 1] sage: QS0 = SymmetricGroupAlgebra(QQ, 0) sage: QS0.cpi(Partition([])) [] TESTS:: sage: QS3.cpi([2,2]) Traceback (most recent call last): ... TypeError: p (= [2, 2]) must be a partition of n (= 3) """ if p not in partition.Partitions_n(self.n): raise TypeError( "p (= {p}) must be a partition of n (= {n})".format(p=p, n=self.n)) character_table = eval( gap.eval("Display(Irr(SymmetricGroup(%d)));" % self.n)) cpi = self.zero() np = partition.Partitions_n(self.n).list() np.reverse() p_index = np.index(p) big_coeff = character_table[p_index][0] / factorial(self.n) character_row = character_table[p_index] dct = { g: big_coeff * character_row[np.index(g.cycle_type())] for g in permutation.StandardPermutations_n(self.n) } return self._from_dict(dct)
def BinaryReedMullerCode(r, k): r""" The binary 'Reed-Muller code' with dimension k and order r is a code with length `2^k` and minimum distance `2^k-r` (see for example, section 1.10 in [HP]_). By definition, the `r^{th}` order binary Reed-Muller code of length `n=2^m`, for `0 \leq r \leq m`, is the set of all vectors `(f(p)\ |\ p \in GF(2)^m)`, where `f` is a multivariate polynomial of degree at most `r` in `m` variables. INPUT: - ``r, k`` -- positive integers with `2^k>r`. OUTPUT: Returns the binary 'Reed-Muller code' with dimension `k` and order `r`. EXAMPLE:: sage: C = codes.BinaryReedMullerCode(2,4); C # optional - gap_packages (Guava package) Linear code of length 16, dimension 11 over Finite Field of size 2 sage: C.minimum_distance() # optional - gap_packages (Guava package) 4 sage: C.generator_matrix() # optional - gap_packages (Guava package) [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1] [0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1] [0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1] [0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1] [0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1] [0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1] [0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1] [0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1] [0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1] [0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1] [0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1] AUTHOR: David Joyner (11-2005) """ F = GF(2) gap.load_package("guava") gap.eval("C:=ReedMullerCode(" + str(r) + ", " + str(k) + ")") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[ gfq_gap_to_sage(gap.eval("G[" + str(i) + "][" + str(j) + "]"), F) for j in range(1, n + 1) ] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def codesize_upper_bound(n,d,q,algorithm=None): r""" This computes the minimum value of the upper bound using the methods of Singleton, Hamming, Plotkin, and Elias. If algorithm="gap" then this returns the best known upper bound `A(n,d)=A_q(n,d)` for the size of a code of length n, minimum distance d over a field of size q. The function first checks for trivial cases (like d=1 or n=d), and if the value is in the built-in table. Then it calculates the minimum value of the upper bound using the algorithms of Singleton, Hamming, Johnson, Plotkin and Elias. If the code is binary, `A(n, 2\ell-1) = A(n+1,2\ell)`, so the function takes the minimum of the values obtained from all algorithms for the parameters `(n, 2\ell-1)` and `(n+1, 2\ell)`. This wraps GUAVA's (i.e. GAP's package Guava) UpperBound( n, d, q ). If algorithm="LP" then this returns the Delsarte (a.k.a. Linear Programming) upper bound. EXAMPLES:: sage: codes.bounds.codesize_upper_bound(10,3,2) 93 sage: codes.bounds.codesize_upper_bound(24,8,2,algorithm="LP") 4096 sage: codes.bounds.codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_packages (Guava package) 85 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm=None) 123361 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_packages (Guava package) 123361 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="LP") 109226 """ if algorithm=="gap": gap.load_package('guava') return int(gap.eval("UpperBound(%s,%s,%s)"%( n, d, q ))) if algorithm=="LP": return int(delsarte_bound_hamming_space(n,d,q)) else: eub = elias_upper_bound(n,q,d) gub = griesmer_upper_bound(n,q,d) hub = hamming_upper_bound(n,q,d) pub = plotkin_upper_bound(n,q,d) sub = singleton_upper_bound(n,q,d) return min([eub,gub,hub,pub,sub])
def codesize_upper_bound(n, d, q, algorithm=None): r""" This computes the minimum value of the upper bound using the methods of Singleton, Hamming, Plotkin, and Elias. If algorithm="gap" then this returns the best known upper bound `A(n,d)=A_q(n,d)` for the size of a code of length n, minimum distance d over a field of size q. The function first checks for trivial cases (like d=1 or n=d), and if the value is in the built-in table. Then it calculates the minimum value of the upper bound using the algorithms of Singleton, Hamming, Johnson, Plotkin and Elias. If the code is binary, `A(n, 2\ell-1) = A(n+1,2\ell)`, so the function takes the minimum of the values obtained from all algorithms for the parameters `(n, 2\ell-1)` and `(n+1, 2\ell)`. This wraps GUAVA's (i.e. GAP's package Guava) UpperBound( n, d, q ). If algorithm="LP" then this returns the Delsarte (a.k.a. Linear Programming) upper bound. EXAMPLES:: sage: codes.bounds.codesize_upper_bound(10,3,2) 93 sage: codes.bounds.codesize_upper_bound(24,8,2,algorithm="LP") 4096 sage: codes.bounds.codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_packages (Guava package) 85 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm=None) 123361 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_packages (Guava package) 123361 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="LP") 109226 """ if algorithm == "gap": gap.load_package('guava') return int(gap.eval("UpperBound(%s,%s,%s)" % (n, d, q))) if algorithm == "LP": return int(delsarte_bound_hamming_space(n, d, q)) else: eub = elias_upper_bound(n, q, d) gub = griesmer_upper_bound(n, q, d) hub = hamming_upper_bound(n, q, d) pub = plotkin_upper_bound(n, q, d) sub = singleton_upper_bound(n, q, d) return min([eub, gub, hub, pub, sub])
def BinaryReedMullerCode(r,k): r""" The binary 'Reed-Muller code' with dimension k and order r is a code with length `2^k` and minimum distance `2^k-r` (see for example, section 1.10 in [HP]_). By definition, the `r^{th}` order binary Reed-Muller code of length `n=2^m`, for `0 \leq r \leq m`, is the set of all vectors `(f(p)\ |\ p \\in GF(2)^m)`, where `f` is a multivariate polynomial of degree at most `r` in `m` variables. INPUT: - ``r, k`` -- positive integers with `2^k>r`. OUTPUT: Returns the binary 'Reed-Muller code' with dimension `k` and order `r`. EXAMPLE:: sage: C = codes.BinaryReedMullerCode(2,4); C # optional - gap_packages (Guava package) Linear code of length 16, dimension 11 over Finite Field of size 2 sage: C.minimum_distance() # optional - gap_packages (Guava package) 4 sage: C.gen_mat() # optional - gap_packages (Guava package) [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1] [0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1] [0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1] [0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1] [0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1] [0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1] [0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1] [0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1] [0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1] [0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1] [0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1] AUTHOR: David Joyner (11-2005) """ F = GF(2) gap.load_package("guava") gap.eval("C:=ReedMullerCode("+str(r)+", "+str(k)+")") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[gfq_gap_to_sage(gap.eval("G["+str(i)+"]["+str(j)+"]"),F) for j in range(1,n+1)] for i in range(1,k+1)] MS = MatrixSpace(F,k,n) return LinearCode(MS(G))
def cpi(self, p): """ Return the centrally primitive idempotent for the symmetric group of order `n` corresponding to the irreducible representation indexed by the partition ``p``. EXAMPLES:: sage: QS3 = SymmetricGroupAlgebra(QQ,3) sage: QS3.cpi([2,1]) 2/3*[1, 2, 3] - 1/3*[2, 3, 1] - 1/3*[3, 1, 2] sage: QS3.cpi([3]) 1/6*[1, 2, 3] + 1/6*[1, 3, 2] + 1/6*[2, 1, 3] + 1/6*[2, 3, 1] + 1/6*[3, 1, 2] + 1/6*[3, 2, 1] sage: QS3.cpi([1,1,1]) 1/6*[1, 2, 3] - 1/6*[1, 3, 2] - 1/6*[2, 1, 3] + 1/6*[2, 3, 1] + 1/6*[3, 1, 2] - 1/6*[3, 2, 1] sage: QS0 = SymmetricGroupAlgebra(QQ, 0) sage: QS0.cpi(Partition([])) [] TESTS:: sage: QS3.cpi([2,2]) Traceback (most recent call last): ... TypeError: p (= [2, 2]) must be a partition of n (= 3) """ if p not in partition.Partitions_n(self.n): raise TypeError("p (= {p}) must be a partition of n (= {n})".format(p=p, n=self.n)) character_table = eval(gap.eval("Display(Irr(SymmetricGroup(%d)));"%self.n)) cpi = self.zero() np = partition.Partitions_n(self.n).list() np.reverse() p_index = np.index(p) big_coeff = character_table[p_index][0] / factorial(self.n) character_row = character_table[p_index] dct = { g : big_coeff * character_row[np.index(g.cycle_type())] for g in permutation.StandardPermutations_n(self.n) } return self._from_dict(dct)
def QuasiQuadraticResidueCode(p): r""" A (binary) quasi-quadratic residue code (or QQR code), as defined by Proposition 2.2 in [BM]_, has a generator matrix in the block form `G=(Q,N)`. Here `Q` is a `p \times p` circulant matrix whose top row is `(0,x_1,...,x_{p-1})`, where `x_i=1` if and only if `i` is a quadratic residue `\mod p`, and `N` is a `p \times p` circulant matrix whose top row is `(0,y_1,...,y_{p-1})`, where `x_i+y_i=1` for all `i`. INPUT: - ``p`` -- a prime `>2`. OUTPUT: Returns a QQR code of length `2p`. EXAMPLES:: sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_packages (Guava package) Linear code of length 22, dimension 11 over Finite Field of size 2 REFERENCES: .. [BM] Bazzi and Mitter, {\it Some constructions of codes from group actions}, (preprint March 2003, available on Mitter's MIT website). .. [Jresidue] D. Joyner, {\it On quadratic residue codes and hyperelliptic curves}, (preprint 2006) These are self-orthogonal in general and self-dual when $p \\equiv 3 \\pmod 4$. AUTHOR: David Joyner (11-2005) """ F = GF(2) gap.load_package("guava") gap.eval("C:=QQRCode(" + str(p) + ")") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[ gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1) ] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def QuasiQuadraticResidueCode(p): r""" A (binary) quasi-quadratic residue code (or QQR code), as defined by Proposition 2.2 in [BM]_, has a generator matrix in the block form `G=(Q,N)`. Here `Q` is a `p \times p` circulant matrix whose top row is `(0,x_1,...,x_{p-1})`, where `x_i=1` if and only if `i` is a quadratic residue `\mod p`, and `N` is a `p \times p` circulant matrix whose top row is `(0,y_1,...,y_{p-1})`, where `x_i+y_i=1` for all `i`. INPUT: - ``p`` -- a prime `>2`. OUTPUT: Returns a QQR code of length `2p`. EXAMPLES:: sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_packages (Guava package) Linear code of length 22, dimension 11 over Finite Field of size 2 REFERENCES: .. [BM] Bazzi and Mitter, {\it Some constructions of codes from group actions}, (preprint March 2003, available on Mitter's MIT website). .. [Jresidue] \D. Joyner, {\it On quadratic residue codes and hyperelliptic curves}, (preprint 2006) These are self-orthogonal in general and self-dual when $p \\equiv 3 \\pmod 4$. AUTHOR: David Joyner (11-2005) """ F = GF(2) gap.load_package("guava") gap.eval("C:=QQRCode(" + str(p) + ")") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1)] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def QuasiQuadraticResidueCode(p): r""" A (binary) quasi-quadratic residue code (or QQR code), as defined by Proposition 2.2 in [BM2003]_, has a generator matrix in the block form `G=(Q,N)`. Here `Q` is a `p \times p` circulant matrix whose top row is `(0,x_1,...,x_{p-1})`, where `x_i=1` if and only if `i` is a quadratic residue `\mod p`, and `N` is a `p \times p` circulant matrix whose top row is `(0,y_1,...,y_{p-1})`, where `x_i+y_i=1` for all `i`. INPUT: - ``p`` -- a prime `>2`. OUTPUT: Returns a QQR code of length `2p`. EXAMPLES:: sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_packages (Guava package) [22, 11] linear code over GF(2) REFERENCES: - [BM2003]_ - [Joy2006]_ These are self-orthogonal in general and self-dual when $p \\equiv 3 \\pmod 4$. AUTHOR: David Joyner (11-2005) """ F = GF(2) gap.load_package("guava") gap.eval("C:=QQRCode(" + str(p) + ")") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[ gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1) ] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def QuasiQuadraticResidueCode(p): r""" A (binary) quasi-quadratic residue code (or QQR code). Follows the definition of Proposition 2.2 in [BM]. The code has a generator matrix in the block form `G=(Q,N)`. Here `Q` is a `p \times p` circulant matrix whose top row is `(0,x_1,...,x_{p-1})`, where `x_i=1` if and only if `i` is a quadratic residue `\mod p`, and `N` is a `p \times p` circulant matrix whose top row is `(0,y_1,...,y_{p-1})`, where `x_i+y_i=1` for all `i`. INPUT: - ``p`` -- a prime `>2`. OUTPUT: Returns a QQR code of length `2p`. EXAMPLES:: sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_packages (Guava package) [22, 11] linear code over GF(2) These are self-orthogonal in general and self-dual when $p \\equiv 3 \\pmod 4$. AUTHOR: David Joyner (11-2005) """ if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') F = GF(2) gap.load_package("guava") gap.eval("C:=QQRCode(" + str(p) + ")") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1)] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def elias_upper_bound(n, q, d, algorithm=None): r""" Returns the Elias upper bound. Returns the Elias upper bound for number of elements in the largest code of minimum distance `d` in `\GF{q}^n`, cf. [HP2003]_. If the method is "gap", it wraps GAP's ``UpperBoundElias``. EXAMPLES:: sage: codes.bounds.elias_upper_bound(10,2,3) 232 sage: codes.bounds.elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 232 """ _check_n_q_d(n, q, d, field_based=False) r = 1 - 1 / q if algorithm == "gap": gap.load_package("guava") ans = gap.eval("UpperBoundElias(%s,%s,%s)" % (n, d, q)) return QQ(ans) else: def ff(n, d, w, q): return r * n * d * q**n / ( (w**2 - 2 * r * n * w + r * n * d) * volume_hamming(n, q, w)) def get_list(n, d, q): I = [] for i in range(1, int(r * n) + 1): if i**2 - 2 * r * n * i + r * n * d > 0: I.append(i) return I I = get_list(n, d, q) bnd = min([ff(n, d, w, q) for w in I]) return int(bnd)
def RandomLinearCodeGuava(n, k, F): r""" The method used is to first construct a `k \times n` matrix of the block form `(I,A)`, where `I` is a `k \times k` identity matrix and `A` is a `k \times (n-k)` matrix constructed using random elements of `F`. Then the columns are permuted using a randomly selected element of the symmetric group `S_n`. INPUT: - ``n,k`` -- integers with `n>k>1`. OUTPUT: Returns a "random" linear code with length `n`, dimension `k` over field `F`. EXAMPLES:: sage: C = codes.RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_packages (Guava package) [30, 15] linear code over GF(2) sage: C = codes.RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_packages (Guava package) [10, 5] linear code over GF(4) AUTHOR: David Joyner (11-2005) """ current_randstate().set_seed_gap() q = F.order() if not is_package_installed('gap_packages'): raise PackageNotFoundError('gap_packages') gap.load_package("guava") gap.eval("C:=RandomLinearCode("+str(n)+","+str(k)+", GF("+str(q)+"))") gap.eval("G:=GeneratorMat(C)") k = int(gap.eval("Length(G)")) n = int(gap.eval("Length(G[1])")) G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) for j in range(1, n + 1)] for i in range(1, k + 1)] MS = MatrixSpace(F, k, n) return LinearCode(MS(G))
def plotkin_upper_bound(n,q,d, algorithm=None): r""" Returns the Plotkin upper bound. Returns the Plotkin upper bound for the number of elements in a largest code of minimum distance `d` in `\GF{q}^n`. More precisely this is a generalization of Plotkin's result for `q=2` to bigger `q` due to Berlekamp. The ``algorithm="gap"`` option wraps Guava's ``UpperBoundPlotkin``. EXAMPLES:: sage: codes.bounds.plotkin_upper_bound(10,2,3) 192 sage: codes.bounds.plotkin_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 192 """ _check_n_q_d(n, q, d, field_based=False) if algorithm=="gap": gap.load_package("guava") ans=gap.eval("UpperBoundPlotkin(%s,%s,%s)"%(n,d,q)) return QQ(ans) else: t = 1 - 1/q if (q==2) and (n == 2*d) and (d%2 == 0): return 4*d elif (q==2) and (n == 2*d + 1) and (d%2 == 1): return 4*d + 4 elif d > t*n: return int(d/( d - t*n)) elif d < t*n + 1: fact = (d-1) / t if RR(fact)==RR(int(fact)): fact = int(fact) + 1 return int(d/( d - t * fact)) * q**(n - fact)
def as_permutation(self): r""" Return the element of the permutation group G (isomorphic to the abelian group A) associated to a in A. EXAMPLES:: sage: G = AbelianGroup(3,[2,3,4],names="abc"); G Multiplicative Abelian group isomorphic to C2 x C3 x C4 sage: a,b,c=G.gens() sage: Gp = G.permutation_group(); Gp Permutation Group with generators [(6,7,8,9), (3,4,5), (1,2)] sage: a.as_permutation() (1,2) sage: ap = a.as_permutation(); ap (1,2) sage: ap in Gp True """ from sage.groups.perm_gps.permgroup import PermutationGroup from sage.interfaces.all import gap G = self.parent() invs = list(G.gens_orders()) s1 = 'A:=AbelianGroup(%s)'%invs gap.eval(s1) s2 = 'phi:=IsomorphismPermGroup(A)' gap.eval(s2) s3 = "gens := GeneratorsOfGroup(A)" gap.eval(s3) L = self.list() gap.eval("L1:="+str(L)) s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);"%len(L) gap.eval(s4) pg = gap.eval("Image(phi,Product(L2))") Gp = G.permutation_group() gp = Gp(pg) return gp
def __init__(self, ambient, gens, names="f"): """ EXAMPLES:: sage: F = AbelianGroup(5,[30,64,729],names = list("abcde")) sage: a,b,c,d,e = F.gens() sage: F.subgroup([a^3,b]) Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a^3, b] :: sage: F.subgroup([c]) Multiplicative Abelian Group isomorphic to C2 x C3 x C5, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [c] :: sage: F.subgroup([a,c]) Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a, c] :: sage: F.subgroup([a,b*c]) Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a, b*c] :: sage: F.subgroup([b*c,d]) Multiplicative Abelian Group isomorphic to C64 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [b*c, d] :: sage: F.subgroup([a*b,c^6,d],names = list("xyz")) Multiplicative Abelian Group isomorphic to C5 x C64 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b, c^6, d] :: sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H Multiplicative Abelian Group isomorphic to C5 x C64 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b, c^6, d] :: sage: G = F.subgroup([a*b,c^6,d],names = list("xyz")); G Multiplicative Abelian Group isomorphic to C5 x C64 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b, c^6, d] sage: x,y,z = G.gens() sage: x.order() +Infinity sage: y.order() 5 sage: z.order() 64 sage: A = AbelianGroup(5,[3, 5, 5, 7, 8], names = "abcde") sage: a,b,c,d,e = A.gens() sage: A.subgroup([a,b]) Multiplicative Abelian Group isomorphic to C3 x C5, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8 generated by [a, b] sage: A.subgroup([a,b,c,d^2,e]) Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8 generated by [a, b, c, d^2, e] sage: A.subgroup([a,b,c,d^2,e^2]) Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8 generated by [a, b, c, d^2, e^2] sage: B = A.subgroup([a^3,b,c,d,e^2]); B Multiplicative Abelian Group isomorphic to C4 x C5 x C5 x C7, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8 generated by [b, c, d, e^2] sage: B.invariants() [4, 5, 5, 7] sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd") sage: a,b,c,d = A.gens() sage: B = A.subgroup([a^3,b,c,d]) sage: B.invariants() [1009, 2003, 3001, 4001] sage: A.order() 24266473210027 sage: B.order() 24266473210027 sage: A = AbelianGroup(4,[1008, 2003, 3001, 4001], names = "abcd") sage: a,b,c,d = A.gens() sage: B = A.subgroup([a^3,b,c,d]); B Multiplicative Abelian Group isomorphic to C3 x C7 x C16 x C2003 x C3001 x C4001, which is the subgroup of Multiplicative Abelian Group isomorphic to C1008 x C2003 x C3001 x C4001 generated by [a^3, b, c, d] Infinite groups can also be handled:: sage: G = AbelianGroup([3,4,0], names = "abc") sage: a,b,c = G.gens() sage: F = G.subgroup([a,b^2,c]); F Multiplicative Abelian Group isomorphic to C2 x C3 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C4 x Z generated by [a, b^2, c] :: sage: F.invariants() [2, 3, 0] sage: F.gens() [a, b^2, c] sage: F.order() +Infinity """ from sage.interfaces.all import gap if not isinstance(ambient, AbelianGroup_class): raise TypeError, "ambient (=%s) must be an abelian group." % ambient if not isinstance(gens, list): raise TypeError, "gens (=%s) must be a list" % gens self.__ambient_group = ambient Hgens = [x for x in gens if x != ambient(1) ] ## in case someone puts 1 in the list of generators self.__gens = Hgens m = len(gens) ell = len(ambient.gens()) ambient_invs = ambient.invariants() invsf = [x for x in ambient_invs if x > 0] ## fixes the problem with invs0 = [x for x in ambient_invs if x == 0] ## the infinite parts Ggens = list(ambient.variable_names()) if invs0 != []: Gfgens = [ x for x in ambient.variable_names() if ambient_invs[Ggens.index(x)] != 0 ] Ggens0 = [ x for x in ambient.variable_names() if ambient_invs[Ggens.index(x)] == 0 ] ## ^^ only look at "finite" names Gf = AbelianGroup_class(len(invsf), invsf, names=Gfgens) s1 = "G:= %s; gens := GeneratorsOfGroup(G)" % Gf._gap_init_() gap.eval(s1) Hgensf = [ x for x in Hgens if len(set(Ggens0).intersection(set(list(str(x))))) == 0 ] # computes the gens of H which do not occur ^^ in the infinite part of G Hgens0 = [x for x in Hgens if not (x in Hgensf)] # the "infinite" generators of H for i in range(len(Gfgens)): cmd = ("%s := gens[" + str(i + 1) + "]") % Gfgens[i] gap.eval(cmd) if invs0 == []: Hgensf = Hgens Hgens0 = [] # added for consistency G = ambient s1 = "G:= %s; gens := GeneratorsOfGroup(G)" % G._gap_init_() gap.eval(s1) for i in range(len(Ggens)): cmd = '%s := gens[%s]' % (Ggens[i], i + 1) #print i," \n",cmd gap.eval(cmd) s2 = "gensH:=%s" % Hgensf #### remove from this the ones <--> 0 invar gap.eval(s2) s3 = 'H:=Subgroup(G,gensH)' gap.eval(s3) # a GAP command which returns the "invariants" of the # subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)), # works if G is the subgroup declared as a AbelianPcpGroup self.__abinvs = eval(gap.eval("AbelianInvariants(H)")) invs = self.__abinvs #print s3, invs if Hgens0 != []: for x in Hgens0: invs.append(0) #print Hgensf, invs, invs0 AbelianGroup_class.__init__(self, len(invs), invs, names)
def word_problem(words, g, verbose=False): r""" G and H are abelian, g in G, H is a subgroup of G generated by a list (words) of elements of G. If g is in H, return the expression for g as a word in the elements of (words). The 'word problem' for a finite abelian group G boils down to the following matrix-vector analog of the Chinese remainder theorem. Problem: Fix integers `1<n_1\leq n_2\leq ...\leq n_k` (indeed, these `n_i` will all be prime powers), fix a generating set `g_i=(a_{i1},...,a_{ik})` (with `a_{ij}\in \mathrm{Z}/n_j\mathrm{Z}`), for `1\leq i\leq \ell`, for the group `G`, and let `d = (d_1,...,d_k)` be an element of the direct product `\mathrm{Z}/n_1\mathrm{Z} \times ...\times \mathrm{Z}/n_k\mathrm{Z}`. Find, if they exist, integers `c_1,...,c_\ell` such that `c_1g_1+...+c_\ell g_\ell = d`. In other words, solve the equation `cA=d` for `c\in \mathrm{Z}^\ell`, where `A` is the matrix whose rows are the `g_i`'s. Of course, it suffices to restrict the `c_i`'s to the range `0\leq c_i\leq N-1`, where `N` denotes the least common multiple of the integers `n_1,...,n_k`. This function does not solve this directly, as perhaps it should. Rather (for both speed and as a model for a similar function valid for more general groups), it pushes it over to GAP, which has optimized (non-deterministic) algorithms for the word problem. Essentially, this function is a wrapper for the GAP function 'Factorization'. EXAMPLE:: sage: G.<a,b,c> = AbelianGroup(3,[2,3,4]); G Multiplicative Abelian Group isomorphic to C2 x C3 x C4 sage: w = word_problem([a*b,a*c], b*c); w #random [[a*b, 1], [a*c, 1]] sage: prod([x^i for x,i in w]) == b*c True sage: w = word_problem([a*c,c],a); w #random [[a*c, 1], [c, -1]] sage: prod([x^i for x,i in w]) == a True sage: word_problem([a*c,c],a,verbose=True) #random a = (a*c)^1*(c)^-1 [[a*c, 1], [c, -1]] :: sage: A.<a,b,c,d,e> = AbelianGroup(5,[4, 5, 5, 7, 8]) sage: b1 = a^3*b*c*d^2*e^5 sage: b2 = a^2*b*c^2*d^3*e^3 sage: b3 = a^7*b^3*c^5*d^4*e^4 sage: b4 = a^3*b^2*c^2*d^3*e^5 sage: b5 = a^2*b^4*c^2*d^4*e^5 sage: w = word_problem([b1,b2,b3,b4,b5],e); w #random [[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1], [a^3*b^3*d^4*e^4, 3], [a^2*b^4*c^2*d^4*e^5, 1]] sage: prod([x^i for x,i in w]) == e True sage: word_problem([a,b,c,d,e],e) [[e, 1]] sage: word_problem([a,b,c,d,e],b) [[b, 1]] .. warning:: 1. Might have unpleasant effect when the word problem cannot be solved. 2. Uses permutation groups, so may be slow when group is large. The instance method word_problem of the class AbelianGroupElement is implemented differently (wrapping GAP's 'EpimorphismFromFreeGroup' and 'PreImagesRepresentative') and may be faster. """ from sage.interfaces.all import gap G = g.parent() invs = G.invariants() gap.eval("l:=One(Rationals)") s1 = 'A:=AbelianGroup(%s)' % invs gap.eval(s1) s2 = 'phi:=IsomorphismPermGroup(A)' gap.eval(s2) s3 = "gens := GeneratorsOfGroup(A)" gap.eval(s3) L = g.list() gap.eval("L1:=" + str(L)) s4 = "L2:=List([l..%s], i->gens[i]^L1[i]);" % len(L) gap.eval(s4) gap.eval("g:=Product(L2); gensH:=[]") for w in words: L = w.list() gap.eval("L1:=" + str(L)) s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);" % len(L) gap.eval(s4) gap.eval("w:=Product(L2)") gap.eval("gensH:=Concatenation(gensH,[w])") s5 = 'H:=Group(gensH)' gap.eval(s5) gap.eval("x:=Factorization(H,g)") l3 = eval(gap.eval("L3:=ExtRepOfObj(x)")) nn = gap.eval("n:=Int(Length(L3)/2)") LL = eval(gap.eval("L4:=List([l..n],i->L3[2*i])")) if verbose: #print gap.eval("x"), l3, nn, LL v = '*'.join([ '(%s)^%s' % (words[l3[2 * i] - 1], LL[i]) for i in range(len(LL)) ]) print '%s = %s' % (g, v) return [[words[l3[2 * i] - 1], LL[i]] for i in range(len(LL))]
def bounds_on_minimum_distance_in_guava(n, k, F): r""" Computes a lower and upper bound on the greatest minimum distance of a `[n,k]` linear code over the field ``F``. This function requires the optional GAP package GUAVA. The function returns a GAP record with the two bounds and an explanation for each bound. The function Display can be used to show the explanations. The values for the lower and upper bound are obtained from a table constructed by Cen Tjhai for GUAVA, derived from the table of Brouwer. See http://www.codetables.de/ for the most recent data. These tables contain lower and upper bounds for `q=2` (when ``n <= 257``), `q=3` (when ``n <= 243``), `q=4` (``n <= 256``). (Current as of 11 May 2006.) For codes over other fields and for larger word lengths, trivial bounds are used. INPUT: - ``n`` -- the length of the code to look up - ``k`` -- the dimension of the code to look up - ``F`` -- the base field of the code to look up OUTPUT: - A GAP record object. See below for an example. EXAMPLES:: sage: gap_rec = codes.databases.bounds_on_minimum_distance_in_guava(10,5,GF(2)) # optional - gap_packages (Guava package) sage: print(gap_rec) # optional - gap_packages (Guava package) rec( construction := [ <Operation "ShortenedCode">, [ [ <Operation "UUVCode">, [ [ <Operation "DualCode">, [ [ <Operation "RepetitionCode">, [ 8, 2 ] ] ] ], [ <Operation "UUVCode">, [ [ <Operation "DualCode">, [ [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ] , [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ] ] ], [ 1, 2, 3, 4, 5, 6 ] ] ], k := 5, lowerBound := 4, lowerBoundExplanation := ... n := 10, q := 2, references := rec( ), upperBound := 4, upperBoundExplanation := ... ) """ GapPackage("guava", spkg="gap_packages").require() gap.load_package("guava") q = F.order() gap.eval("data := BoundsMinimumDistance(%s,%s,GF(%s))" % (n, k, q)) Ldata = gap.eval("Display(data)") return Ldata
def subgroups(self, check=False): r""" Compute all the subgroups of this abelian group (which must be finite). TODO: This is *many orders of magnitude* slower than Magma. INPUT: - check: if True, performs the same computation in GAP and checks that the number of subgroups generated is the same. (I don't know how to convert GAP's output back into Sage, so we don't actually compare the subgroups). ALGORITHM: If the group is cyclic, the problem is easy. Otherwise, write it as a direct product A x B, where B is cyclic. Compute the subgroups of A (by recursion). Now, for every subgroup C of A x B, let G be its *projection onto* A and H its *intersection with* B. Then there is a well-defined homomorphism f: G -> B/H that sends a in G to the class mod H of b, where (a,b) is any element of C lifting a; and every subgroup C arises from a unique triple (G, H, f). EXAMPLES:: sage: AbelianGroup([2,3]).subgroups() [Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of Multiplicative Abelian Group isomorphic to C2 x C3 generated by [f0*f1^2], Multiplicative Abelian Group isomorphic to C2, which is the subgroup of Multiplicative Abelian Group isomorphic to C2 x C3 generated by [f0], Multiplicative Abelian Group isomorphic to C3, which is the subgroup of Multiplicative Abelian Group isomorphic to C2 x C3 generated by [f1], Trivial Abelian Group, which is the subgroup of Multiplicative Abelian Group isomorphic to C2 x C3 generated by []] sage: len(AbelianGroup([2,4,8]).subgroups()) 81 """ if not self.is_finite(): raise ValueError, "Group must be finite" from sage.misc.misc import verbose v = self.invariants() if len(v) <= 1: if v == [] or v[0] == 1: return [self] else: return [ self.subgroup([self.gen(0)**i]) for i in divisors(v[0])[:-1] ] + [self.subgroup([])] A = AbelianGroup(v[:-1]) x = v[-1] Wsubs = A.subgroups() subgps = [] for G in Wsubs: verbose("G = subgp generated by %s" % G.gens()) verbose("invariants are:", [t.order() for t in G.gens()]) # G.invariants() doesn't work for H in divisors(x): # H = the subgroup of *index* H. its = [ xrange(0, H, H / gcd(H, G.gen(i).order())) for i in xrange(len(G.gens())) ] for f in cartesian_product_iterator(its): verbose("using hom from G to C_%s sending gens to %s" % (H, f)) new_sub = [] for a in xrange(len(G.gens())): new_sub.append(G.gen(a).list() + [f[a]]) if H != x: new_sub.append([0] * A.ngens() + [H]) subgps.append(self.subgroup_reduced(new_sub)) if check: from sage.interfaces.all import gap verbose("Running Gap cross-check") t = ZZ( gap.eval("Size(SubgroupsSolvableGroup(AbelianGroup(%s)))" % v)) if t != len(subgps): raise ArithmeticError, "For %s Gap finds %s subgroups, I found %s" % ( v, t, len(subgps)) verbose("Gap check OK for %s: %s" % (v, t)) return subgps
def codesize_upper_bound(n,d,q,algorithm=None): r""" Returns an upper bound on the number of codewords in a (possibly non-linear) code. This function computes the minimum value of the upper bounds of Singleton, Hamming, Plotkin, and Elias. If algorithm="gap" then this returns the best known upper bound `A(n,d)=A_q(n,d)` for the size of a code of length n, minimum distance d over a field of size q. The function first checks for trivial cases (like d=1 or n=d), and if the value is in the built-in table. Then it calculates the minimum value of the upper bound using the algorithms of Singleton, Hamming, Johnson, Plotkin and Elias. If the code is binary, `A(n, 2\ell-1) = A(n+1,2\ell)`, so the function takes the minimum of the values obtained from all algorithms for the parameters `(n, 2\ell-1)` and `(n+1, 2\ell)`. This wraps GUAVA's (i.e. GAP's package Guava) UpperBound( n, d, q ). If algorithm="LP" then this returns the Delsarte (a.k.a. Linear Programming) upper bound. EXAMPLES:: sage: codes.bounds.codesize_upper_bound(10,3,2) 93 sage: codes.bounds.codesize_upper_bound(24,8,2,algorithm="LP") 4096 sage: codes.bounds.codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_packages (Guava package) 85 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm=None) 123361 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_packages (Guava package) 123361 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="LP") 109226 TESTS: Make sure :trac:`22961` is fixed:: sage: codes.bounds.codesize_upper_bound(19,10,2) 20 sage: codes.bounds.codesize_upper_bound(19,10,2,algorithm="gap") # optional - gap_packages (Guava package) 20 Meaningless parameters are rejected:: sage: codes.bounds.codesize_upper_bound(10, -20, 6) Traceback (most recent call last): ... ValueError: The length or minimum distance does not make sense """ _check_n_q_d(n, q, d, field_based=False) if algorithm=="gap": gap.load_package('guava') return int(gap.eval("UpperBound(%s,%s,%s)"%( n, d, q ))) if algorithm=="LP": return int(delsarte_bound_hamming_space(n,d,q)) else: eub = elias_upper_bound(n,q,d) hub = hamming_upper_bound(n,q,d) pub = plotkin_upper_bound(n,q,d) sub = singleton_upper_bound(n,q,d) return min([eub,hub,pub,sub])
def __init__(self, ambient, gens, names="f"): """ EXAMPLES:: sage: F = AbelianGroup(5,[30,64,729],names = list("abcde")) sage: a,b,c,d,e = F.gens() sage: F.subgroup([a^3,b]) Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a^3, b] :: sage: F.subgroup([c]) Multiplicative Abelian Group isomorphic to C2 x C3 x C5, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [c] :: sage: F.subgroup([a,c]) Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a, c] :: sage: F.subgroup([a,b*c]) Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a, b*c] :: sage: F.subgroup([b*c,d]) Multiplicative Abelian Group isomorphic to C64 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [b*c, d] :: sage: F.subgroup([a*b,c^6,d],names = list("xyz")) Multiplicative Abelian Group isomorphic to C5 x C64 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b, c^6, d] :: sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H Multiplicative Abelian Group isomorphic to C5 x C64 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b, c^6, d] :: sage: G = F.subgroup([a*b,c^6,d],names = list("xyz")); G Multiplicative Abelian Group isomorphic to C5 x C64 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b, c^6, d] sage: x,y,z = G.gens() sage: x.order() +Infinity sage: y.order() 5 sage: z.order() 64 sage: A = AbelianGroup(5,[3, 5, 5, 7, 8], names = "abcde") sage: a,b,c,d,e = A.gens() sage: A.subgroup([a,b]) Multiplicative Abelian Group isomorphic to C3 x C5, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8 generated by [a, b] sage: A.subgroup([a,b,c,d^2,e]) Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8 generated by [a, b, c, d^2, e] sage: A.subgroup([a,b,c,d^2,e^2]) Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8 generated by [a, b, c, d^2, e^2] sage: B = A.subgroup([a^3,b,c,d,e^2]); B Multiplicative Abelian Group isomorphic to C4 x C5 x C5 x C7, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8 generated by [b, c, d, e^2] sage: B.invariants() [4, 5, 5, 7] sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd") sage: a,b,c,d = A.gens() sage: B = A.subgroup([a^3,b,c,d]) sage: B.invariants() [1009, 2003, 3001, 4001] sage: A.order() 24266473210027 sage: B.order() 24266473210027 sage: A = AbelianGroup(4,[1008, 2003, 3001, 4001], names = "abcd") sage: a,b,c,d = A.gens() sage: B = A.subgroup([a^3,b,c,d]); B Multiplicative Abelian Group isomorphic to C3 x C7 x C16 x C2003 x C3001 x C4001, which is the subgroup of Multiplicative Abelian Group isomorphic to C1008 x C2003 x C3001 x C4001 generated by [a^3, b, c, d] Infinite groups can also be handled:: sage: G = AbelianGroup([3,4,0], names = "abc") sage: a,b,c = G.gens() sage: F = G.subgroup([a,b^2,c]); F Multiplicative Abelian Group isomorphic to C2 x C3 x Z, which is the subgroup of Multiplicative Abelian Group isomorphic to C3 x C4 x Z generated by [a, b^2, c] :: sage: F.invariants() [2, 3, 0] sage: F.gens() [a, b^2, c] sage: F.order() +Infinity """ from sage.interfaces.all import gap if not isinstance(ambient, AbelianGroup_class): raise TypeError, "ambient (=%s) must be an abelian group."%ambient if not isinstance(gens, list): raise TypeError, "gens (=%s) must be a list"%gens self.__ambient_group = ambient Hgens = [x for x in gens if x != ambient(1)] ## in case someone puts 1 in the list of generators self.__gens = Hgens m = len(gens) ell = len(ambient.gens()) ambient_invs = ambient.invariants() invsf = [x for x in ambient_invs if x > 0] ## fixes the problem with invs0 = [x for x in ambient_invs if x == 0] ## the infinite parts Ggens = list(ambient.variable_names()) if invs0!=[]: Gfgens = [x for x in ambient.variable_names() if ambient_invs[Ggens.index(x)] != 0] Ggens0 = [x for x in ambient.variable_names() if ambient_invs[Ggens.index(x)] == 0] ## ^^ only look at "finite" names Gf = AbelianGroup_class(len(invsf), invsf, names = Gfgens) s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%Gf._gap_init_() gap.eval(s1) Hgensf = [x for x in Hgens if len(set(Ggens0).intersection(set(list(str(x)))))==0] # computes the gens of H which do not occur ^^ in the infinite part of G Hgens0 = [x for x in Hgens if not(x in Hgensf)] # the "infinite" generators of H for i in range(len(Gfgens)): cmd = ("%s := gens["+str(i+1)+"]")%Gfgens[i] gap.eval(cmd) if invs0==[]: Hgensf = Hgens Hgens0 = [] # added for consistency G = ambient s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_() gap.eval(s1) for i in range(len(Ggens)): cmd = '%s := gens[%s]'%(Ggens[i], i+1) #print i," \n",cmd gap.eval(cmd) s2 = "gensH:=%s"%Hgensf #### remove from this the ones <--> 0 invar gap.eval(s2) s3 = 'H:=Subgroup(G,gensH)' gap.eval(s3) # a GAP command which returns the "invariants" of the # subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)), # works if G is the subgroup declared as a AbelianPcpGroup self.__abinvs = eval(gap.eval("AbelianInvariants(H)")) invs = self.__abinvs #print s3, invs if Hgens0 != []: for x in Hgens0: invs.append(0) #print Hgensf, invs, invs0 AbelianGroup_class.__init__(self, len(invs), invs, names)
def word_problem(words, g, verbose = False): r""" G and H are abelian, g in G, H is a subgroup of G generated by a list (words) of elements of G. If g is in H, return the expression for g as a word in the elements of (words). The 'word problem' for a finite abelian group G boils down to the following matrix-vector analog of the Chinese remainder theorem. Problem: Fix integers `1<n_1\leq n_2\leq ...\leq n_k` (indeed, these `n_i` will all be prime powers), fix a generating set `g_i=(a_{i1},...,a_{ik})` (with `a_{ij}\in \mathrm{Z}/n_j\mathrm{Z}`), for `1\leq i\leq \ell`, for the group `G`, and let `d = (d_1,...,d_k)` be an element of the direct product `\mathrm{Z}/n_1\mathrm{Z} \times ...\times \mathrm{Z}/n_k\mathrm{Z}`. Find, if they exist, integers `c_1,...,c_\ell` such that `c_1g_1+...+c_\ell g_\ell = d`. In other words, solve the equation `cA=d` for `c\in \mathrm{Z}^\ell`, where `A` is the matrix whose rows are the `g_i`'s. Of course, it suffices to restrict the `c_i`'s to the range `0\leq c_i\leq N-1`, where `N` denotes the least common multiple of the integers `n_1,...,n_k`. This function does not solve this directly, as perhaps it should. Rather (for both speed and as a model for a similar function valid for more general groups), it pushes it over to GAP, which has optimized (non-deterministic) algorithms for the word problem. Essentially, this function is a wrapper for the GAP function 'Factorization'. EXAMPLE:: sage: G.<a,b,c> = AbelianGroup(3,[2,3,4]); G Multiplicative Abelian Group isomorphic to C2 x C3 x C4 sage: w = word_problem([a*b,a*c], b*c); w #random [[a*b, 1], [a*c, 1]] sage: prod([x^i for x,i in w]) == b*c True sage: w = word_problem([a*c,c],a); w #random [[a*c, 1], [c, -1]] sage: prod([x^i for x,i in w]) == a True sage: word_problem([a*c,c],a,verbose=True) #random a = (a*c)^1*(c)^-1 [[a*c, 1], [c, -1]] :: sage: A.<a,b,c,d,e> = AbelianGroup(5,[4, 5, 5, 7, 8]) sage: b1 = a^3*b*c*d^2*e^5 sage: b2 = a^2*b*c^2*d^3*e^3 sage: b3 = a^7*b^3*c^5*d^4*e^4 sage: b4 = a^3*b^2*c^2*d^3*e^5 sage: b5 = a^2*b^4*c^2*d^4*e^5 sage: w = word_problem([b1,b2,b3,b4,b5],e); w #random [[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1], [a^3*b^3*d^4*e^4, 3], [a^2*b^4*c^2*d^4*e^5, 1]] sage: prod([x^i for x,i in w]) == e True sage: word_problem([a,b,c,d,e],e) [[e, 1]] sage: word_problem([a,b,c,d,e],b) [[b, 1]] .. warning:: 1. Might have unpleasant effect when the word problem cannot be solved. 2. Uses permutation groups, so may be slow when group is large. The instance method word_problem of the class AbelianGroupElement is implemented differently (wrapping GAP's 'EpimorphismFromFreeGroup' and 'PreImagesRepresentative') and may be faster. """ from sage.interfaces.all import gap G = g.parent() invs = G.invariants() gap.eval("l:=One(Rationals)") s1 = 'A:=AbelianGroup(%s)'%invs gap.eval(s1) s2 = 'phi:=IsomorphismPermGroup(A)' gap.eval(s2) s3 = "gens := GeneratorsOfGroup(A)" gap.eval(s3) L = g.list() gap.eval("L1:="+str(L)) s4 = "L2:=List([l..%s], i->gens[i]^L1[i]);"%len(L) gap.eval(s4) gap.eval("g:=Product(L2); gensH:=[]") for w in words: L = w.list() gap.eval("L1:="+str(L)) s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);"%len(L) gap.eval(s4) gap.eval("w:=Product(L2)") gap.eval("gensH:=Concatenation(gensH,[w])") s5 = 'H:=Group(gensH)' gap.eval(s5) gap.eval("x:=Factorization(H,g)") l3 = eval(gap.eval("L3:=ExtRepOfObj(x)")) nn = gap.eval("n:=Int(Length(L3)/2)") LL = eval(gap.eval("L4:=List([l..n],i->L3[2*i])")) if verbose: #print gap.eval("x"), l3, nn, LL v = '*'.join(['(%s)^%s'%(words[l3[2*i]-1], LL[i]) for i in range(len(LL))]) print '%s = %s'%(g, v) return [[words[l3[2*i]-1],LL[i]] for i in range(len(LL))]
def bounds_on_minimum_distance_in_guava(n, k, F): r""" Computes a lower and upper bound on the greatest minimum distance of a `[n,k]` linear code over the field ``F``. This function requires the optional GAP package GUAVA. The function returns a GAP record with the two bounds and an explanation for each bound. The function Display can be used to show the explanations. The values for the lower and upper bound are obtained from a table constructed by Cen Tjhai for GUAVA, derived from the table of Brouwer. See http://www.codetables.de/ for the most recent data. These tables contain lower and upper bounds for `q=2` (when ``n <= 257``), `q=3` (when ``n <= 243``), `q=4` (``n <= 256``). (Current as of 11 May 2006.) For codes over other fields and for larger word lengths, trivial bounds are used. INPUT: - ``n`` -- the length of the code to look up - ``k`` -- the dimension of the code to look up - ``F`` -- the base field of the code to look up OUTPUT: - A GAP record object. See below for an example. EXAMPLES:: sage: gap_rec = codes.databases.bounds_on_minimum_distance_in_guava(10,5,GF(2)) # optional - gap_packages (Guava package) sage: print(gap_rec) # optional - gap_packages (Guava package) rec( construction := [ <Operation "ShortenedCode">, [ [ <Operation "UUVCode">, [ [ <Operation "DualCode">, [ [ <Operation "RepetitionCode">, [ 8, 2 ] ] ] ], [ <Operation "UUVCode">, [ [ <Operation "DualCode">, [ [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ] , [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ] ] ], [ 1, 2, 3, 4, 5, 6 ] ] ], k := 5, lowerBound := 4, lowerBoundExplanation := ... n := 10, q := 2, references := rec( ), upperBound := 4, upperBoundExplanation := ... ) """ from sage.interfaces.all import gap gap.load_package("guava") q = F.order() gap.eval("data := BoundsMinimumDistance(%s,%s,GF(%s))"%(n,k,q)) Ldata = gap.eval("Display(data)") return Ldata
def subgroups(self, check=False): r""" Compute all the subgroups of this abelian group (which must be finite). TODO: This is *many orders of magnitude* slower than Magma. INPUT: - check: if True, performs the same computation in GAP and checks that the number of subgroups generated is the same. (I don't know how to convert GAP's output back into Sage, so we don't actually compare the subgroups). ALGORITHM: If the group is cyclic, the problem is easy. Otherwise, write it as a direct product A x B, where B is cyclic. Compute the subgroups of A (by recursion). Now, for every subgroup C of A x B, let G be its *projection onto* A and H its *intersection with* B. Then there is a well-defined homomorphism f: G -> B/H that sends a in G to the class mod H of b, where (a,b) is any element of C lifting a; and every subgroup C arises from a unique triple (G, H, f). EXAMPLES:: sage: AbelianGroup([2,3]).subgroups() [Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of Multiplicative Abelian Group isomorphic to C2 x C3 generated by [f0*f1^2], Multiplicative Abelian Group isomorphic to C2, which is the subgroup of Multiplicative Abelian Group isomorphic to C2 x C3 generated by [f0], Multiplicative Abelian Group isomorphic to C3, which is the subgroup of Multiplicative Abelian Group isomorphic to C2 x C3 generated by [f1], Trivial Abelian Group, which is the subgroup of Multiplicative Abelian Group isomorphic to C2 x C3 generated by []] sage: len(AbelianGroup([2,4,8]).subgroups()) 81 """ if not self.is_finite(): raise ValueError, "Group must be finite" from sage.misc.misc import verbose v = self.invariants() if len(v) <= 1: if v == [] or v[0] == 1: return [self] else: return [ self.subgroup([self.gen(0)**i]) for i in divisors(v[0])[:-1]] + [self.subgroup([])] A = AbelianGroup(v[:-1]) x = v[-1] Wsubs = A.subgroups() subgps = [] for G in Wsubs: verbose("G = subgp generated by %s" % G.gens()) verbose("invariants are:", [t.order() for t in G.gens()]) # G.invariants() doesn't work for H in divisors(x): # H = the subgroup of *index* H. its = [xrange(0, H, H/gcd(H, G.gen(i).order())) for i in xrange(len(G.gens()))] for f in cartesian_product_iterator(its): verbose("using hom from G to C_%s sending gens to %s" % (H,f)) new_sub = [] for a in xrange(len(G.gens())): new_sub.append(G.gen(a).list() + [f[a]]) if H != x: new_sub.append([0]*A.ngens() + [H]) subgps.append(self.subgroup_reduced(new_sub)) if check: from sage.interfaces.all import gap verbose("Running Gap cross-check") t = ZZ(gap.eval("Size(SubgroupsSolvableGroup(AbelianGroup(%s)))" % v)) if t != len(subgps): raise ArithmeticError, "For %s Gap finds %s subgroups, I found %s" % (v, t, len(subgps)) verbose("Gap check OK for %s: %s" % (v, t)) return subgps
def as_permutation(self): r""" Return the element of the permutation group G (isomorphic to the abelian group A) associated to a in A. EXAMPLES:: sage: G = AbelianGroup(3,[2,3,4],names="abc"); G Multiplicative Abelian Group isomorphic to C2 x C3 x C4 sage: a,b,c=G.gens() sage: Gp = G.permutation_group(); Gp Permutation Group with generators [(1,3,2,4)(5,7,6,8)(9,11,10,12)(13,15,14,16)(17,19,18,20)(21,23,22,24), (1,5,9)(2,6,10)(3,7,11)(4,8,12)(13,17,21)(14,18,22)(15,19,23)(16,20,24), (1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24)] sage: a.as_permutation() (1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24) sage: ap = a.as_permutation(); ap (1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24) sage: ap in Gp True """ from sage.groups.perm_gps.permgroup import PermutationGroup from sage.interfaces.all import gap G = self.parent() invs = G.invariants() s1 = 'A:=AbelianGroup(%s)' % invs gap.eval(s1) s2 = 'phi:=IsomorphismPermGroup(A)' gap.eval(s2) s3 = "gens := GeneratorsOfGroup(A)" gap.eval(s3) L = self.list() gap.eval("L1:=" + str(L)) s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);" % len(L) gap.eval(s4) pg = gap.eval("Image(phi,Product(L2))") Gp = G.permutation_group() gp = Gp(pg) return gp
def as_permutation(self): r""" Return the element of the permutation group G (isomorphic to the abelian group A) associated to a in A. EXAMPLES:: sage: G = AbelianGroup(3,[2,3,4],names="abc"); G Multiplicative Abelian Group isomorphic to C2 x C3 x C4 sage: a,b,c=G.gens() sage: Gp = G.permutation_group(); Gp Permutation Group with generators [(1,3,2,4)(5,7,6,8)(9,11,10,12)(13,15,14,16)(17,19,18,20)(21,23,22,24), (1,5,9)(2,6,10)(3,7,11)(4,8,12)(13,17,21)(14,18,22)(15,19,23)(16,20,24), (1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24)] sage: a.as_permutation() (1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24) sage: ap = a.as_permutation(); ap (1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24) sage: ap in Gp True """ from sage.groups.perm_gps.permgroup import PermutationGroup from sage.interfaces.all import gap G = self.parent() invs = G.invariants() s1 = 'A:=AbelianGroup(%s)'%invs gap.eval(s1) s2 = 'phi:=IsomorphismPermGroup(A)' gap.eval(s2) s3 = "gens := GeneratorsOfGroup(A)" gap.eval(s3) L = self.list() gap.eval("L1:="+str(L)) s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);"%len(L) gap.eval(s4) pg = gap.eval("Image(phi,Product(L2))") Gp = G.permutation_group() gp = Gp(pg) return gp
def word_problem(self, words, display=True): """ This is a rather hackish method and is included for completeness. The word problem for an instance of DualAbelianGroup as it can for an AbelianGroup. The reason why is that word problem for an instance of AbelianGroup simply calls GAP (which has abelian groups implemented) and invokes "EpimorphismFromFreeGroup" and "PreImagesRepresentative". GAP does not have duals of abelian groups implemented. So, by using the same name for the generators, the method below converts the problem for the dual group to the corresponding problem on the group itself and uses GAP to solve that. EXAMPLES:: sage: G = AbelianGroup(5,[3, 5, 5, 7, 8],names="abcde") sage: Gd = G.dual_group(names="abcde") sage: a,b,c,d,e = Gd.gens() sage: u = a^3*b*c*d^2*e^5 sage: v = a^2*b*c^2*d^3*e^3 sage: w = a^7*b^3*c^5*d^4*e^4 sage: x = a^3*b^2*c^2*d^3*e^5 sage: y = a^2*b^4*c^2*d^4*e^5 sage: e.word_problem([u,v,w,x,y],display=False) [[b^2*c^2*d^3*e^5, 245]] The command e.word_problem([u,v,w,x,y],display=True) returns the same list but also prints $e = (b^2*c^2*d^3*e^5)^245$. """ ## First convert the problem to one using AbelianGroups import copy from sage.groups.abelian_gps.abelian_group import AbelianGroup from sage.interfaces.all import gap M = self.parent() G = M.group() gens = M.variable_names() g = prod([G.gen(i)**(self.list()[i]) for i in range(G.ngens())]) gap.eval("l:=One(Rationals)" ) ## trick needed for LL line below to keep Sage from parsing s1 = "gens := GeneratorsOfGroup(%s)" % G._gap_init_() gap.eval(s1) for i in range(len(gens)): cmd = ("%s := gens[" + str(i + 1) + "]") % gens[i] gap.eval(cmd) s2 = "g0:=%s; gensH:=%s" % (str(g), words) gap.eval(s2) s3 = 'G:=Group(gens); H:=Group(gensH)' gap.eval(s3) phi = gap.eval("hom:=EpimorphismFromFreeGroup(H)") l1 = gap.eval("ans:=PreImagesRepresentative(hom,g0)") l2 = copy.copy(l1) l4 = [] l3 = l1.split("*") for i in range(1, len(words) + 1): l2 = l2.replace("x" + str(i), "(" + str(words[i - 1]) + ")") l3 = eval(gap.eval("L3:=ExtRepOfObj(ans)")) nn = eval(gap.eval("n:=Int(Length(L3)/2)")) LL1 = eval( gap.eval("L4:=List([l..n],i->L3[2*i])")) ## note the l not 1 LL2 = eval( gap.eval("L5:=List([l..n],i->L3[2*i-1])")) ## note the l not 1 if display: s = str(g) + " = " + add_strings([ "(" + str(words[LL2[i] - 1]) + ")^" + str(LL1[i]) + "*" for i in range(nn) ]) m = len(s) print(" ", s[:m - 1], "\n") return [[words[LL2[i] - 1], LL1[i]] for i in range(nn)]
def word_problem(self, words, display=True): """ This is a rather hackish method and is included for completeness. The word problem for an instance of DualAbelianGroup as it can for an AbelianGroup. The reason why is that word problem for an instance of AbelianGroup simply calls GAP (which has abelian groups implemented) and invokes "EpimorphismFromFreeGroup" and "PreImagesRepresentative". GAP does not have duals of abelian groups implemented. So, by using the same name for the generators, the method below converts the problem for the dual group to the corresponding problem on the group itself and uses GAP to solve that. EXAMPLES:: sage: G = AbelianGroup(5,[3, 5, 5, 7, 8],names="abcde") sage: Gd = G.dual_group(names="abcde") sage: a,b,c,d,e = Gd.gens() sage: u = a^3*b*c*d^2*e^5 sage: v = a^2*b*c^2*d^3*e^3 sage: w = a^7*b^3*c^5*d^4*e^4 sage: x = a^3*b^2*c^2*d^3*e^5 sage: y = a^2*b^4*c^2*d^4*e^5 sage: e.word_problem([u,v,w,x,y],display=False) [[b^2*c^2*d^3*e^5, 245]] The command e.word_problem([u,v,w,x,y],display=True) returns the same list but also prints $e = (b^2*c^2*d^3*e^5)^245$. """ ## First convert the problem to one using AbelianGroups import copy from sage.groups.abelian_gps.abelian_group import AbelianGroup from sage.interfaces.all import gap M = self.parent() G = M.group() gens = M.variable_names() g = prod([G.gen(i)**(self.list()[i]) for i in range(G.ngens())]) gap.eval("l:=One(Rationals)") ## trick needed for LL line below to keep Sage from parsing s1 = "gens := GeneratorsOfGroup(%s)"%G._gap_init_() gap.eval(s1) for i in range(len(gens)): cmd = ("%s := gens["+str(i+1)+"]")%gens[i] gap.eval(cmd) s2 = "g0:=%s; gensH:=%s"%(str(g),words) gap.eval(s2) s3 = 'G:=Group(gens); H:=Group(gensH)' gap.eval(s3) phi = gap.eval("hom:=EpimorphismFromFreeGroup(H)") l1 = gap.eval("ans:=PreImagesRepresentative(hom,g0)") l2 = copy.copy(l1) l4 = [] l3 = l1.split("*") for i in range(1,len(words)+1): l2 = l2.replace("x"+str(i),"("+str(words[i-1])+")") l3 = eval(gap.eval("L3:=ExtRepOfObj(ans)")) nn = eval(gap.eval("n:=Int(Length(L3)/2)")) LL1 = eval(gap.eval("L4:=List([l..n],i->L3[2*i])")) ## note the l not 1 LL2 = eval(gap.eval("L5:=List([l..n],i->L3[2*i-1])")) ## note the l not 1 if display: s = str(g)+" = "+add_strings(["("+str(words[LL2[i]-1])+")^"+str(LL1[i])+"*" for i in range(nn)]) m = len(s) print " ",s[:m-1],"\n" return [[words[LL2[i]-1],LL1[i]] for i in range(nn)]
def as_permutation(self): r""" Return the element of the permutation group G (isomorphic to the abelian group A) associated to a in A. EXAMPLES:: sage: G = AbelianGroup(3,[2,3,4],names="abc"); G Multiplicative Abelian group isomorphic to C2 x C3 x C4 sage: a,b,c=G.gens() sage: Gp = G.permutation_group(); Gp Permutation Group with generators [(6,7,8,9), (3,4,5), (1,2)] sage: a.as_permutation() (1,2) sage: ap = a.as_permutation(); ap (1,2) sage: ap in Gp True """ from sage.groups.perm_gps.permgroup import PermutationGroup from sage.interfaces.all import gap G = self.parent() invs = list(G.gens_orders()) s1 = 'A:=AbelianGroup(%s)' % invs gap.eval(s1) s2 = 'phi:=IsomorphismPermGroup(A)' gap.eval(s2) s3 = "gens := GeneratorsOfGroup(A)" gap.eval(s3) L = self.list() gap.eval("L1:=" + str(L)) s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);" % len(L) gap.eval(s4) pg = gap.eval("Image(phi,Product(L2))") Gp = G.permutation_group() gp = Gp(pg) return gp