Covering designs: coverings of \(t\)-element subsets of a \(v\)-set by \(k\)-sets - Combinatorics

Skip to content
Back to top
View this page
Edit this page

# Covering designs: coverings of \(t\)-element subsets of a \(v\)-set by \(k\)-sets

A \((v, k, t)\) covering design \(C\) is an incidence structure consisting of a set of points \(P\) of order \(v\), and a set of blocks \(B\), where each block contains \(k\) points of \(P\). Every \(t\)-element subset of \(P\) must be contained in at least one block.

If every \(t\)-set is contained in exactly one block of \(C\), then we have a block design. Following the block design implementation, the standard representation of a covering design uses \(P = [0, 1, ..., v-1]\).

In addition to the parameters and incidence structure for a covering design from this database, we include extra information:

- Best known lower bound on the size of a \((v, k, t)\)-covering design

- Name of the person(s) who produced the design

- Method of construction used

- Date when the design was added to the database

REFERENCES:

[1]

La Jolla Covering Repository, https://dmgordon.org/cover

[2]

Daniel M. Gordon and Douglas R. Stinson, Coverings, Chapter 1 in: Charles J. Colbourn and Jeffrey H. Dinitz, Handbook of Combinatorial Designs, 2nd Edition, 2006. https://www.dmgordon.org/papers/hcd.pdf

AUTHORS:

- Daniel M. Gordon (2008-12-22): initial version

## Classes and methods

class sage.combinat.designs.covering_design.CoveringDesign(v=0, k=0, t=0, size=0, points=None, blocks=None, low_bd=0, method='', creator='', timestamp='')

  Bases: `SageObject`

  Covering design.

  INPUT:

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

  - `size` – integer

  - `points` – list of points (default: \([0, ..., v-1]\))

  - `blocks`

  - `low_bd` – integer; lower bound for such a design

  - `method`, `creator`, `timestamp` – database information

  creator()

    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

        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'

    Python

        >>> from sage.all import *
        >>> from sage.combinat.designs.covering_design import CoveringDesign
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)], [Integer(2), Integer(3), Integer(6)],
        ...     [Integer(2), Integer(4), Integer(5)]],Integer(0), 'Projective Plane', 'Gino Fano')
        >>> C.creator()
        'Gino Fano'

  incidence_structure()

    Return the incidence structure of this design, without extra parameters.

    EXAMPLES:

    Sage

        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]]

    Python

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

  is_covering()

    Check all \(t\)-sets are in fact covered by the blocks of `self`.

    Note

    This is very slow and wasteful of memory.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)],
        ...     [Integer(2), Integer(3), Integer(6)], [Integer(2), Integer(4), Integer(5)]], Integer(0), 'Projective Plane')
        >>> C.is_covering()
        True
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)], [Integer(2), Integer(3), Integer(6)],
        ...     [Integer(2), Integer(4), Integer(6)]], Integer(0), 'not a covering')   # last block altered
        >>> C.is_covering()
        False

  k()

    Return \(k\), the size of blocks of the covering design.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.combinat.designs.covering_design import CoveringDesign
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)],
        ...     [Integer(2), Integer(3), Integer(6)], [Integer(2), Integer(4), Integer(5)]], Integer(0), 'Projective Plane')
        >>> C.k()
        3

  low_bd()

    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

        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

    Python

        >>> from sage.all import *
        >>> from sage.combinat.designs.covering_design import CoveringDesign
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)],
        ...     [Integer(2), Integer(3), Integer(6)], [Integer(2), Integer(4), Integer(5)]], Integer(0), 'Projective Plane')
        >>> C.low_bd()
        7

  method()

    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

        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'

    Python

        >>> from sage.all import *
        >>> from sage.combinat.designs.covering_design import CoveringDesign
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)],
        ...     [Integer(2), Integer(3), Integer(6)], [Integer(2), Integer(4), Integer(5)]], Integer(0), 'Projective Plane')
        >>> C.method()
        'Projective Plane'

  size()

    Return the number of blocks in the covering design.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.combinat.designs.covering_design import CoveringDesign
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)],
        ...     [Integer(2), Integer(3), Integer(6)], [Integer(2), Integer(4), Integer(5)]], Integer(0), 'Projective Plane')
        >>> C.size()
        7

  t()

    Return \(t\), the size of sets which must be covered by the blocks of the covering design

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.combinat.designs.covering_design import CoveringDesign
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)],
        ...     [Integer(2), Integer(3), Integer(6)], [Integer(2), Integer(4), Integer(5)]], Integer(0), 'Projective Plane')
        >>> C.t()
        2

  timestamp()

    Return the time that the covering was submitted to the database.

    EXAMPLES:

    Sage

        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'

    Python

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

  v()

    Return \(v\), the number of points in the covering design.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.combinat.designs.covering_design import CoveringDesign
        >>> C = CoveringDesign(Integer(7), Integer(3), Integer(2), Integer(7), range(Integer(7)), [[Integer(0), Integer(1), Integer(2)],
        ...     [Integer(0), Integer(3), Integer(4)], [Integer(0), Integer(5), Integer(6)], [Integer(1), Integer(3), Integer(5)], [Integer(1), Integer(4), Integer(6)],
        ...     [Integer(2), Integer(3), Integer(6)], [Integer(2), Integer(4), Integer(5)]], Integer(0), 'Projective Plane')
        >>> C.v()
        7

sage.combinat.designs.covering_design.best_known_covering_design_www(v, k, t, verbose=False)

  Return the best known \((v, k, t)\) covering design from an online database.

  This uses the La Jolla Covering Repository, a database available at https://ljcr.dmgordon.org/cover.html

  INPUT:

  - `v` – integer; the size of the point set for the design

  - `k` – integer; the number of points per block

  - `t` – integer; the size of sets covered by the blocks

  - `verbose` – boolean (default: `False`); print verbose message

  OUTPUT:

  A `CoveringDesign` object representing the `(v, k, t)`-covering design with smallest number of blocks available in the database.

  EXAMPLES:

  Sage

      sage: from sage.combinat.designs.covering_design import (  # optional - internet
      ....:     best_known_covering_design_www)
      sage: C = best_known_covering_design_www(7, 3, 2)  # optional - internet
      sage: print(C)                                     # optional - internet
      C(7, 3, 2) = 7
      Method: lex covering
      Submitted on: 1996-12-01 00:00:00
      0  1  2
      0  3  4
      0  5  6
      1  3  5
      1  4  6
      2  3  6
      2  4  5

  Python

      >>> from sage.all import *
      >>> from sage.combinat.designs.covering_design import (  # optional - internet
      ...     best_known_covering_design_www)
      >>> C = best_known_covering_design_www(Integer(7), Integer(3), Integer(2))  # optional - internet
      >>> print(C)                                     # optional - internet
      C(7, 3, 2) = 7
      Method: lex covering
      Submitted on: 1996-12-01 00:00:00
      0  1  2
      0  3  4
      0  5  6
      1  3  5
      1  4  6
      2  3  6
      2  4  5

  A `ValueError` is raised if the `(v, k, t)` parameters are not found in the database.

sage.combinat.designs.covering_design.schonheim(v, k, t)

  Return the Schonheim lower bound for the size of such a covering design.

  INPUT:

  - `v` – integer; size of point set

  - `k` – integer; cardinality of each block

  - `t` – integer; cardinality of sets being covered

  OUTPUT:

  The Schonheim lower bound for such a covering design’s size: \(C(v, k, t) \leq \lceil(\frac{v}{k} \lceil \frac{v-1}{k-1} \cdots \lceil \frac{v-t+1}{k-t+1} \rceil \cdots \rceil \rceil\)

  EXAMPLES:

  Sage

      sage: from sage.combinat.designs.covering_design import schonheim
      sage: schonheim(10, 3, 2)
      17
      sage: schonheim(32, 16, 8)
      930

  Python

      >>> from sage.all import *
      >>> from sage.combinat.designs.covering_design import schonheim
      >>> schonheim(Integer(10), Integer(3), Integer(2))
      17
      >>> schonheim(Integer(32), Integer(16), Integer(8))
      930

sage.combinat.designs.covering_design.trivial_covering_design(v, k, t)

  Construct a trivial covering design.

  INPUT:

  - `v` – integer; size of point set

  - `k` – integer; cardinality of each block

  - `t` – integer; cardinality of sets being covered

  OUTPUT:

  A trivial \((v, k, t)\) covering design

  EXAMPLES:

  Sage

      sage: C = trivial_covering_design(8, 3, 1)
      sage: print(C)
      C(8, 3, 1) = 3
      Method: Trivial
      0   1   2
      0   6   7
      3   4   5
      sage: C = trivial_covering_design(5, 3, 2)
      sage: print(C)
      4 <= C(5, 3, 2) <= 10
      Method: Trivial
      0   1   2
      0   1   3
      0   1   4
      0   2   3
      0   2   4
      0   3   4
      1   2   3
      1   2   4
      1   3   4
      2   3   4

  Python

      >>> from sage.all import *
      >>> C = trivial_covering_design(Integer(8), Integer(3), Integer(1))
      >>> print(C)
      C(8, 3, 1) = 3
      Method: Trivial
      0   1   2
      0   6   7
      3   4   5
      >>> C = trivial_covering_design(Integer(5), Integer(3), Integer(2))
      >>> print(C)
      4 <= C(5, 3, 2) <= 10
      Method: Trivial
      0   1   2
      0   1   3
      0   1   4
      0   2   3
      0   2   4
      0   3   4
      1   2   3
      1   2   4
      1   3   4
      2   3   4

  Note

  Cases are:

  - \(t=0\): This could be empty, but it’s a useful convention to have one block (which is empty if \(k=0\)).

  - \(t=1\) : This contains \(\lceil v/k \rceil\) blocks: \([0, ..., k-1], [k, ..., 2k-1], ...\). The last block wraps around if \(k\) does not divide \(v\).

  - anything else: Just use every \(k\)-subset of \([0, 1,..., v-1]\).