Evenly distributed sets in finite fields¶
This module consists of a simple class EvenlyDistributedSetsBacktracker. Its main
purpose is to iterate through the evenly distributed sets of a given finite
field.
The naive backtracker implemented here is not directly used to generate
difference family as even for small parameters it already takes time to run.
Instead, its output has been stored into a database
sage.combinat.designs.database. If the backtracker is improved, then one
might want to update this database with more values.
Classes and methods¶
- class sage.combinat.designs.evenly_distributed_sets.EvenlyDistributedSetsBacktracker[source]¶
- Bases: - object- Set of evenly distributed subsets in finite fields. - Definition: Let \(K\) be a finite field of cardinality \(q\) and \(k\) an integer so that \(k(k-1)\) divides \(q-1\). Let \(H = K^*\) be the multiplicative group of invertible elements in \(K\). A \(k\)-evenly distributed set in \(K\) is a set \(B = \{b_1, b_2, \ldots, b_k\}\) of \(k\) elements of \(K\) so that the \(k(k-1)\) differences \(\Delta B = \{b_i - b_j; i \not= j\}\) hit each coset modulo \(H^{2(q-1)/(k(k-1))}\) exactly twice. - Evenly distributed sets were introduced by Wilson [Wi72] (see also [BJL99-1], Chapter VII.6). He proved that for any \(k\), and for any prime power \(q\) large enough such that \(k(k-1)\) divides \(k\) there exists a \(k\)-evenly distributed set in the field of cardinality \(q\). This existence result based on a counting argument (using Dirichlet theorem) does not provide a simple method to generate them. - From a \(k\)-evenly distributed set, it is straightforward to build a \((q,k,1)\)-difference family (see - to_difference_family()). Another approach to generate a difference family, somehow dual to this one, is via radical difference family (see in particular- radical_difference_family()from the module- difference_family).- By default, this backtracker only considers evenly distributed sets up to affine automorphisms, i.e. \(B\) is considered equivalent to \(s B + t\) for any invertible element \(s\) and any element \(t\) in the field \(K\). Note that the set of differences is just multiplicatively translated by \(s\) as \(\Delta (s B + t) = s (\Delta B)\), and so that \(B\) is an evenly distributed set if and only if \(sB\) is one too. This behaviour can be modified via the argument - up_to_isomorphism(see the input section and the examples below).- INPUT: - K– a finite field of cardinality \(q\)
- k– positive integer such that \(k(k-1)\) divides \(q-1\)
- up_to_isomorphism– boolean (default:- True); whether only consider evenly distributed sets up to automorphisms of the field of the form \(x \mapsto ax + b\). If set to- Falsethen the iteration is over all evenly distributed sets that contain- 0and- 1.
- check– boolean (default:- False); whether you want to check intermediate steps of the iterator. This is mainly intended for debugging purpose. Setting it to- Truewill considerably slow the iteration.
 - EXAMPLES: - The main part of the code is contained in the iterator. To get one evenly distributed set just do: - sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker sage: E = EvenlyDistributedSetsBacktracker(Zmod(151),6) sage: B = E.an_element() sage: B [0, 1, 69, 36, 57, 89] - >>> from sage.all import * >>> from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker >>> E = EvenlyDistributedSetsBacktracker(Zmod(Integer(151)),Integer(6)) >>> B = E.an_element() >>> B [0, 1, 69, 36, 57, 89] - The class has a method to convert it to a difference family: - sage: E.to_difference_family(B) [[0, 1, 69, 36, 57, 89], [0, 132, 48, 71, 125, 121], [0, 59, 145, 10, 41, 117], [0, 87, 114, 112, 127, 42], [0, 8, 99, 137, 3, 108]] - >>> from sage.all import * >>> E.to_difference_family(B) [[0, 1, 69, 36, 57, 89], [0, 132, 48, 71, 125, 121], [0, 59, 145, 10, 41, 117], [0, 87, 114, 112, 127, 42], [0, 8, 99, 137, 3, 108]] - It is also possible to run over all evenly distributed sets: - sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=False) sage: for B in E: print(B) [0, 1, 11, 5] [0, 1, 4, 6] [0, 1, 9, 3] [0, 1, 8, 10] sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=True) sage: for B in E: print(B) [0, 1, 11, 5] - >>> from sage.all import * >>> E = EvenlyDistributedSetsBacktracker(Zmod(Integer(13)), Integer(4), up_to_isomorphism=False) >>> for B in E: print(B) [0, 1, 11, 5] [0, 1, 4, 6] [0, 1, 9, 3] [0, 1, 8, 10] >>> E = EvenlyDistributedSetsBacktracker(Zmod(Integer(13)), Integer(4), up_to_isomorphism=True) >>> for B in E: print(B) [0, 1, 11, 5] - Or only count them: - sage: for k in range(13, 200, 12): ....: if is_prime_power(k): ....: K = GF(k,'a') ....: E1 = EvenlyDistributedSetsBacktracker(K, 4, False) ....: E2 = EvenlyDistributedSetsBacktracker(K, 4, True) ....: print("{:3} {:3} {:3}".format(k, E1.cardinality(), E2.cardinality())) 13 4 1 25 40 4 37 12 1 49 24 2 61 12 1 73 48 4 97 64 6 109 72 6 121 240 20 157 96 8 169 240 20 181 204 17 193 336 28 - >>> from sage.all import * >>> for k in range(Integer(13), Integer(200), Integer(12)): ... if is_prime_power(k): ... K = GF(k,'a') ... E1 = EvenlyDistributedSetsBacktracker(K, Integer(4), False) ... E2 = EvenlyDistributedSetsBacktracker(K, Integer(4), True) ... print("{:3} {:3} {:3}".format(k, E1.cardinality(), E2.cardinality())) 13 4 1 25 40 4 37 12 1 49 24 2 61 12 1 73 48 4 97 64 6 109 72 6 121 240 20 157 96 8 169 240 20 181 204 17 193 336 28 - Note that by definition, the number of evenly distributed sets up to isomorphisms is at most \(k(k-1)\) times smaller than without isomorphisms. But it might not be exactly \(k(k-1)\) as some of them might have symmetries: - sage: B = EvenlyDistributedSetsBacktracker(Zmod(13), 4).an_element() sage: B [0, 1, 11, 5] sage: [9*x + 5 for x in B] [5, 1, 0, 11] sage: [3*x + 11 for x in B] [11, 1, 5, 0] - >>> from sage.all import * >>> B = EvenlyDistributedSetsBacktracker(Zmod(Integer(13)), Integer(4)).an_element() >>> B [0, 1, 11, 5] >>> [Integer(9)*x + Integer(5) for x in B] [5, 1, 0, 11] >>> [Integer(3)*x + Integer(11) for x in B] [11, 1, 5, 0] - an_element()[source]¶
- Return an evenly distributed set. - If there is no such subset raise an - EmptySetError.- EXAMPLES: - sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker sage: E = EvenlyDistributedSetsBacktracker(Zmod(41),5) sage: E.an_element() [0, 1, 13, 38, 31] sage: E = EvenlyDistributedSetsBacktracker(Zmod(61),6) sage: E.an_element() Traceback (most recent call last): ... EmptySetError: no 6-evenly distributed set in Ring of integers modulo 61 - >>> from sage.all import * >>> from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker >>> E = EvenlyDistributedSetsBacktracker(Zmod(Integer(41)),Integer(5)) >>> E.an_element() [0, 1, 13, 38, 31] >>> E = EvenlyDistributedSetsBacktracker(Zmod(Integer(61)),Integer(6)) >>> E.an_element() Traceback (most recent call last): ... EmptySetError: no 6-evenly distributed set in Ring of integers modulo 61 
 - cardinality()[source]¶
- Return the number of evenly distributed sets. - Use with precaution as there can be a lot of such sets and this method might be very long to answer! - EXAMPLES: - sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker sage: E = EvenlyDistributedSetsBacktracker(GF(25,'a'), 4); E 4-evenly distributed sets (up to isomorphism) in Finite Field in a of size 5^2 sage: E.cardinality() 4 sage: E = EvenlyDistributedSetsBacktracker(GF(25,'a'), 4, ....: up_to_isomorphism=False) sage: E.cardinality() 40 - >>> from sage.all import * >>> from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker >>> E = EvenlyDistributedSetsBacktracker(GF(Integer(25),'a'), Integer(4)); E 4-evenly distributed sets (up to isomorphism) in Finite Field in a of size 5^2 >>> E.cardinality() 4 >>> E = EvenlyDistributedSetsBacktracker(GF(Integer(25),'a'), Integer(4), ... up_to_isomorphism=False) >>> E.cardinality() 40 
 - to_difference_family(B, check=True)[source]¶
- Given an evenly distributed set - Bconvert it to a difference family.- As for any \(x\in K^*=H\) we have \(|\Delta B \cap x H^{2(q-1)/(k(k-1))}|=2\) (see - EvenlyDistributedSetsBacktracker), the difference family is produced as \(\{xB:x\in H^{2(q-1)/(k(k-1))}\}\)- This method is useful if you want to obtain the difference family from the output of the iterator. - INPUT: - B– an evenly distributed set
- check– boolean (default:- True); whether to check the result
 - EXAMPLES: - sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker sage: E = EvenlyDistributedSetsBacktracker(Zmod(41),5) sage: B = E.an_element(); B [0, 1, 13, 38, 31] sage: D = E.to_difference_family(B); D [[0, 1, 13, 38, 31], [0, 32, 6, 27, 8]] sage: from sage.combinat.designs.difference_family import is_difference_family sage: is_difference_family(Zmod(41),D,41,5,1) True - >>> from sage.all import * >>> from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker >>> E = EvenlyDistributedSetsBacktracker(Zmod(Integer(41)),Integer(5)) >>> B = E.an_element(); B [0, 1, 13, 38, 31] >>> D = E.to_difference_family(B); D [[0, 1, 13, 38, 31], [0, 32, 6, 27, 8]] >>> from sage.combinat.designs.difference_family import is_difference_family >>> is_difference_family(Zmod(Integer(41)),D,Integer(41),Integer(5),Integer(1)) True - Setting - checkto- Falseis much faster:- sage: timeit("df = E.to_difference_family(B, check=True)") # random 625 loops, best of 3: 117 µs per loop sage: timeit("df = E.to_difference_family(B, check=False)") # random 625 loops, best of 3: 1.83 µs per loop - >>> from sage.all import * >>> timeit("df = E.to_difference_family(B, check=True)") # random 625 loops, best of 3: 117 µs per loop >>> timeit("df = E.to_difference_family(B, check=False)") # random 625 loops, best of 3: 1.83 µs per loop