Example #1
0
def CremonaRichmondConfiguration():
    r"""
    Return the Cremona-Richmond configuration

    The Cremona-Richmond configuration is a set system whose incidence graph
    is equal to the
    :meth:`~sage.graphs.graph_generators.GraphGenerators.TutteCoxeterGraph`. It
    is a generalized quadrangle of parameters `(2,2)`.

    For more information, see the
    :wikipedia:`Cremona-Richmond_configuration`.

    EXAMPLE::

        sage: H = designs.CremonaRichmondConfiguration(); H
        Incidence structure with 15 points and 15 blocks
        sage: g = graphs.TutteCoxeterGraph()
        sage: H.incidence_graph().is_isomorphic(g)
        True
    """
    from sage.graphs.generators.smallgraphs import TutteCoxeterGraph
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    g = TutteCoxeterGraph()
    H = IncidenceStructure([g.neighbors(v)
                            for v in g.bipartite_sets()[0]])
    H.relabel()
    return H
Example #2
0
def CremonaRichmondConfiguration():
    r"""
    Return the Cremona-Richmond configuration

    The Cremona-Richmond configuration is a set system whose incidence graph
    is equal to the
    :meth:`~sage.graphs.graph_generators.GraphGenerators.TutteCoxeterGraph`. It
    is a generalized quadrangle of parameters `(2,2)`.

    For more information, see the
    :wikipedia:`Cremona-Richmond_configuration`.

    EXAMPLES::

        sage: H = designs.CremonaRichmondConfiguration(); H
        Incidence structure with 15 points and 15 blocks
        sage: g = graphs.TutteCoxeterGraph()
        sage: H.incidence_graph().is_isomorphic(g)
        True
    """
    from sage.graphs.generators.smallgraphs import TutteCoxeterGraph
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    g = TutteCoxeterGraph()
    H = IncidenceStructure([g.neighbors(v) for v in g.bipartite_sets()[0]])
    H.relabel()
    return H
Example #3
0
    def __init__(self,
                 points=None,
                 blocks=None,
                 incidence_matrix=None,
                 name=None,
                 check=False,
                 copy=True):
        r"""
        Constructor of the class

        TESTS::

            sage: from sage.combinat.designs.twographs import TwoGraph
            sage: TwoGraph([[1,2]])
            Incidence structure with 2 points and 1 blocks
            sage: TwoGraph([[1,2]], check=True)
            Traceback (most recent call last):
            ...
            AssertionError: the structure is not a 2-graph!
            sage: p=graphs.PetersenGraph().twograph()
            sage: TwoGraph(p, check=True)
            Incidence structure with 10 points and 60 blocks
        """
        IncidenceStructure.__init__(self,
                                    points=points,
                                    blocks=blocks,
                                    incidence_matrix=incidence_matrix,
                                    name=name,
                                    check=False,
                                    copy=copy)
        if check:  # it is a very slow, O(|points|^4), test...
            assert is_twograph(self), "the structure is not a 2-graph!"
Example #4
0
 def __init__(self,
              v=0,
              k=0,
              t=0,
              size=0,
              points=[],
              blocks=[],
              low_bd=0,
              method='',
              creator='',
              timestamp=''):
     """
     EXAMPLES:
         sage: C=CoveringDesign(5,4,3,4,range(5),[[0,1,2,3],[0,1,2,4],[0,1,3,4],[0,2,3,4]],4, 'Lexicographic Covering')
         sage: print C
         C(5,4,3) = 4
         Method: Lexicographic Covering
         0   1   2   3   
         0   1   2   4   
         0   1   3   4   
         0   2   3   4   
     """
     self.__v = v
     self.__k = k
     self.__t = t
     self.__size = size
     if low_bd > 0:
         self.__low_bd = low_bd
     else:
         self.__low_bd = schonheim(v, k, t)
     self.__method = method
     self.__creator = creator
     self.__timestamp = timestamp
     self.__incidence_structure = IncidenceStructure(points, blocks)
Example #5
0
    def __init__(self, v=0, k=0, t=0, size=0, points=[], blocks=[], low_bd=0, method='', creator ='',timestamp=''):
        """
        EXAMPLES::

            sage: C=CoveringDesign(5,4,3,4,range(5),[[0,1,2,3],[0,1,2,4],[0,1,3,4],[0,2,3,4]],4, 'Lexicographic Covering')
            sage: print(C)
            C(5,4,3) = 4
            Method: Lexicographic Covering
            0   1   2   3
            0   1   2   4
            0   1   3   4
            0   2   3   4
        """
        self.__v = v
        self.__k = k
        self.__t = t
        self.__size = size
        if low_bd > 0:
            self.__low_bd = low_bd
        else:
            self.__low_bd = schonheim(v,k,t)
        self.__method = method
        self.__creator = creator
        self.__timestamp = timestamp
        self.__incidence_structure = IncidenceStructure(points, blocks)
Example #6
0
    def underlying_hypergraph(self):
        r"""
        Return the underlying hypergraph of cocircuits of the vector configuration.

        Edges of the hypergraph correspond to zeros in a cocircuit.

        OUTPUT:

        A hypergraph

        EXAMPLES::

            sage: from cn_hyperarr.vector_classes import *
            sage: vc = VectorConfiguration([[1,0,0],[0,1,0],[0,0,1],[1,1,0],[0,1,1],[1,1,1]])
            sage: vc.underlying_hypergraph()
            Incidence structure with 6 points and 7 blocks

        For a set of three linearly dependent vectors in dimension three there
        is just one cocicuit and thus one block::

            sage: vc = VectorConfiguration([[1,0,0],[0,1,0],[2,-1,0]])
            sage: vc.underlying_hypergraph()
            Incidence structure with 3 points and 1 blocks
        """
        coc = set([v[1] for v in self.three_dim_cocircuits()])
        return IncidenceStructure(coc)
Example #7
0
def Hadamard3Design(n):
    r"""
    Return the Hadamard 3-design with parameters `3-(n, \frac n 2, \frac n 4 - 1)`.

    This is the unique extension of the Hadamard `2`-design (see
    :meth:`HadamardDesign`).  We implement the description from pp. 12 in
    [CvL]_.

    INPUT:

    - ``n`` (integer) -- a multiple of 4 such that `n>4`.

    EXAMPLES::

        sage: designs.Hadamard3Design(12)
        Incidence structure with 12 points and 22 blocks

    We verify that any two blocks of the Hadamard `3`-design `3-(8, 4, 1)`
    design meet in `0` or `2` points. More generally, it is true that any two
    blocks of a Hadamard `3`-design meet in `0` or `\frac{n}{4}` points (for `n
    > 4`).

    ::

        sage: D = designs.Hadamard3Design(8)
        sage: N = D.incidence_matrix()
        sage: N.transpose()*N
        [4 2 2 2 2 2 2 2 2 2 2 2 2 0]
        [2 4 2 2 2 2 2 2 2 2 2 2 0 2]
        [2 2 4 2 2 2 2 2 2 2 2 0 2 2]
        [2 2 2 4 2 2 2 2 2 2 0 2 2 2]
        [2 2 2 2 4 2 2 2 2 0 2 2 2 2]
        [2 2 2 2 2 4 2 2 0 2 2 2 2 2]
        [2 2 2 2 2 2 4 0 2 2 2 2 2 2]
        [2 2 2 2 2 2 0 4 2 2 2 2 2 2]
        [2 2 2 2 2 0 2 2 4 2 2 2 2 2]
        [2 2 2 2 0 2 2 2 2 4 2 2 2 2]
        [2 2 2 0 2 2 2 2 2 2 4 2 2 2]
        [2 2 0 2 2 2 2 2 2 2 2 4 2 2]
        [2 0 2 2 2 2 2 2 2 2 2 2 4 2]
        [0 2 2 2 2 2 2 2 2 2 2 2 2 4]


    REFERENCES:

    .. [CvL] \P. Cameron, J. H. van Lint, Designs, graphs, codes and
      their links, London Math. Soc., 1991.
    """
    if n == 1 or n == 4:
        raise ValueError("The Hadamard design with n = %s does not extend to a three design." % n)
    from sage.combinat.matrices.hadamard_matrix import hadamard_matrix
    from sage.matrix.constructor import matrix, block_matrix
    H = hadamard_matrix(n) #assumed to be normalised.
    H1 = H.matrix_from_columns(range(1, n))
    J = matrix(ZZ, n, n-1, [1]*(n-1)*n)
    A1 = (H1+J)/2
    A2 = (J-H1)/2
    A = block_matrix(1, 2, [A1, A2]) #the incidence matrix of the design.
    return IncidenceStructure(incidence_matrix=A, name="HadamardThreeDesign")
Example #8
0
    def __init__(self, points=None, blocks=None, incidence_matrix=None,
            name=None, check=False, copy=True):
        r"""
        Constructor of the class

        TESTS::

            sage: from sage.combinat.designs.twographs import TwoGraph
            sage: TwoGraph([[1,2]])
            Incidence structure with 2 points and 1 blocks
            sage: TwoGraph([[1,2]], check=True)
            Traceback (most recent call last):
            ...
            AssertionError: the structure is not a 2-graph!
            sage: p=graphs.PetersenGraph().twograph()
            sage: TwoGraph(p, check=True)
            Incidence structure with 10 points and 60 blocks
        """
        IncidenceStructure.__init__(self, points=points, blocks=blocks,
                                    incidence_matrix=incidence_matrix,
                                    name=name, check=False, copy=copy)
        if check:  # it is a very slow, O(|points|^4), test...
           assert is_twograph(self), "the structure is not a 2-graph!"
Example #9
0
    def __init__(self,
                 edge_set,
                 vertex_sizes,
                 num_locs,
                 initial_distribution=None):
        if (initial_distribution is None):
            self.even_dist = True
        else:
            self.even_dist = False
            self.initial_distribution = initial_distribution
        self.vertex_sizes = vertex_sizes
        assert len(edge_set.values()) > 0
        assert len(list(edge_set.values())[0]) == 3
        blocks = [k for (_, k, _) in edge_set.values()]
        firsts = [k_0[0] for k_0 in blocks]
        # Ensure that all elements are assigned to at most once
        # Assumes that all operations are assignments, which precludes
        # in-place operations
        assert len(set(firsts)) == len(firsts)
        self.hypergraph = IS(blocks)
        # Make sure the big vertex list only includes vertices in the
        # edge set
        ground_set = set(self.hypergraph.ground_set())
        assert ground_set == (ground_set
                              | set(vertex_sizes[0] + vertex_sizes[1] +
                                    vertex_sizes[2] + vertex_sizes[3]))
        self.edge_set = edge_set
        lhs = {l[0]: edge for (edge, (_, l, _)) in self.edge_set.items()}
        partial_order = {k: set([]) for k in self.edge_set.keys()}
        for name, (_, var_s, _) in self.edge_set.items():
            for i in var_s[1:]:
                try:
                    if lhs[i] != name:
                        partial_order[name].add(lhs[i])
                except KeyError:
                    partial_order[name].add('_begin_')
        self.partial_order = DiGraph(partial_order).reverse()
        vertex_set = self.hypergraph.ground_set()

        self.output_size_calculators = {
            2: {
                'add': self.add_output_size,
                'mul': self.mul_output_size
            }
        }
        self.vertices = {}
        self.init_vertices(vertex_set)
Example #10
0
def HadamardDesign(n):
    """
    As described in Section 1, p. 10, in [CvL]_. The input n must have the
    property that there is a Hadamard matrix of order `n+1` (and that a
    construction of that Hadamard matrix has been implemented...).

    EXAMPLES::

        sage: designs.HadamardDesign(7)
        Incidence structure with 7 points and 7 blocks
        sage: print(designs.HadamardDesign(7))
        Incidence structure with 7 points and 7 blocks

    For example, the Hadamard 2-design with `n = 11` is a design whose parameters are 2-(11, 5, 2).
    We verify that `NJ = 5J` for this design. ::

        sage: D = designs.HadamardDesign(11); N = D.incidence_matrix()
        sage: J = matrix(ZZ, 11, 11, [1]*11*11); N*J
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]
        [5 5 5 5 5 5 5 5 5 5 5]

    REFERENCES:

    - [CvL] P. Cameron, J. H. van Lint, Designs, graphs, codes and
      their links, London Math. Soc., 1991.
    """
    from sage.combinat.matrices.hadamard_matrix import hadamard_matrix
    from sage.matrix.constructor import matrix
    H = hadamard_matrix(n + 1)  #assumed to be normalised.
    H1 = H.matrix_from_columns(range(1, n + 1))
    H2 = H1.matrix_from_rows(range(1, n + 1))
    J = matrix(ZZ, n, n, [1] * n * n)
    MS = J.parent()
    A = MS((H2 + J) / 2)  # convert -1's to 0's; coerce entries to ZZ
    # A is the incidence matrix of the block design
    return IncidenceStructure(incidence_matrix=A, name="HadamardDesign")
Example #11
0
    def CompleteUniform(self, n, k):
        r"""
        Return the complete `k`-uniform hypergraph on `n` points.

        INPUT:

        - ``k,n`` -- nonnegative integers with `k\leq n`

        EXAMPLES::

            sage: h = hypergraphs.CompleteUniform(5,2); h
            Incidence structure with 5 points and 10 blocks
            sage: len(h.packing())
            2
        """
        from sage.combinat.designs.incidence_structures import IncidenceStructure
        from itertools import combinations
        return IncidenceStructure(list(combinations(range(n), k)))
Example #12
0
class Problem:
    """
    Highest level object for the tiling solver

    INPUT:
    
    - edge_set -- A dictionary containing tuples of (op_name,
    [inputs/outputs to operation] as sets, expression from AST)

    We use the list of inputs/outputs to feed into the construction
    of the hypergraph.

    -- NOTE -- 
    Order for the inputs/outputs is important in the edge set, as the order
    informs how the cost function calculates cost.
    However, since we don't allow any variable to be assigned more than
    once, the fact that the IncidenceStructure modifies the order of the lists
    of inputs/outputs doesn't matter. Input matrices to an operation shouldn't
    be assigned later since they were assigned at initialization/being passed 
    into the function. Output matrices shouldn't be assigned again either, 
    obviously, meaning this set of inputs/outputs is guaranteed to be unique, 
    and equality can be tested by vertex membership agnostic of the order.
    -- NOTE --

    - vertex_sizes -- A tuple of lists of variable_names.
    The tuple is structured as (big_big, big_small, small_big, small_small)

    - num_locs -- Number of localities to be used in computation

    - (Optional) initial_distribution -- Dictionary for sets of localities each
    beginning distributed matrix is spread across

    """
    def __init__(self,
                 edge_set,
                 vertex_sizes,
                 num_locs,
                 initial_distribution=None):
        if (initial_distribution is None):
            self.even_dist = True
        else:
            self.even_dist = False
            self.initial_distribution = initial_distribution
        self.vertex_sizes = vertex_sizes
        assert len(edge_set.values()) > 0
        assert len(list(edge_set.values())[0]) == 3
        blocks = [k for (_, k, _) in edge_set.values()]
        firsts = [k_0[0] for k_0 in blocks]
        # Ensure that all elements are assigned to at most once
        # Assumes that all operations are assignments, which precludes
        # in-place operations
        assert len(set(firsts)) == len(firsts)
        self.hypergraph = IS(blocks)
        # Make sure the big vertex list only includes vertices in the
        # edge set
        ground_set = set(self.hypergraph.ground_set())
        assert ground_set == (ground_set
                              | set(vertex_sizes[0] + vertex_sizes[1] +
                                    vertex_sizes[2] + vertex_sizes[3]))
        self.edge_set = edge_set
        lhs = {l[0]: edge for (edge, (_, l, _)) in self.edge_set.items()}
        partial_order = {k: set([]) for k in self.edge_set.keys()}
        for name, (_, var_s, _) in self.edge_set.items():
            for i in var_s[1:]:
                try:
                    if lhs[i] != name:
                        partial_order[name].add(lhs[i])
                except KeyError:
                    partial_order[name].add('_begin_')
        self.partial_order = DiGraph(partial_order).reverse()
        vertex_set = self.hypergraph.ground_set()

        self.output_size_calculators = {
            2: {
                'add': self.add_output_size,
                'mul': self.mul_output_size
            }
        }
        self.vertices = {}
        self.init_vertices(vertex_set)

    def init_vertices(self, vertex_set):
        print("Inside init_vertices")
        for level_set in self.partial_order.level_sets()[1:]:
            for edge in level_set:
                op, vars_, expr = self.edge_set[edge]
                output_size_func = self.output_size_calculators[len(
                    vars_[1:])][op]
                operands = []
                for k in vars_[1:]:
                    if k in self.vertex_sizes[0]:
                        size = MatrixSize.large_large
                    elif k in self.vertex_sizes[1]:
                        size = MatrixSize.large_small
                    elif k in self.vertex_sizes[2]:
                        size = MatrixSize.small_large
                    elif k in self.vertex_sizes[3]:
                        size = MatrixSize.small_small
                    else:
                        raise ValueError('Error retrieving matrix size')
                    if not self.even_dist:
                        if k in initial_distribution.keys():
                            operands.append((size, initial_distribution[k]))
                    else:
                        operands.append((size, None))
                out_size = output_size_func(operands)
                if out_size[0] == MatrixSize.large_large:
                    self.vertex_sizes[0].append(vars_[0])
                elif out_size[0] == MatrixSize.large_small:
                    self.vertex_sizes[1].append(vars_[0])
                elif out_size[0] == MatrixSize.small_large:
                    self.vertex_sizes[2].append(vars_[0])
                elif out_size[0] == MatrixSize.small_small:
                    self.vertex_sizes[3].append(vars_[0])

    def add_output_size(self, operands):
        lhs = operands[0]
        rhs = operands[1]
        assert lhs[0] == rhs[0], "Add operation should have equal size"
        assert lhs[1] == rhs[1], "Add operation should have aligned tiles"
        return lhs

    def mul_output_size(self, operands):
        assert len(operands), 'Matrix multiplication takes two arguments'
        lhs_size = operands[0][0]
        rhs_size = operands[1][0]
        out_size = None
        if lhs_size == MatrixSize.large_large:
            if rhs_size == MatrixSize.large_large:
                out_size = MatrixSize.large_large
            elif rhs_size == MatrixSize.large_small:
                out_size = MatrixSize.large_small
        elif lhs_size == MatrixSize.large_small:
            if rhs_size == MatrixSize.small_large:
                out_size = MatrixSize.large_large
            elif rhs_size == MatrixSize.small_small:
                out_size = MatrixSize.large_small
        elif lhs_size == MatrixSize.small_large:
            if rhs_size == MatrixSize.large_large:
                out_size = MatrixSize.small_large
            elif rhs_size == MatrixSize.large_small:
                out_size = MatrixSize.small_small
        elif lhs_size == MatrixSize.small_small:
            if rhs_size == MatrixSize.small_large:
                out_size = MatrixSize.small_large
            elif rhs_size == MatrixSize.small_small:
                out_size = MatrixSize.small_small
        if out_size is None:
            raise ValueError('Matrix size mismatch {0}, {1}'.format(
                lhs_size, rhs_size))
        else:
            # Copy tiling from LHS
            return (out_size, operands[0][1])
Example #13
0
def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False):
    r"""
    Return the collinearity graph of the generalized quadrangle `AS(q)`, or of its dual

    Let `q` be an odd prime power.  `AS(q)` is a generalized quadrangle [GQwiki]_ of
    order `(q-1,q+1)`, see 3.1.5 in [PT09]_. Its points are elements
    of `F_q^3`, and lines are sets of size `q` of the form

    * `\{ (\sigma, a, b) \mid \sigma\in F_q \}`
    * `\{ (a, \sigma, b) \mid \sigma\in F_q \}`
    * `\{ (c \sigma^2 - b \sigma + a, -2 c \sigma + b, \sigma) \mid \sigma\in F_q \}`,

    where `a`, `b`, `c` are arbitrary elements of `F_q`.

    INPUT:

    - ``q`` -- a power of an odd prime number

    - ``dual`` -- if ``False`` (default), return the collinearity graph of `AS(q)`.
      Otherwise return the collinearity graph of the dual `AS(q)`.

    EXAMPLES::

        sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g
        AS(5); GQ(4, 6): Graph on 125 vertices
        sage: g.is_strongly_regular(parameters=True)
        (125, 28, 3, 7)
        sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5,dual=True); g
        AS(5)*; GQ(6, 4): Graph on 175 vertices
        sage: g.is_strongly_regular(parameters=True)
        (175, 30, 5, 5)

    REFERENCE:

    .. [GQwiki] `Generalized quadrangle
      <http://en.wikipedia.org/wiki/Generalized_quadrangle>`__

    .. [PT09] \S. Payne, J. A. Thas.
      Finite generalized quadrangles.
      European Mathematical Society,
      2nd edition, 2009.
    """
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    p, k = is_prime_power(q,get_data=True)
    if k==0 or p==2:
       raise ValueError('q must be an odd prime power')
    F = FiniteField(q, 'a')
    L = []
    for a in F:
        for b in F:
            L.append(tuple(map(lambda s: (s, a, b), F)))
            L.append(tuple(map(lambda s: (a, s, b), F)))
            for c in F:
                L.append(tuple(map(lambda s: (c*s**2 - b*s + a, -2*c*s + b, s), F)))
    if dual:
        G = IncidenceStructure(L).intersection_graph()
        G.name('AS('+str(q)+')*; GQ'+str((q+1,q-1)))
    else:
        G = IncidenceStructure(L).dual().intersection_graph()
        G.name('AS('+str(q)+'); GQ'+str((q-1,q+1)))
    return G
Example #14
0
    def UniformRandomUniform(self, n, k, m):
        r"""
        Return a uniformly sampled `k`-uniform hypergraph on `n` points with
        `m` hyperedges.

        - ``n`` -- number of nodes of the graph

        - ``k`` -- uniformity

        - ``m`` -- number of edges

        EXAMPLES::

            sage: H = hypergraphs.UniformRandomUniform(52, 3, 17)
            sage: H
            Incidence structure with 52 points and 17 blocks
            sage: H.is_connected()
            False

        TESTS::

            sage: hypergraphs.UniformRandomUniform(-52, 3, 17)
            Traceback (most recent call last):
            ...
            ValueError: number of vertices should be non-negative
            sage: hypergraphs.UniformRandomUniform(52.9, 3, 17)
            Traceback (most recent call last):
            ...
            ValueError: number of vertices should be an integer
            sage: hypergraphs.UniformRandomUniform(52, -3, 17)
            Traceback (most recent call last):
            ...
            ValueError: the uniformity should be non-negative
            sage: hypergraphs.UniformRandomUniform(52, I, 17)
            Traceback (most recent call last):
            ...
            ValueError: the uniformity should be an integer
        """
        from sage.rings.integer import Integer
        from sage.combinat.subset import Subsets
        from sage.misc.prandom import sample

        # Construct the vertex set
        if n < 0:
            raise ValueError("number of vertices should be non-negative")
        try:
            nverts = Integer(n)
        except TypeError:
            raise ValueError("number of vertices should be an integer")
        vertices = range(nverts)

        # Construct the edge set
        if k < 0:
            raise ValueError("the uniformity should be non-negative")
        try:
            uniformity = Integer(k)
        except TypeError:
            raise ValueError("the uniformity should be an integer")
        all_edges = Subsets(vertices, uniformity)
        try:
            edges = sample(all_edges, m)
        except OverflowError:
            raise OverflowError(
                "binomial({}, {}) too large to be treated".format(n, k))
        except ValueError:
            raise ValueError(
                "number of edges m must be between 0 and binomial({}, {})".
                format(n, k))

        from sage.combinat.designs.incidence_structures import IncidenceStructure
        return IncidenceStructure(points=vertices, blocks=edges)
Example #15
0
class CoveringDesign(SageObject):
    """
    Covering design.

    INPUT:

    - ``v``, ``k``, ``t`` -- integer parameters of the covering design

    - ``size`` (integer)

    - ``points`` -- list of points (default points are `[0, ..., v-1]`)

    - ``blocks``

    - ``low_bd`` (integer) -- lower bound for such a design

    - ``method``, ``creator``, ``timestamp`` -- database information
    """
    def __init__(self,
                 v=0,
                 k=0,
                 t=0,
                 size=0,
                 points=None,
                 blocks=None,
                 low_bd=0,
                 method='',
                 creator='',
                 timestamp=''):
        """
        EXAMPLES::

            sage: C = CoveringDesign(5, 4, 3, 4, range(5), [[0, 1, 2, 3],
            ....:     [0, 1, 2, 4], [0, 1, 3, 4], [0, 2, 3, 4]], 4,
            ....:     'Lexicographic Covering')
            sage: print(C)
            C(5, 4, 3) = 4
            Method: Lexicographic Covering
            0   1   2   3
            0   1   2   4
            0   1   3   4
            0   2   3   4
        """
        self.__v = v
        self.__k = k
        self.__t = t
        self.__size = size
        if low_bd > 0:
            self.__low_bd = low_bd
        else:
            self.__low_bd = schonheim(v, k, t)
        self.__method = method
        self.__creator = creator
        self.__timestamp = timestamp
        if points is None:
            points = []
        if blocks is None:
            blocks = []
        self.__incidence_structure = IncidenceStructure(points, blocks)

    def __repr__(self):
        """
        Return the representation of this covering design.

        This has the parameters but not the blocks.

        EXAMPLES::

            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C
            (7, 3, 2)-covering design of size 7
            Lower bound: 7
            Method: Projective Plane
        """
        repr = ('(%d, %d, %d)-covering design of size %d\n' %
                (self.__v, self.__k, self.__t, self.__size))
        repr += 'Lower bound: %d\n' % (self.__low_bd)
        if self.__creator:
            repr += 'Created by: %s\n' % (self.__creator)
        if self.__method:
            repr += 'Method: %s\n' % (self.__method)
        if self.__timestamp:
            repr += 'Submitted on: %s\n' % (self.__timestamp)
        return repr[:-1]

    def __str__(self):
        """
        Return the string for this covering design.

        This has the parameters and the blocks in readable form.

        EXAMPLES::

            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: print(C)
            C(7, 3, 2) = 7
            Method: Projective Plane
            0   1   2
            0   3   4
            0   5   6
            1   3   5
            1   4   6
            2   3   6
            2   4   5
        """
        if self.__size == self.__low_bd:  # check if covering is optimal
            repr = ('C(%d, %d, %d) = %d\n' %
                    (self.__v, self.__k, self.__t, self.__size))
        else:
            repr = ('%d <= C(%d, %d, %d) <= %d\n' %
                    (self.__low_bd, self.__v, self.__k, self.__t, self.__size))
        if self.__creator:
            repr += 'Created by: %s\n' % (self.__creator)
        if self.__method:
            repr += 'Method: %s\n' % (self.__method)
        if self.__timestamp:
            repr += 'Submitted on: %s\n' % (self.__timestamp)
        return repr + '\n'.join(
            '  '.join(str(k) for k in block)
            for block in self.__incidence_structure.blocks())

    def is_covering(self):
        """
        Check all `t`-sets are in fact covered by the blocks of ``self``.

        .. NOTE::

            This is very slow and wasteful of memory.

        EXAMPLES::

            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C.is_covering()
            True
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6],
            ....:     [2, 4, 6]], 0, 'not a covering')   # last block altered
            sage: C.is_covering()
            False
        """
        v = self.__v
        k = self.__k
        t = self.__t
        Svt = Combinations(range(v), t)
        Skt = Combinations(range(k), t)
        tset = {}  # tables of t-sets: False = uncovered, True = covered
        for i in Svt:
            tset[tuple(i)] = False
        # mark all t-sets covered by each block
        for a in self.__incidence_structure.blocks():
            for z in Skt:
                y = (a[x] for x in z)
                tset[tuple(y)] = True
        for i in Svt:
            if not tset[tuple(i)]:  # uncovered
                return False
        return True  # everything was covered

    def v(self):
        """
        Return `v`, the number of points in the covering design.

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C.v()
            7
        """
        return self.__v

    def k(self):
        """
        Return `k`, the size of blocks of the covering design

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C.k()
            3
        """
        return self.__k

    def t(self):
        """
        Return `t`, the size of sets which must be covered by the
        blocks of the covering design

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C.t()
            2
        """
        return self.__t

    def size(self):
        """
        Return the number of blocks in the covering design

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C.size()
            7
        """
        return self.__size

    def low_bd(self):
        """
        Return a lower bound for the number of blocks a covering
        design with these parameters could have.

        Typically this is the Schonheim bound, but for some parameters
        better bounds have been shown.

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C.low_bd()
            7
        """
        return self.__low_bd

    def method(self):
        """
        Return the method used to create the covering design.

        This field is optional, and is used in a database to give information
        about how coverings were constructed.

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C.method()
            'Projective Plane'
        """
        return self.__method

    def creator(self):
        """
        Return the creator of the covering design

        This field is optional, and is used in a database to give
        attribution for the covering design It can refer to the person
        who submitted it, or who originally gave a construction

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6],
            ....:     [2, 4, 5]],0, 'Projective Plane', 'Gino Fano')
            sage: C.creator()
            'Gino Fano'
        """
        return self.__creator

    def timestamp(self):
        """
        Return the time that the covering was submitted to the database

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]],0, 'Projective Plane',
            ....:     'Gino Fano', '1892-01-01 00:00:00')
            sage: C.timestamp()  # No exact date known; in Fano's 1892 article
            '1892-01-01 00:00:00'
        """
        return self.__timestamp

    def incidence_structure(self):
        """
        Return the incidence structure of this design, without extra parameters.

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: D = C.incidence_structure()
            sage: D.ground_set()
            [0, 1, 2, 3, 4, 5, 6]
            sage: D.blocks()
            [[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5],
            [1, 4, 6], [2, 3, 6], [2, 4, 5]]

        """
        return self.__incidence_structure
Example #16
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
Example #17
0
class CoveringDesign(SageObject):
    """
    Covering design.

    INPUT:

    - ``v,k,t`` -- integer parameters of the covering design.

    - ``size`` (integer)

    - ``points`` -- list of points (default points are `[0,...v-1]`).

    - ``blocks``

    - ``low_bd`` (integer) -- lower bound for such a design

    - ``method, creator, timestamp`` -- database information.
    """

    def __init__(self, v=0, k=0, t=0, size=0, points=[], blocks=[], low_bd=0, method='', creator ='',timestamp=''):
        """
        EXAMPLES::

            sage: C=CoveringDesign(5,4,3,4,range(5),[[0,1,2,3],[0,1,2,4],[0,1,3,4],[0,2,3,4]],4, 'Lexicographic Covering')
            sage: print(C)
            C(5,4,3) = 4
            Method: Lexicographic Covering
            0   1   2   3
            0   1   2   4
            0   1   3   4
            0   2   3   4
        """
        self.__v = v
        self.__k = k
        self.__t = t
        self.__size = size
        if low_bd > 0:
            self.__low_bd = low_bd
        else:
            self.__low_bd = schonheim(v,k,t)
        self.__method = method
        self.__creator = creator
        self.__timestamp = timestamp
        self.__incidence_structure = IncidenceStructure(points, blocks)


    def __repr__(self):
        """
        A print method, giving the parameters and any other
        information about the covering (but not the blocks).

        EXAMPLES::

            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C
            (7,3,2)-covering design of size 7
            Lower bound: 7
            Method: Projective Plane
        """
        repr = '(%d,%d,%d)-covering design of size %d\n' % (self.__v,
                                                            self.__k,
                                                            self.__t,
                                                            self.__size)
        repr += 'Lower bound: %d\n' % (self.__low_bd)
        if self.__creator != '':
            repr += 'Created by: %s\n' % (self.__creator)
        if self.__method != '':
            repr += 'Method: %s\n' % (self.__method)
        if self.__timestamp != '':
            repr += 'Submitted on: %s\n' % (self.__timestamp)

        return repr

    def __str__(self):
        """
        A print method, displaying a covering design's parameters and blocks.

        OUTPUT:

        covering design parameters and blocks, in a readable form

        EXAMPLES::

            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: print(C)
            C(7,3,2) = 7
            Method: Projective Plane
            0   1   2
            0   3   4
            0   5   6
            1   3   5
            1   4   6
            2   3   6
            2   4   5
        """
        if self.__size == self.__low_bd:    # check if the covering is known to be optimal
            repr =  'C(%d,%d,%d) = %d\n'%(self.__v,self.__k,self.__t,self.__size)
        else:
            repr = '%d <= C(%d,%d,%d) <= %d\n'%(self.__low_bd,self.__v,self.__k,self.__t,self.__size);
        if self.__creator != '':
            repr += 'Created by: %s\n'%(self.__creator)
        if self.__method != '':
            repr += 'Method: %s\n'%(self.__method)
        if self.__timestamp != '':
            repr += 'Submitted on: %s\n'%(self.__timestamp)
        for i in range(self.__size):
            for j in range(self.__k):
                repr = repr + str(self.__incidence_structure.blocks()[i][j]) + '  '
            repr += '\n'

        return repr

    def is_covering(self):
        """
        Checks that all `t`-sets are in fact covered by the blocks of
        ``self``

        .. NOTE::

            This is very slow and wasteful of memory.

        EXAMPLES::

            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.is_covering()
            True
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 6]],0, 'not a covering')   # last block altered
            sage: C.is_covering()
            False
        """
        v = self.__v
        k = self.__k
        t = self.__t
        Svt = Combinations(range(v),t)
        Skt = Combinations(range(k),t)
        tset = {}       # tables of t-sets: False = uncovered, True = covered
        for i in Svt:
            tset[tuple(i)] = False

        # mark all t-sets covered by each block
        for a in self.__incidence_structure.blocks():
            for z in Skt:
                y = [a[x] for x in z]
                tset[tuple(y)] = True

        for i in Svt:
            if not tset[tuple(i)]:     # uncovered
                return False

        return True                  # everything was covered

    def v(self):
        """
        Return `v`, the number of points in the covering design.

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.v()
            7
        """
        return self.__v


    def k(self):
        """
        Return `k`, the size of blocks of the covering design

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.k()
            3
        """
        return self.__k


    def t(self):
        """
        Return `t`, the size of sets which must be covered by the
        blocks of the covering design

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.t()
            2
        """
        return self.__t

    def size(self):
        """
        Return the number of blocks in the covering design

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.size()
            7
        """
        return self.__size


    def low_bd(self):
        """
        Return a lower bound for the number of blocks a covering
        design with these parameters could have.

        Typically this is the Schonheim bound, but for some parameters
        better bounds have been shown.

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.low_bd()
            7
        """
        return self.__low_bd

    def method(self):
        """
        Return the method used to create the covering design
        This field is optional, and is used in a database to give information about how coverings were constructed

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.method()
            'Projective Plane'
        """
        return self.__method

    def creator(self):
        """
        Return the creator of the covering design

        This field is optional, and is used in a database to give
        attribution for the covering design It can refer to the person
        who submitted it, or who originally gave a construction

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane','Gino Fano')
            sage: C.creator()
            'Gino Fano'
        """
        return self.__creator

    def timestamp(self):
        """
        Return the time that the covering was submitted to the database

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane','Gino Fano','1892-01-01 00:00:00')
            sage: C.timestamp()  #Fano had an article in 1892, I don't know the date it appeared
            '1892-01-01 00:00:00'
        """
        return self.__timestamp


    def incidence_structure(self):
        """
        Return the incidence structure of a covering design, without all the extra parameters.

        EXAMPLES::

            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: D = C.incidence_structure()
            sage: D.ground_set()
            [0, 1, 2, 3, 4, 5, 6]
            sage: D.blocks()
            [[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]

        """
        return self.__incidence_structure
Example #18
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
Example #19
0
class CoveringDesign(SageObject):
    """
    Covering design.

    INPUT:
      data -- parameters (v,k,t)
              size
              incidence structure (points and blocks) -- default points are $[0,...v-1]$
              lower bound for such a design
              database information: creator, method, timestamp
    """
    def __init__(self,
                 v=0,
                 k=0,
                 t=0,
                 size=0,
                 points=[],
                 blocks=[],
                 low_bd=0,
                 method='',
                 creator='',
                 timestamp=''):
        """
        EXAMPLES:
            sage: C=CoveringDesign(5,4,3,4,range(5),[[0,1,2,3],[0,1,2,4],[0,1,3,4],[0,2,3,4]],4, 'Lexicographic Covering')
            sage: print C
            C(5,4,3) = 4
            Method: Lexicographic Covering
            0   1   2   3   
            0   1   2   4   
            0   1   3   4   
            0   2   3   4   
        """
        self.__v = v
        self.__k = k
        self.__t = t
        self.__size = size
        if low_bd > 0:
            self.__low_bd = low_bd
        else:
            self.__low_bd = schonheim(v, k, t)
        self.__method = method
        self.__creator = creator
        self.__timestamp = timestamp
        self.__incidence_structure = IncidenceStructure(points, blocks)

    def __repr__(self):
        """
        A print method, giving the parameters and any other information about the covering (but not the blocks).

        EXAMPLES:
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C
            (7,3,2)-covering design of size 7
            Lower bound: 7
            Method: Projective Plane
        """
        repr = '(%d,%d,%d)-covering design of size %d\n' % (
            self.__v, self.__k, self.__t, self.__size)
        repr += 'Lower bound: %d\n' % (self.__low_bd)
        if self.__creator != '':
            repr += 'Created by: %s\n' % (self.__creator)
        if self.__method != '':
            repr += 'Method: %s\n' % (self.__method)
        if self.__timestamp != '':
            repr += 'Submitted on: %s\n' % (self.__timestamp)

        return repr

    def __str__(self):
        """
        A print method, displaying a covering design's parameters and blocks.

        OUTPUT:
            covering design parameters and blocks, in a readable form
            
        EXAMPLES:
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: print C
            C(7,3,2) = 7
            Method: Projective Plane
            0   1   2   
            0   3   4   
            0   5   6   
            1   3   5
            1   4   6
            2   3   6
            2   4   5
        """
        if self.__size == self.__low_bd:  # check if the covering is known to be optimal
            repr = 'C(%d,%d,%d) = %d\n' % (self.__v, self.__k, self.__t,
                                           self.__size)
        else:
            repr = '%d <= C(%d,%d,%d) <= %d\n' % (
                self.__low_bd, self.__v, self.__k, self.__t, self.__size)
        if self.__creator != '':
            repr += 'Created by: %s\n' % (self.__creator)
        if self.__method != '':
            repr += 'Method: %s\n' % (self.__method)
        if self.__timestamp != '':
            repr += 'Submitted on: %s\n' % (self.__timestamp)
        for i in range(self.__size):
            for j in range(self.__k):
                repr = repr + str(
                    self.__incidence_structure.blocks()[i][j]) + '  '
            repr += '\n'

        return repr

    def is_covering(self):
        """
        Checks that all t-sets are in fact covered.

        INPUT:
            putative covering design

        OUTPUT:
            True if all t-sets are in at least one block


        NOTES:
            This is very slow and wasteful of memory.  A faster Cython
            version will be added soon.

        EXAMPLES:
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.is_covering()
            True
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 6]],0, 'not a covering')   # last block altered
            sage: C.is_covering()
            False
        """
        v = self.__v
        k = self.__k
        t = self.__t
        Svt = Combinations(range(v), t)
        Skt = Combinations(range(k), t)
        tset = {}  # tables of t-sets: False = uncovered, True = covered
        for i in Svt:
            tset[tuple(i)] = False

        # mark all t-sets covered by each block
        for a in self.__incidence_structure.blocks():
            for z in Skt:
                y = [a[x] for x in z]
                tset[tuple(y)] = True

        for i in Svt:
            if tset[tuple(i)] == False:  # uncovered
                return False

        return True  # everything was covered

    def v(self):
        """
        Return v, the number of points in the covering design

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.v()
            7
        """
        return self.__v

    def k(self):
        """
        Return k, the size of blocks of the covering design

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.k()
            3
        """
        return self.__k

    def t(self):
        """
        Return t, the size of sets which must be covered by the blocks of the covering design

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.t()
            2
        """
        return self.__t

    def size(self):
        """
        Return the number of blocks in the covering design

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.size()
            7
        """
        return self.__size

    def low_bd(self):
        """
        Return a lower bound for the number of blocks a covering design with these parameters could have.
        Typically this is the Schonheim bound, but for some parameters better bounds have been shown.

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.low_bd()
            7
        """
        return self.__low_bd

    def method(self):
        """
        Return the method used to create the covering design
        This field is optional, and is used in a database to give information about how coverings were constructed

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.method()
            'Projective Plane'
        """
        return self.__method

    def creator(self):
        """
        Return the creator of the covering design
        This field is optional, and is used in a database to give attribution for the covering design
        It can refer to the person who submitted it, or who originally gave a construction

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane','Gino Fano')
            sage: C.creator()
            'Gino Fano'
        """
        return self.__creator

    def timestamp(self):
        """
        Return the time that the covering was submitted to the database

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane','Gino Fano','1892-01-01 00:00:00')
            sage: C.timestamp()  #Fano had an article in 1892, I don't know the date it appeared
            '1892-01-01 00:00:00'
        """
        return self.__timestamp

    def incidence_structure(self):
        """
        Return the incidence structure of a covering design, without all the extra parameters.

        EXAMPLES:
            sage: from sage.combinat.designs.covering_design import CoveringDesign
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: D = C.incidence_structure()
            sage: D.points()
            [0, 1, 2, 3, 4, 5, 6]
            sage: D.blocks()
            [[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]

        """
        return self.__incidence_structure
Example #20
0
def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False):
    r"""
    Return the collinearity graph of the generalized quadrangle `AS(q)`, or of its dual

    Let `q` be an odd prime power.  `AS(q)` is a generalized quadrangle [GQwiki]_ of
    order `(q-1,q+1)`, see 3.1.5 in [PT09]_. Its points are elements
    of `F_q^3`, and lines are sets of size `q` of the form

    * `\{ (\sigma, a, b) \mid \sigma\in F_q \}`
    * `\{ (a, \sigma, b) \mid \sigma\in F_q \}`
    * `\{ (c \sigma^2 - b \sigma + a, -2 c \sigma + b, \sigma) \mid \sigma\in F_q \}`,

    where `a`, `b`, `c` are arbitrary elements of `F_q`.

    INPUT:

    - ``q`` -- a power of an odd prime number

    - ``dual`` -- if ``False`` (default), return the collinearity graph of `AS(q)`.
      Otherwise return the collinearity graph of the dual `AS(q)`.

    EXAMPLES::

        sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g
        AS(5); GQ(4, 6): Graph on 125 vertices
        sage: g.is_strongly_regular(parameters=True)
        (125, 28, 3, 7)
        sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5,dual=True); g
        AS(5)*; GQ(6, 4): Graph on 175 vertices
        sage: g.is_strongly_regular(parameters=True)
        (175, 30, 5, 5)

    REFERENCE:

    .. [GQwiki] `Generalized quadrangle
      <http://en.wikipedia.org/wiki/Generalized_quadrangle>`__

    .. [PT09] S. Payne, J. A. Thas.
      Finite generalized quadrangles.
      European Mathematical Society,
      2nd edition, 2009.
    """
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    p, k = is_prime_power(q,get_data=True)
    if k==0 or p==2:
       raise ValueError('q must be an odd prime power')
    F = FiniteField(q, 'a')
    L = []
    for a in F:
        for b in F:
            L.append(tuple(map(lambda s: (s, a, b), F)))
            L.append(tuple(map(lambda s: (a, s, b), F)))
            for c in F:
                L.append(tuple(map(lambda s: (c*s**2 - b*s + a, -2*c*s + b, s), F)))
    if dual:
        G = IncidenceStructure(L).intersection_graph()
        G.name('AS('+str(q)+')*; GQ'+str((q+1,q-1)))
    else:
        G = IncidenceStructure(L).dual().intersection_graph()
        G.name('AS('+str(q)+'); GQ'+str((q-1,q+1)))
    return G