def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): r""" Return an affine geometry design. The affine geometry design `AG_d(n,q)` is the 2-design whose blocks are the `d`-vector subspaces in `\GF{q}^n`. It has parameters .. MATH:: v = q^n,\ k = q^d,\ \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:`ProjectiveGeometryDesign` INPUT: - ``n`` (integer) -- the Euclidean dimension. The number of points of the design is `v=|\GF{q}^n|`. - ``d`` (integer) -- the dimension of the (affine) subspaces of `\GF{q}^n` which make up the blocks. - ``F`` -- a finite field or a prime power. - ``point_coordinates`` -- (optional, default ``True``) whether we use coordinates in `\GF{q}^n` or plain integers for the points of the design. - ``check`` -- (optional, default ``True``) whether to check the output. EXAMPLES:: sage: BD = designs.AffineGeometryDesign(3, 1, GF(2)) sage: BD.is_t_design(return_parameters=True) (True, (2, 8, 2, 1)) sage: BD = designs.AffineGeometryDesign(3, 2, GF(4)) sage: BD.is_t_design(return_parameters=True) (True, (2, 64, 16, 5)) sage: BD = designs.AffineGeometryDesign(4, 2, GF(3)) sage: BD.is_t_design(return_parameters=True) (True, (2, 81, 9, 13)) With ``F`` an integer instead of a finite field:: sage: BD = designs.AffineGeometryDesign(3, 2, 4) sage: BD.is_t_design(return_parameters=True) (True, (2, 64, 16, 5)) Testing the option ``point_coordinates``:: sage: designs.AffineGeometryDesign(3, 1, GF(2), point_coordinates=True).blocks()[0] [(0, 0, 0), (0, 0, 1)] sage: designs.AffineGeometryDesign(3, 1, GF(2), point_coordinates=False).blocks()[0] [0, 1] """ try: q = int(F) except TypeError: q = F.cardinality() else: from sage.rings.finite_rings.finite_field_constructor import GF F = GF(q) n = int(n) d = int(d) from itertools import islice from sage.combinat.q_analogues import q_binomial 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)) if p[0, 0] } blocks = [] l1 = int(q_binomial(n + 1, d + 1, q) - q_binomial(n, d + 1, q)) l2 = q**d for m1 in islice( reduced_echelon_matrix_iterator(F, d + 1, n + 1, copy=False), int(l1)): b = [] for m2 in islice( reduced_echelon_matrix_iterator(F, 1, d + 1, copy=False), int(l2)): m = m2 * m1 m.echelonize() m.set_immutable() b.append(points[m]) blocks.append(b) B = BlockDesign(len(points), blocks, name="AffineGeometryDesign", check=check) if point_coordinates: rd = {i: p[0][1:] for p, i in points.items()} for v in rd.values(): v.set_immutable() B.relabel(rd) if check: if not B.is_t_design( t=2, v=q**n, k=q**d, l=q_binomial(n - 1, d - 1, q)): raise RuntimeError( "error in AffineGeometryDesign " "construction. Please e-mail [email protected]") return B
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 ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, check=True): """ Return a projective geometry design. A projective geometry design of parameters `n,d,F` has for points the lines of `F^{n+1}`, and for blocks the `d+1`-dimensional subspaces of `F^{n+1}`, each of which contains `\\frac {|F|^{d+1}-1} {|F|-1}` lines. INPUT: - ``n`` is the projective dimension - ``d`` is the dimension of the subspaces of `P = PPn(F)` which make up the blocks. - ``F`` is a finite field. - ``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 `F^{n+1}`. Otherwise the ground set is indexed by integers, 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,'z')) sage: PG.is_t_design(return_parameters=True) (True, (2, 85, 5, 1)) 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)) """ if algorithm is None: from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator from copy import copy points = {} 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.iteritems()}) return B if algorithm == "gap": # Requires GAP's Design from sage.interfaces.gap import gap gap.load_package("design") gap.eval("D := PGPointFlatBlockDesign( %s, %s, %d )"%(n,F.order(),d)) v = eval(gap.eval("D.v")) gblcks = eval(gap.eval("D.blocks")) gB = [] for b in gblcks: gB.append([x-1 for x in b]) return BlockDesign(v, gB, name="ProjectiveGeometryDesign", check=check)
def ProjectiveGeometryDesign(n, d, F, algorithm=None, check=True): """ Return a projective geometry design. A projective geometry design of parameters `n,d,F` has for points the lines of `F^{n+1}`, and for blocks the `d+1`-dimensional subspaces of `F^{n+1}`, each of which contains `\\frac {|F|^{d+1}-1} {|F|-1}` lines. INPUT: - ``n`` is the projective dimension - ``d`` is the dimension of the subspaces of `P = PPn(F)` which make up the blocks. - ``F`` is a finite field. - ``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. 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,'z')) sage: PG.is_t_design(return_parameters=True) (True, (2, 85, 5, 1)) 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)) """ if algorithm is None: from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator from copy import copy points = {} 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) return BlockDesign(len(points), blocks, name="ProjectiveGeometryDesign", check=check) if algorithm == "gap": # Requires GAP's Design from sage.interfaces.gap import gap gap.load_package("design") gap.eval("D := PGPointFlatBlockDesign( %s, %s, %d )" % (n, F.order(), d)) v = eval(gap.eval("D.v")) gblcks = eval(gap.eval("D.blocks")) gB = [] for b in gblcks: gB.append([x - 1 for x in b]) return BlockDesign(v, gB, name="ProjectiveGeometryDesign", check=check)
def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): r""" Return an affine geometry design. The affine geometry design `AG_d(n,q)` is the 2-design whose blocks are the `d`-vector subspaces in `\GF{q}^n`. It has parameters .. MATH:: v = q^n,\ k = q^d,\ \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:`ProjectiveGeometryDesign` INPUT: - ``n`` (integer) -- the Euclidean dimension. The number of points of the design is `v=|\GF{q}^n|`. - ``d`` (integer) -- the dimension of the (affine) subspaces of `\GF(q)^n` which make up the blocks. - ``F`` -- a finite field or a prime power. - ``point_coordinates`` -- (optional, default ``True``) whether we use coordinates in `\GF(q)^n` or plain integers for the points of the design. - ``check`` -- (optional, default ``True``) whether to check the output. EXAMPLES:: sage: BD = designs.AffineGeometryDesign(3, 1, GF(2)) sage: BD.is_t_design(return_parameters=True) (True, (2, 8, 2, 1)) sage: BD = designs.AffineGeometryDesign(3, 2, GF(4)) sage: BD.is_t_design(return_parameters=True) (True, (2, 64, 16, 5)) sage: BD = designs.AffineGeometryDesign(4, 2, GF(3)) sage: BD.is_t_design(return_parameters=True) (True, (2, 81, 9, 13)) With ``F`` an integer instead of a finite field:: sage: BD = designs.AffineGeometryDesign(3, 2, 4) sage: BD.is_t_design(return_parameters=True) (True, (2, 64, 16, 5)) Testing the option ``point_coordinates``:: sage: designs.AffineGeometryDesign(3, 1, GF(2), point_coordinates=True).blocks()[0] [(0, 0, 0), (0, 0, 1)] sage: designs.AffineGeometryDesign(3, 1, GF(2), point_coordinates=False).blocks()[0] [0, 1] """ try: q = int(F) except TypeError: q = F.cardinality() else: from sage.rings.finite_rings.finite_field_constructor import GF F = GF(q) n = int(n) d = int(d) from itertools import islice from sage.combinat.q_analogues import q_binomial 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)) if p[0,0]} blocks = [] l1 = q_binomial(n+1, d+1, q) - q_binomial(n, d+1, q) l2 = q**d for m1 in islice(reduced_echelon_matrix_iterator(F,d+1,n+1,copy=False), l1): b = [] for m2 in islice(reduced_echelon_matrix_iterator(F,1,d+1,copy=False), l2): m = m2*m1 m.echelonize() m.set_immutable() b.append(points[m]) blocks.append(b) B = BlockDesign(len(points), blocks, name="AffineGeometryDesign", check=check) if point_coordinates: rd = {i:p[0][1:] for p,i in points.iteritems()} for v in rd.values(): v.set_immutable() B.relabel(rd) if check: if not B.is_t_design(t=2, v=q**n, k=q**d, l=q_binomial(n-1, d-1, q)): raise RuntimeError("error in AffineGeometryDesign " "construction. Please e-mail [email protected]") return B
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.iteritems()}) elif algorithm == "gap": # Requires GAP's Design from sage.interfaces.gap import gap gap.load_package("design") gap.eval("D := PGPointFlatBlockDesign( %s, %s, %d )"%(n,F.order(),d)) v = eval(gap.eval("D.v")) gblcks = eval(gap.eval("D.blocks")) 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