def WittDesign(n): """ INPUT: - ``n`` is in `9,10,11,12,21,22,23,24`. Wraps GAP Design's WittDesign. If ``n=24`` then this function returns the large Witt design `W_{24}`, the unique (up to isomorphism) `5-(24,8,1)` design. If ``n=12`` then this function returns the small Witt design `W_{12}`, the unique (up to isomorphism) `5-(12,6,1)` design. The other values of `n` return a block design derived from these. .. NOTE:: Requires GAP's Design package (included in the gap_packages Sage spkg). EXAMPLES:: sage: BD = designs.WittDesign(9) # optional - gap_packages (design package) sage: BD.is_t_design(return_parameters=True) # optional - gap_packages (design package) (True, (2, 9, 3, 1)) sage: BD # optional - gap_packages (design package) Incidence structure with 9 points and 12 blocks sage: print(BD) # optional - gap_packages (design package) Incidence structure with 9 points and 12 blocks """ libgap.load_package("design") B = libgap.WittDesign(n) v = B['v'].sage() gB = [[x - 1 for x in b] for b in B['blocks'].sage()] return BlockDesign(v, gB, name="WittDesign", check=True)
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() GapPackage("guava", spkg="gap_packages").require() libgap.load_package("guava") C=libgap.RandomLinearCode(n,k,F) G=C.GeneratorMat() MS = MatrixSpace(F, len(G), len(G[0])) return LinearCode(MS(G))
def plotkin_upper_bound(n, q, d, algorithm=None): r""" Return the Plotkin upper bound. Return 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": libgap.load_package("guava") return QQ(libgap.UpperBoundPlotkin(n, d, q)) 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 QuasiQuadraticResidueCode(p): r""" A (binary) quasi-quadratic residue code (or QQR code). Follows the definition of Proposition 2.2 in [BM2003]_. 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) """ GapPackage("guava", spkg="gap_packages").require() libgap.load_package("guava") C=libgap.QQRCode(p) G=C.GeneratorMat() MS = MatrixSpace(GF(2), len(G), len(G[0])) return LinearCode(MS(G))
def bounds_on_minimum_distance_in_guava(n, k, F): r""" Compute 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 method ``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: gap_rec.Display() # 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() libgap.load_package("guava") return libgap.BoundsMinimumDistance(n, k, F)
def griesmer_upper_bound(n, q, d, algorithm=None): r""" Return the Griesmer upper bound. Return 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": libgap.load_package("guava") return QQ(libgap.UpperBoundGriesmer(n, d, q)) 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 best_linear_code_in_guava(n, k, F): r""" Return the linear code of length ``n``, dimension ``k`` over field ``F`` with the maximal minimum distance which is known to the GAP package GUAVA. The function uses the tables described in :func:`bounds_on_minimum_distance_in_guava` to construct this code. This requires the optional GAP package GUAVA. 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 :class:`LinearCode` which is a best linear code of the given parameters known to GUAVA. EXAMPLES:: sage: codes.databases.best_linear_code_in_guava(10,5,GF(2)) # long time; optional - gap_packages (Guava package) [10, 5] linear code over GF(2) sage: gap.eval("C:=BestKnownLinearCode(10,5,GF(2))") # long time; optional - gap_packages (Guava package) 'a linear [10,5,4]2..4 shortened code' This means that the best possible binary linear code of length 10 and dimension 5 is a code with minimum distance 4 and covering radius s somewhere between 2 and 4. Use ``bounds_on_minimum_distance_in_guava(10,5,GF(2))`` for further details. """ from .linear_code import LinearCode GapPackage("guava", spkg="gap_packages").require() libgap.load_package("guava") C = libgap.BestKnownLinearCode(n, k, F) return LinearCode(C.GeneratorMat()._matrix_(F))
def elias_upper_bound(n, q, d, algorithm=None): r""" Return the Elias upper bound. Return 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": libgap.load_package("guava") return QQ(libgap.UpperBoundElias(n, d, q)) 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 ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, check=True): r""" Return a projective geometry design. The projective geometry design `PG_d(n,q)` has for points the lines of `\GF{q}^{n+1}`, and for blocks the `d+1`-dimensional subspaces of `\GF{q}^{n+1}`, each of which contains `\frac {|\GF{q}|^{d+1}-1} {|\GF{q}|-1}` lines. It is a `2`-design with parameters .. MATH:: v = \binom{n+1}{1}_q,\ k = \binom{d+1}{1}_q,\ \lambda = \binom{n-1}{d-1}_q where the `q`-binomial coefficient `\binom{m}{r}_q` is defined by .. MATH:: \binom{m}{r}_q = \frac{(q^m - 1)(q^{m-1} - 1) \cdots (q^{m-r+1}-1)} {(q^r-1)(q^{r-1}-1)\cdots (q-1)} .. SEEALSO:: :func:`AffineGeometryDesign` INPUT: - ``n`` is the projective dimension - ``d`` is the dimension of the subspaces which make up the blocks. - ``F`` -- a finite field or a prime power. - ``algorithm`` -- set to ``None`` by default, which results in using Sage's own implementation. In order to use GAP's implementation instead (i.e. its ``PGPointFlatBlockDesign`` function) set ``algorithm="gap"``. Note that GAP's "design" package must be available in this case, and that it can be installed with the ``gap_packages`` spkg. - ``point_coordinates`` -- ``True`` by default. Ignored and assumed to be ``False`` if ``algorithm="gap"``. If ``True``, the ground set is indexed by coordinates in `\GF{q}^{n+1}`. Otherwise the ground set is indexed by integers. - ``check`` -- (optional, default to ``True``) whether to check the output. EXAMPLES: The set of `d`-dimensional subspaces in a `n`-dimensional projective space forms `2`-designs (or balanced incomplete block designs):: sage: PG = designs.ProjectiveGeometryDesign(4, 2, GF(2)) sage: PG Incidence structure with 31 points and 155 blocks sage: PG.is_t_design(return_parameters=True) (True, (2, 31, 7, 7)) sage: PG = designs.ProjectiveGeometryDesign(3, 1, GF(4)) sage: PG.is_t_design(return_parameters=True) (True, (2, 85, 5, 1)) Check with ``F`` being a prime power:: sage: PG = designs.ProjectiveGeometryDesign(3, 2, 4) sage: PG Incidence structure with 85 points and 85 blocks Use coordinates:: sage: PG = designs.ProjectiveGeometryDesign(2, 1, GF(3)) sage: PG.blocks()[0] [(1, 0, 0), (1, 0, 1), (1, 0, 2), (0, 0, 1)] Use indexing by integers:: sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3),point_coordinates=0) sage: PG.blocks()[0] [0, 1, 2, 12] Check that the constructor using gap also works:: sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm="gap") # optional - gap_packages (design package) sage: BD.is_t_design(return_parameters=True) # optional - gap_packages (design package) (True, (2, 7, 3, 1)) """ try: q = int(F) except TypeError: q = F.cardinality() else: from sage.rings.finite_rings.finite_field_constructor import GF F = GF(q) if algorithm is None: from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator points = { p: i for i, p in enumerate( reduced_echelon_matrix_iterator( F, 1, n + 1, copy=True, set_immutable=True)) } blocks = [] for m1 in reduced_echelon_matrix_iterator(F, d + 1, n + 1, copy=False): b = [] for m2 in reduced_echelon_matrix_iterator(F, 1, d + 1, copy=False): m = m2 * m1 m.echelonize() m.set_immutable() b.append(points[m]) blocks.append(b) B = BlockDesign(len(points), blocks, name="ProjectiveGeometryDesign", check=check) if point_coordinates: B.relabel({i: p[0] for p, i in points.items()}) elif algorithm == "gap": # Requires GAP's Design libgap.load_package("design") D = libgap.PGPointFlatBlockDesign(n, F.order(), d) v = D['v'].sage() gblcks = D['blocks'].sage() gB = [] for b in gblcks: gB.append([x - 1 for x in b]) B = BlockDesign(v, gB, name="ProjectiveGeometryDesign", check=check) if check: from sage.combinat.q_analogues import q_binomial q = F.cardinality() if not B.is_t_design(t=2, v=q_binomial(n + 1, 1, q), k=q_binomial(d + 1, 1, q), l=q_binomial(n - 1, d - 1, q)): raise RuntimeError( "error in ProjectiveGeometryDesign " "construction. Please e-mail [email protected]") return B
def codesize_upper_bound(n, d, q, algorithm=None): r""" Return 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": libgap.load_package('guava') return int(libgap.UpperBound(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])