예제 #1
0
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)
예제 #2
0
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)
예제 #3
0
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
예제 #4
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1| 1  1| 1  1| 1  1| 1  1| 1  1]
        [ 1 -1|-1  1|-1  1|-1  1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1 -1| 1  1|-1 -1|-1 -1| 1  1]
        [ 1  1|-1 -1| 1 -1|-1  1|-1  1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1| 1 -1| 1  1|-1 -1|-1 -1]
        [ 1  1| 1 -1|-1 -1| 1 -1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1| 1  1| 1 -1| 1  1|-1 -1]
        [ 1  1|-1  1| 1 -1|-1 -1| 1 -1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1|-1 -1| 1  1| 1 -1| 1  1]
        [ 1  1|-1  1|-1  1| 1 -1|-1 -1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1|-1 -1|-1 -1| 1  1| 1 -1]
        [ 1  1| 1 -1|-1  1|-1  1| 1 -1|-1 -1]

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyII, is_hadamard_matrix)
        sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
    """
    q = n//2 - 1
    if not(n%2==0 and is_prime_power(q) and (q % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)

    from sage.rings.finite_rings.constructor import FiniteField
    K = FiniteField(q,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(q+1):
        H[0,i] = 1
        H[i,0] = 1
        H[i,i] = 0

    tr = { 0: matrix(2,2,[ 1,-1,-1,-1]),
           1: matrix(2,2,[ 1, 1, 1,-1]),
          -1: matrix(2,2,[-1,-1,-1, 1])}

    H = block_matrix(q+1,q+1,[tr[v] for r in H for v in r])

    return normalise_hadamard(H)
예제 #5
0
def hadamard_matrix_paleyI(n, normalize=True):
    """
    Implements the Paley type I construction.

    The Paley type I case corresponds to the case `p \cong 3 \mod{4}` for a
    prime `p` (see [Hora]_).

    INPUT:

    - ``n`` -- the matrix size 

    - ``normalize`` (boolean) -- whether to normalize the result.

    EXAMPLES:

    We note that this method by default returns a normalised Hadamard matrix ::

        sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI
        sage: hadamard_matrix_paleyI(4)
        [ 1  1  1  1]
        [ 1 -1  1 -1]
        [ 1 -1 -1  1]
        [ 1  1 -1 -1]

    Otherwise, it returns a skew Hadamard matrix `H`, i.e. `H=S+I`, with
    `S=-S^\top`  ::

        sage: M=hadamard_matrix_paleyI(4, normalize=False); M
        [ 1  1  1  1]
        [-1  1  1 -1]
        [-1 -1  1  1]
        [-1  1 -1  1]
        sage: S=M-identity_matrix(4); -S==S.T
        True

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix
        sage: test_cases = [x+1 for x in range(100) if is_prime_power(x) and x%4==3]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n,normalize=False),verbose=True)
        ....:     for n in test_cases)
        True
    """
    p = n - 1
    if not(is_prime_power(p) and (p % 4 == 3)):
        raise ValueError("The order %s is not covered by the Paley type I construction." % n)

    from sage.rings.finite_rings.constructor import FiniteField
    K = FiniteField(p,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(n):
        H[i,0] = -1
        H[0,i] =  1
    if normalize:
        for i in range(n):
            H[i,i] = -1
        H = normalise_hadamard(H)
    return H
예제 #6
0
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
예제 #7
0
def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True):
    r"""
    Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual

    Let `q=2^k` and `\Theta=PG(3,q)`.  `T_2^*(q)` is a generalized quadrangle [GQwiki]_
    of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. Fix a plane `\Pi \subset \Theta` and a
    `hyperoval <http://en.wikipedia.org/wiki/Oval_(projective_plane)#Even_q>`__
    `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of `\Theta`
    outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi`
    that meet `\Pi` in a point of `O`.

    INPUT:

    - ``q`` -- a power of two

    - ``dual`` -- if ``False`` (default), return the graph of `T_2^*(O)`.
      Otherwise return the graph of the dual `T_2^*(O)`.

    - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane
      meeting every line in 0 or 2 points) in the plane of points with 0th coordinate
      0 in `PG(3,q)` over the field ``field``. Each point of ``hyperoval`` must be a length 4
      vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and
      ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval``
      we build is the classical one, i.e. a conic with the point of intersection of its
      tangent lines.

    - ``field`` -- an instance of a finite field of order `q`, must be provided
      if ``hyperoval`` is provided.

    - ``check_hyperoval`` -- (default: ``True``) if ``True``,
      check ``hyperoval`` for correctness.


    EXAMPLES:

    using the built-in construction::

        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4); g
        T2*(O,4); GQ(3, 5): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 18, 2, 6)
        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4,dual=True); g
        T2*(O,4)*; GQ(5, 3): Graph on 96 vertices
        sage: g.is_strongly_regular(parameters=True)
        (96, 20, 4, 4)

    supplying your own hyperoval::

        sage: F=GF(4,'b')
        sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g
        T2*(O,4); GQ(3, 5): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 18, 2, 6)

    TESTS::

        sage: F=GF(4,'b') # repeating a point...
        sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
        Traceback (most recent call last):
        ...
        RuntimeError: incorrect hyperoval size
        sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
        Traceback (most recent call last):
        ...
        RuntimeError: incorrect hyperoval
    """
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    from sage.combinat.designs.block_design import ProjectiveGeometryDesign as PG
    from sage.modules.free_module_element import free_module_element as vector

    p, k = is_prime_power(q,get_data=True)
    if k==0 or p!=2:
       raise ValueError('q must be a power of 2')
    if field is None:
        F = FiniteField(q, 'a')
    else:
        F = field

    Theta = PG(3, 1, F, point_coordinates=1)
    Pi = set(filter(lambda x: x[0]==F.zero(), Theta.ground_set()))
    if hyperoval is None:
        O = filter(lambda x: x[1]+x[2]*x[3]==0 or (x[1]==1 and x[2]==0 and x[3]==0), Pi)
        O = set(O)
    else:
        map(lambda x: x.set_immutable(), hyperoval)
        O = set(hyperoval)
        if check_hyperoval:
            if len(O) != q+2:
                raise RuntimeError("incorrect hyperoval size")
            for L in Theta.blocks():
                if set(L).issubset(Pi):
                    if not len(O.intersection(L)) in [0,2]:
                        raise RuntimeError("incorrect hyperoval")
    L = map(lambda z: filter(lambda y: not y in O, z),
            filter(lambda x: len(O.intersection(x)) == 1, Theta.blocks()))
    if dual:
        G = IncidenceStructure(L).intersection_graph()
        G.name('T2*(O,'+str(q)+')*; GQ'+str((q+1,q-1)))
    else:
        G = IncidenceStructure(L).dual().intersection_graph()
        G.name('T2*(O,'+str(q)+'); GQ'+str((q-1,q+1)))
    return G
예제 #8
0
def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True):
    r"""
    Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual

    Let `q=2^k` and `\Theta=PG(3,q)`.  `T_2^*(q)` is a generalized quadrangle [GQwiki]_
    of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. Fix a plane `\Pi \subset \Theta` and a
    `hyperoval <http://en.wikipedia.org/wiki/Oval_(projective_plane)#Even_q>`__
    `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of `\Theta`
    outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi`
    that meet `\Pi` in a point of `O`.

    INPUT:

    - ``q`` -- a power of two

    - ``dual`` -- if ``False`` (default), return the graph of `T_2^*(O)`.
      Otherwise return the graph of the dual `T_2^*(O)`.

    - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane
      meeting every line in 0 or 2 points) in the plane of points with 0th coordinate
      0 in `PG(3,q)` over the field ``field``. Each point of ``hyperoval`` must be a length 4
      vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and
      ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval``
      we build is the classical one, i.e. a conic with the point of intersection of its
      tangent lines.

    - ``field`` -- an instance of a finite field of order `q`, must be provided
      if ``hyperoval`` is provided.

    - ``check_hyperoval`` -- (default: ``True``) if ``True``,
      check ``hyperoval`` for correctness.


    EXAMPLES:

    using the built-in construction::

        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4); g
        T2*(O,4); GQ(3, 5): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 18, 2, 6)
        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4,dual=True); g
        T2*(O,4)*; GQ(5, 3): Graph on 96 vertices
        sage: g.is_strongly_regular(parameters=True)
        (96, 20, 4, 4)

    supplying your own hyperoval::

        sage: F=GF(4,'b')
        sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g
        T2*(O,4); GQ(3, 5): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 18, 2, 6)

    TESTS::

        sage: F=GF(4,'b') # repeating a point...
        sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
        Traceback (most recent call last):
        ...
        RuntimeError: incorrect hyperoval size
        sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
        Traceback (most recent call last):
        ...
        RuntimeError: incorrect hyperoval
    """
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    from sage.combinat.designs.block_design import ProjectiveGeometryDesign as PG
    from sage.modules.free_module_element import free_module_element as vector

    p, k = is_prime_power(q,get_data=True)
    if k==0 or p!=2:
       raise ValueError('q must be a power of 2')
    if field is None:
        F = FiniteField(q, 'a')
    else:
        F = field

    Theta = PG(3, 1, F, point_coordinates=1)
    Pi = set(filter(lambda x: x[0]==F.zero(), Theta.ground_set()))
    if hyperoval is None:
        O = filter(lambda x: x[1]+x[2]*x[3]==0 or (x[1]==1 and x[2]==0 and x[3]==0), Pi)
        O = set(O)
    else:
        map(lambda x: x.set_immutable(), hyperoval)
        O = set(hyperoval)
        if check_hyperoval:
            if len(O) != q+2:
                raise RuntimeError("incorrect hyperoval size")
            for L in Theta.blocks():
                if set(L).issubset(Pi):
                    if not len(O.intersection(L)) in [0,2]:
                        raise RuntimeError("incorrect hyperoval")
    L = map(lambda z: filter(lambda y: not y in O, z),
            filter(lambda x: len(O.intersection(x)) == 1, Theta.blocks()))
    if dual:
        G = IncidenceStructure(L).intersection_graph()
        G.name('T2*(O,'+str(q)+')*; GQ'+str((q+1,q-1)))
    else:
        G = IncidenceStructure(L).dual().intersection_graph()
        G.name('T2*(O,'+str(q)+'); GQ'+str((q-1,q+1)))
    return G
예제 #9
0
def hadamard_matrix_paleyI(n, normalize=True):
    """
    Implements the Paley type I construction.

    The Paley type I case corresponds to the case `p \cong 3 \mod{4}` for a
    prime `p` (see [Hora]_).

    INPUT:

    - ``n`` -- the matrix size 

    - ``normalize`` (boolean) -- whether to normalize the result.

    EXAMPLES:

    We note that this method by default returns a normalised Hadamard matrix ::

        sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI
        sage: hadamard_matrix_paleyI(4)
        [ 1  1  1  1]
        [ 1 -1  1 -1]
        [ 1 -1 -1  1]
        [ 1  1 -1 -1]

    Otherwise, it returns a skew Hadamard matrix `H`, i.e. `H=S+I`, with
    `S=-S^\top`  ::

        sage: M=hadamard_matrix_paleyI(4, normalize=False); M
        [ 1  1  1  1]
        [-1  1  1 -1]
        [-1 -1  1  1]
        [-1  1 -1  1]
        sage: S=M-identity_matrix(4); -S==S.T
        True

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix
        sage: test_cases = [x+1 for x in range(100) if is_prime_power(x) and x%4==3]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n,normalize=False),verbose=True)
        ....:     for n in test_cases)
        True
    """
    p = n - 1
    if not(is_prime_power(p) and (p % 4 == 3)):
        raise ValueError("The order %s is not covered by the Paley type I construction." % n)

    from sage.rings.finite_rings.constructor import FiniteField
    K = FiniteField(p,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(n):
        H[i,0] = -1
        H[0,i] =  1
    if normalize:
        for i in range(n):
            H[i,i] = -1
        H = normalise_hadamard(H)
    return H
예제 #10
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1| 1  1| 1  1| 1  1| 1  1| 1  1]
        [ 1 -1|-1  1|-1  1|-1  1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1 -1| 1  1|-1 -1|-1 -1| 1  1]
        [ 1  1|-1 -1| 1 -1|-1  1|-1  1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1| 1 -1| 1  1|-1 -1|-1 -1]
        [ 1  1| 1 -1|-1 -1| 1 -1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1| 1  1| 1 -1| 1  1|-1 -1]
        [ 1  1|-1  1| 1 -1|-1 -1| 1 -1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1|-1 -1| 1  1| 1 -1| 1  1]
        [ 1  1|-1  1|-1  1| 1 -1|-1 -1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1|-1 -1|-1 -1| 1  1| 1 -1]
        [ 1  1| 1 -1|-1  1|-1  1| 1 -1|-1 -1]

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyII, is_hadamard_matrix)
        sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
    """
    q = n//2 - 1
    if not(n%2==0 and is_prime_power(q) and (q % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)

    from sage.rings.finite_rings.constructor import FiniteField
    K = FiniteField(q,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(q+1):
        H[0,i] = 1
        H[i,0] = 1
        H[i,i] = 0

    tr = { 0: matrix(2,2,[ 1,-1,-1,-1]),
           1: matrix(2,2,[ 1, 1, 1,-1]),
          -1: matrix(2,2,[-1,-1,-1, 1])}

    H = block_matrix(q+1,q+1,[tr[v] for r in H for v in r])

    return normalise_hadamard(H)