### Navigation

- index
- modules |
- next |
- previous |
- Combinatorics »
- Designs and Incidence Structures »

# Difference families

This module gathers everything related to difference families. One can build a difference family (or check that it can be built) with `difference_family()`:

    sage: G,F = designs.difference_family(13,4,1)

It defines the following functions:

`is_difference_family()` | Check if the input is a (`k`, `l`)-difference family.
`singer_difference_set()` | Return a difference set associated to hyperplanes in a projective space.
`difference_family()` | Return a (`k`, `l`)-difference family on an Abelian group of size `v`.

REFERENCES:

[Wi72] | R. M. Wilson “Cyclotomy and difference families in elementary Abelian groups”, J. of Num. Th., 4 (1972), pp. 17-47.

## Functions

`sage.combinat.designs.difference_family.``block_stabilizer`(G, B)

  Compute the left stabilizer of the block `B` under the action of `G`.

  This function return the list of all \(x\in G\) such that \(x\cdot B=B\) (as a set).

  INPUT:

  - `G` – a group (additive or multiplicative).
  - `B` – a subset of `G`.

  EXAMPLES:

      sage: from sage.combinat.designs.difference_family import block_stabilizer

      sage: Z8 = Zmod(8)
      sage: block_stabilizer(Z8, [Z8(0),Z8(2),Z8(4),Z8(6)])
      [0, 2, 4, 6]
      sage: block_stabilizer(Z8, [Z8(0),Z8(2)])
      [0]

      sage: C = cartesian_product([Zmod(4),Zmod(3)])
      sage: block_stabilizer(C, [C((0,0)),C((2,0)),C((0,1)),C((2,1))])
      [(0, 0), (2, 0)]

      sage: b = map(Zmod(45),[1, 3, 7, 10, 22, 25, 30, 35, 37, 38, 44])
      sage: block_stabilizer(Zmod(45),b)
      [0]

`sage.combinat.designs.difference_family.``difference_family`(v, k, l=1, existence=False, check=True)

  Return a (`k`, `l`)-difference family on an Abelian group of cardinality `v`.

  Let \(G\) be a finite Abelian group. For a given subset \(D\) of \(G\), we define \(\Delta D\) to be the multi-set of differences \(\Delta D = \{x - y; x \in D, y \in D, x \not= y\}\). A \((G,k,\lambda)\)-difference family is a collection of \(k\)-subsets of \(G\), \(D = \{D_1, D_2, \ldots, D_b\}\) such that the union of the difference sets \(\Delta D_i\) for \(i=1,...b\), seen as a multi-set, contains each element of \(G \backslash \{0\}\) exactly \(\lambda\)-times.

  When there is only one block, i.e. \(\lambda(v - 1) = k(k-1)\), then a \((G,k,\lambda)\)-difference family is also called a difference set.

  See also Wikipedia article Difference_set.

  If there is no such difference family, an `EmptySetError` is raised and if there is no construction at the moment `NotImplementedError` is raised.

  EXAMPLES:

      sage: K,D = designs.difference_family(73,4)
      sage: D
      [[0, 1, 8, 64],
       [0, 25, 54, 67],
       [0, 41, 36, 69],
       [0, 3, 24, 46],
       [0, 2, 16, 55],
       [0, 50, 35, 61]]

      sage: K,D = designs.difference_family(337,7)
      sage: D
      [[1, 175, 295, 64, 79, 8, 52],
       [326, 97, 125, 307, 142, 249, 102],
       [121, 281, 310, 330, 123, 294, 226],
       [17, 279, 297, 77, 332, 136, 210],
       [150, 301, 103, 164, 55, 189, 49],
       [35, 59, 215, 218, 69, 280, 135],
       [289, 25, 331, 298, 252, 290, 200],
       [191, 62, 66, 92, 261, 180, 159]]

  For \(k=6,7\) we look at the set of small prime powers for which a construction is available:

      sage: def prime_power_mod(r,m):
      ....:     k = m+r
      ....:     while True:
      ....:         if is_prime_power(k):
      ....:             yield k
      ....:         k += m

      sage: from itertools import islice
      sage: l6 = {True:[], False: [], Unknown: []}
      sage: for q in islice(prime_power_mod(1,30), 60):
      ....:     l6[designs.difference_family(q,6,existence=True)].append(q)
      sage: l6[True]
      [31, 121, 151, 181, 211, ...,  3061, 3121, 3181]
      sage: l6[Unknown]
      [61]
      sage: l6[False]
      []

      sage: l7 = {True: [], False: [], Unknown: []}
      sage: for q in islice(prime_power_mod(1,42), 60):
      ....:     l7[designs.difference_family(q,7,existence=True)].append(q)
      sage: l7[True]
      [337, 421, 463, 883, 1723, 3067, 3319, 3529, 3823, 3907, 4621, 4957, 5167]
      sage: l7[Unknown]
      [43, 127, 169, 211, ..., 4999, 5041, 5209]
      sage: l7[False]
      []

  Other constructions for \(\lambda > 1\):

      sage: for v in xrange(2,100):
      ....:     constructions = []
      ....:     for k in xrange(2,10):
      ....:         for l in xrange(2,10):
      ....:             if designs.difference_family(v,k,l,existence=True):
      ....:                 constructions.append((k,l))
      ....:                 _ = designs.difference_family(v,k,l)
      ....:     if constructions:
      ....:         print "%2d: %s"%(v, ', '.join('(%d,%d)'%(k,l) for k,l in constructions))
       2: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
       3: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
       4: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
       5: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
       7: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
       8: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
       9: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      11: (3,2), (4,3), (4,6), (5,2), (5,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      13: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8)
      15: (4,6), (5,6), (7,3)
      16: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      17: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8)
      19: (3,2), (4,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,4), (9,5), (9,6), (9,7), (9,8)
      21: (4,3), (6,3), (6,5)
      22: (4,2), (6,5), (7,4), (8,8)
      23: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      25: (3,2), (4,3), (5,4), (6,5), (7,6), (7,7), (8,7), (9,8)
      27: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      28: (3,2), (6,5)
      29: (3,2), (4,3), (5,4), (6,5), (7,3), (7,6), (8,4), (8,6), (8,7), (9,8)
      31: (3,2), (4,2), (4,3), (5,2), (5,4), (6,5), (7,6), (8,7), (9,8)
      32: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      33: (5,5), (6,5)
      34: (4,2)
      35: (5,2), (8,4)
      37: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,2), (9,3), (9,8)
      39: (6,5)
      40: (3,2)
      41: (3,2), (4,3), (5,4), (6,3), (6,5), (7,6), (8,7), (9,8)
      43: (3,2), (4,2), (4,3), (5,4), (6,5), (7,2), (7,3), (7,6), (8,4), (8,7), (9,8)
      46: (4,2), (6,2)
      47: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      49: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8)
      51: (5,2), (6,3)
      53: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      55: (9,4)
      57: (7,3)
      59: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      61: (3,2), (4,3), (5,4), (6,2), (6,3), (6,5), (7,6), (8,7), (9,8)
      64: (3,2), (4,3), (5,4), (6,5), (7,2), (7,6), (8,7), (9,8)
      67: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      71: (3,2), (4,3), (5,2), (5,4), (6,5), (7,3), (7,6), (8,4), (8,7), (9,8)
      73: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      75: (5,2)
      79: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      81: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      83: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      85: (7,2), (7,3), (8,2)
      89: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
      97: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8)

  TESTS:

  Check more of the Wilson constructions from [Wi72]:

      sage: Q5 = [241, 281,421,601,641, 661, 701, 821,881]
      sage: Q9 = [73, 1153, 1873, 2017]
      sage: Q15 = [76231]
      sage: Q4 = [13, 73, 97, 109, 181, 229, 241, 277, 337, 409, 421, 457]
      sage: Q8 = [1009, 3137, 3697]
      sage: for Q,k in [(Q4,4),(Q5,5),(Q8,8),(Q9,9),(Q15,15)]:
      ....:     for q in Q:
      ....:         assert designs.difference_family(q,k,1,existence=True) is True
      ....:         _ = designs.difference_family(q,k,1)

  Check Singer difference sets:

      sage: sgp = lambda q,d: ((q**(d+1)-1)//(q-1), (q**d-1)//(q-1), (q**(d-1)-1)//(q-1))

      sage: for q in range(2,10):
      ....:     if is_prime_power(q):
      ....:         for d in [2,3,4]:
      ....:           v,k,l = sgp(q,d)
      ....:           assert designs.difference_family(v,k,l,existence=True) is True
      ....:           _ = designs.difference_family(v,k,l)

  Check twin primes difference sets:

      sage: for p in [3,5,7,9,11]:
      ....:     v = p*(p+2); k = (v-1)/2;  lmbda = (k-1)/2
      ....:     G,D = designs.difference_family(v,k,lmbda)

  Check the database:

  > sage: from sage.combinat.designs.database import DF sage: for v,k,l in DF: ....: df = designs.difference_family(v,k,l,check=True)

  Todo

  Implement recursive constructions from Buratti “Recursive for difference matrices and relative difference families” (1998) and Jungnickel “Composition theorems for difference families and regular planes” (1978)

`sage.combinat.designs.difference_family.``group_law`(G)

  Return a triple `(identity, operation, inverse)` that define the operations on the group `G`.

  EXAMPLES:

      sage: from sage.combinat.designs.difference_family import group_law
      sage: group_law(Zmod(3))
      (0, <built-in function add>, <built-in function neg>)
      sage: group_law(SymmetricGroup(5))
      ((), <built-in function mul>, <built-in function inv>)
      sage: group_law(VectorSpace(QQ,3))
      ((0, 0, 0), <built-in function add>, <built-in function neg>)

`sage.combinat.designs.difference_family.``is_difference_family`(G, D, v=None, k=None, l=None, verbose=False)

  Check wether `D` forms a difference family in the group `G`.

  INPUT:

  - `G` - group of cardinality `v`
  - `D` - a set of `k`-subsets of `G`
  - `v`, `k` and `l` - optional parameters of the difference family
  - `verbose` - whether to print additional information

  See also

  `difference_family()`

  EXAMPLES:

      sage: from sage.combinat.designs.difference_family import is_difference_family
      sage: G = Zmod(21)
      sage: D = [[0,1,4,14,16]]
      sage: is_difference_family(G, D, 21, 5)
      True

      sage: G = Zmod(41)
      sage: D = [[0,1,4,11,29],[0,2,8,17,21]]
      sage: is_difference_family(G, D, verbose=True)
      Too few:
        5 is obtained 0 times in blocks []
        14 is obtained 0 times in blocks []
        27 is obtained 0 times in blocks []
        36 is obtained 0 times in blocks []
      Too much:
        4 is obtained 2 times in blocks [0, 1]
        13 is obtained 2 times in blocks [0, 1]
        28 is obtained 2 times in blocks [0, 1]
        37 is obtained 2 times in blocks [0, 1]
      False
      sage: D = [[0,1,4,11,29],[0,2,8,17,22]]
      sage: is_difference_family(G, D)
      True

      sage: G = Zmod(61)
      sage: D = [[0,1,3,13,34],[0,4,9,23,45],[0,6,17,24,32]]
      sage: is_difference_family(G, D)
      True

      sage: G = AdditiveAbelianGroup([3]*4)
      sage: a,b,c,d = G.gens()
      sage: D = [[d, -a+d, -c+d, a-b-d, b+c+d],
      ....:      [c, a+b-d, -b+c, a-b+d, a+b+c],
      ....:      [-a-b+c+d, a-b-c-d, -a+c-d, b-c+d, a+b],
      ....:      [-b-d, a+b+d, a-b+c-d, a-b+c, -b+c+d]]
      sage: is_difference_family(G, D)
      True

  The following example has a third block with a non-trivial stabilizer:

      sage: G = Zmod(15)
      sage: D = [[0,1,4],[0,2,9],[0,5,10]]
      sage: is_difference_family(G,D,verbose=True)
      It is a (15,3,1)-difference family
      True

  The function also supports multiplicative groups (non necessarily Abelian):

      sage: G = DihedralGroup(8)
      sage: x,y = G.gens()
      sage: i = G.one()
      sage: D1 = [[i,x,x^4], [i,x^2, y*x], [i,x^5,y], [i,x^6,y*x^2], [i,x^7,y*x^5]]
      sage: is_difference_family(G, D1, 16, 3, 2)
      True
      sage: from sage.combinat.designs.bibd import BIBD_from_difference_family
      sage: bibd = BIBD_from_difference_family(G,D1,lambd=2)

`sage.combinat.designs.difference_family.``singer_difference_set`(q, d)

  Return a difference set associated to the set of hyperplanes in a projective space of dimension \(d\) over \(GF(q)\).

  A Singer difference set has parameters:

  \[v = \frac{q^{d+1}-1}{q-1}, \quad k = \frac{q^d-1}{q-1}, \quad \lambda = \frac{q^{d-1}-1}{q-1}.\]

  The idea of the construction is as follows. One consider the finite field \(GF(q^{d+1})\) as a vector space of dimension \(d+1\) over \(GF(q)\). The set of \(GF(q)\)-lines in \(GF(q^{d+1})\) is a projective plane and its set of hyperplanes form a balanced incomplete block design.

  Now, considering a multiplicative generator \(z\) of \(GF(q^{d+1})\), we get a transitive action of a cyclic group on our projective plane from which it is possible to build a difference set.

  The construction is given in details in [Stinson2004], section 3.3.

  EXAMPLES:

      sage: from sage.combinat.designs.difference_family import singer_difference_set, is_difference_family
      sage: G,D = singer_difference_set(3,2)
      sage: is_difference_family(G,D,verbose=True)
      It is a (13,4,1)-difference family
      True

      sage: G,D = singer_difference_set(4,2)
      sage: is_difference_family(G,D,verbose=True)
      It is a (21,5,1)-difference family
      True

      sage: G,D = singer_difference_set(3,3)
      sage: is_difference_family(G,D,verbose=True)
      It is a (40,13,4)-difference family
      True

      sage: G,D = singer_difference_set(9,3)
      sage: is_difference_family(G,D,verbose=True)
      It is a (820,91,10)-difference family
      True

### Navigation

- index
- modules |
- next |
- previous |
- Combinatorics »
- Designs and Incidence Structures »