def HughesPlane(q2, check=True): r""" Return the Hughes projective plane of order ``q2``. Let `q` be an odd prime, the Hughes plane of order `q^2` is a finite projective plane of order `q^2` introduced by D. Hughes in [Hu57]_. Its construction is as follows. Let `K = GF(q^2)` be a finite field with `q^2` elements and `F = GF(q) \subset K` be its unique subfield with `q` elements. We define a twisted multiplication on `K` as .. MATH:: x \circ y = \begin{cases} x\ y & \text{if y is a square in K}\\ x^q\ y & \text{otherwise} \end{cases} The points of the Hughes plane are the triples `(x, y, z)` of points in `K^3 \backslash \{0,0,0\}` up to the equivalence relation `(x,y,z) \sim (x \circ k, y \circ k, z \circ k)` where `k \in K`. For `a = 1` or `a \in (K \backslash F)` we define a block `L(a)` as the set of triples `(x,y,z)` so that `x + a \circ y + z = 0`. The rest of the blocks are obtained by letting act the group `GL(3, F)` by its standard action. For more information, see :wikipedia:`Hughes_plane` and [We07]. .. SEEALSO:: :func:`DesarguesianProjectivePlaneDesign` to build the Desarguesian projective planes INPUT: - ``q2`` -- an even power of an odd prime number - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. EXAMPLES:: sage: H = designs.HughesPlane(9) sage: H (91,10,1)-Balanced Incomplete Block Design We prove in the following computations that the Desarguesian plane ``H`` is not Desarguesian. Let us consider the two triangles `(0,1,10)` and `(57, 70, 59)`. We show that the intersection points `D_{0,1} \cap D_{57,70}`, `D_{1,10} \cap D_{70,59}` and `D_{10,0} \cap D_{59,57}` are on the same line while `D_{0,70}`, `D_{1,59}` and `D_{10,57}` are not concurrent:: sage: blocks = H.blocks() sage: line = lambda p,q: (b for b in blocks if p in b and q in b).next() sage: b_0_1 = line(0, 1) sage: b_1_10 = line(1, 10) sage: b_10_0 = line(10, 0) sage: b_57_70 = line(57, 70) sage: b_70_59 = line(70, 59) sage: b_59_57 = line(59, 57) sage: set(b_0_1).intersection(b_57_70) {2} sage: set(b_1_10).intersection(b_70_59) {73} sage: set(b_10_0).intersection(b_59_57) {60} sage: line(2, 73) == line(73, 60) True sage: b_0_57 = line(0, 57) sage: b_1_70 = line(1, 70) sage: b_10_59 = line(10, 59) sage: p = set(b_0_57).intersection(b_1_70) sage: q = set(b_1_70).intersection(b_10_59) sage: p == q False TESTS: Some wrong input:: sage: designs.HughesPlane(5) Traceback (most recent call last): ... EmptySetError: No Hughes plane of non-square order exists. sage: designs.HughesPlane(16) Traceback (most recent call last): ... EmptySetError: No Hughes plane of even order exists. Check that it works for non-prime `q`:: sage: designs.HughesPlane(3**4) # not tested - 10 secs (6643,82,1)-Balanced Incomplete Block Design """ if not q2.is_square(): raise EmptySetError("No Hughes plane of non-square order exists.") if q2 % 2 == 0: raise EmptySetError("No Hughes plane of even order exists.") q = q2.sqrt() K = FiniteField(q2, prefix='x', conway=True) F = FiniteField(q, prefix='y', conway=True) A = q3_minus_one_matrix(F) A = A.change_ring(K) m = K.list() V = VectorSpace(K, 3) zero = K.zero() one = K.one() points = [(x, y, one) for x in m for y in m] + \ [(x, one, zero) for x in m] + \ [(one, zero, zero)] relabel = {tuple(p): i for i, p in enumerate(points)} blcks = [] for a in m: if a not in F or a == 1: # build L(a) aa = ~a l = [] l.append(V((-a, one, zero))) for x in m: y = -aa * (x + one) if not y.is_square(): y *= aa**(q - 1) l.append(V((x, y, one))) # compute the orbit of L(a) blcks.append( [relabel[normalize_hughes_plane_point(p, q)] for p in l]) for i in range(q2 + q): l = [A * j for j in l] blcks.append( [relabel[normalize_hughes_plane_point(p, q)] for p in l]) from bibd import BalancedIncompleteBlockDesign return BalancedIncompleteBlockDesign(q2**2 + q2 + 1, blcks, check=check)
def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True): r""" Return the Desarguesian projective plane of order ``n`` as a 2-design. The Desarguesian projective plane of order `n` can also be defined as the projective plane over a field of order `n`. For more information, have a look at :wikipedia:`Projective_plane`. INPUT: - ``n`` -- an integer which must be a power of a prime number - ``point_coordinates`` (boolean) -- whether to label the points with their homogeneous coordinates (default) or with integers. - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. .. SEEALSO:: :func:`ProjectiveGeometryDesign` EXAMPLES:: sage: designs.DesarguesianProjectivePlaneDesign(2) (7,3,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(3) (13,4,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(4) (21,5,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(5) (31,6,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(6) Traceback (most recent call last): ... ValueError: the order of a finite field must be a prime power """ K = FiniteField(n, 'a') n2 = n**2 relabel = {x:i for i,x in enumerate(K)} Kiter = relabel # it is much faster to iterate throug a dict than through # the finite field K # we decompose the (equivalence class) of points [x:y:z] of the projective # plane into an affine plane, an affine line and a point. At the same time, # we relabel the points with the integers from 0 to n^2 + n as follows: # - the affine plane is the set of points [x:y:1] (i.e. the third coordinate # is non-zero) and gets relabeled from 0 to n^2-1 affine_plane = lambda x,y: relabel[x] + n * relabel[y] # - the affine line is the set of points [x:1:0] (i.e. the third coordinate is # zero but not the second one) and gets relabeld from n^2 to n^2 + n - 1 line_infinity = lambda x: n2 + relabel[x] # - the point is [1:0:0] and gets relabeld n^2 + n point_infinity = n2 + n blcks = [] # the n^2 lines of the form "x = sy + az" for s in Kiter: for a in Kiter: # points in the affine plane blcks.append([affine_plane(s*y+a, y) for y in Kiter]) # point at infinity blcks[-1].append(line_infinity(s)) # the n horizontals of the form "y = az" for a in Kiter: # points in the affine plane blcks.append([affine_plane(x,a) for x in Kiter]) # point at infinity blcks[-1].append(point_infinity) # the line at infinity "z = 0" blcks.append(range(n2,n2+n+1)) if check: from designs_pyx import is_projective_plane if not is_projective_plane(blcks): raise RuntimeError('There is a problem in the function DesarguesianProjectivePlane') from bibd import BalancedIncompleteBlockDesign B = BalancedIncompleteBlockDesign(n2+n+1, blcks, check=check) if point_coordinates: zero = K.zero() one = K.one() d = {affine_plane(x,y): (x,y,one) for x in Kiter for y in Kiter} d.update({line_infinity(x): (x,one,zero) for x in Kiter}) d[n2+n]=(one,zero,zero) B.relabel(d) return B
def DesarguesianProjectivePlaneDesign(n, check=True): r""" Return the Desarguesian projective plane of order ``n`` as a 2-design. The Desarguesian projective plane of order `n` can also be defined as the projective plane over a field of order `n`. For more information, have a look at :wikipedia:`Projective_plane`. INPUT: - ``n`` -- an integer which must be a power of a prime number - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. .. SEEALSO:: :func:`ProjectiveGeometryDesign` EXAMPLES:: sage: designs.DesarguesianProjectivePlaneDesign(2) (7,3,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(3) (13,4,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(4) (21,5,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(5) (31,6,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(6) Traceback (most recent call last): ... ValueError: the order of a finite field must be a prime power """ K = FiniteField(n, 'x') n2 = n**2 relabel = {x: i for i, x in enumerate(K)} Kiter = relabel # it is much faster to iterate throug a dict than through # the finite field K # we decompose the (equivalence class) of points [x:y:z] of the projective # plane into an affine plane, an affine line and a point. At the same time, # we relabel the points with the integers from 0 to n^2 + n as follows: # - the affine plane is the set of points [x:y:1] (i.e. the third coordinate # is non-zero) and gets relabeled from 0 to n^2-1 affine_plane = lambda x, y: relabel[x] + n * relabel[y] # - the affine line is the set of points [x:1:0] (i.e. the third coordinate is # zero but not the second one) and gets relabeld from n^2 to n^2 + n - 1 line_infinity = lambda x: n2 + relabel[x] # - the point is [1:0:0] and gets relabeld n^2 + n point_infinity = n2 + n blcks = [] # the n^2 lines of the form "x = sy + az" for s in Kiter: for a in Kiter: # points in the affine plane blcks.append([affine_plane(s * y + a, y) for y in Kiter]) # point at infinity blcks[-1].append(line_infinity(s)) # the n horizontals of the form "y = az" for a in Kiter: # points in the affine plane blcks.append([affine_plane(x, a) for x in Kiter]) # point at infinity blcks[-1].append(point_infinity) # the line at infinity "z = 0" blcks.append(range(n2, n2 + n + 1)) if check: from designs_pyx import is_projective_plane if not is_projective_plane(blcks): raise RuntimeError( 'There is a problem in the function DesarguesianProjectivePlane' ) from bibd import BalancedIncompleteBlockDesign return BalancedIncompleteBlockDesign(n2 + n + 1, blcks, check=check)