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
¶ Bases:
object
Set of evenly distributed subsets in finite fields.
Definition: Letbe a finite field of cardinality
and
an integer so that
divides
. Let
be the multiplicative group of invertible elements in
. A
-evenly distributed set in
is a set
of
elements of
so that the
differences
hit each coset modulo
exactly twice.
Evenly distributed sets were introduced by Wilson [Wi72] (see also [BJL99-1], Chapter VII.6). He proved that for any
, and for any prime power
large enough such that
divides
there exists a
-evenly distributed set in the field of cardinality
. This existence result based on a counting argument (using Dirichlet theorem) does not provide a simple method to generate them.
From a
-evenly distributed set, it is straightforward to build a
-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 particularradical_difference_family()
from the moduledifference_family
).By default, this backtracker only considers evenly distributed sets up to affine automorphisms, i.e.
is considered equivalent to
for any invertible element
and any element
in the field
. Note that the set of differences is just multiplicatively translated by
as
, and so that
is an evenly distributed set if and only if
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 cardinalityk
– a positive integer such thatdivides
up_to_isomorphism
- (boolean, defaultTrue
) whether only consider evenly distributed sets up to automorphisms of the field of the form. If set to
False
then the iteration is over all evenly distributed sets that contain0
and1
.check
– boolean (default isFalse
). Whether you want to check intermediate steps of the iterator. This is mainly intended for debugging purpose. Setting it toTrue
will 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]
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]]
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]
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
Note that by definition, the number of evenly distributed sets up to isomorphisms is at most
times smaller than without isomorphisms. But it might not be exactly
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]
-
an_element
()¶ 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
-
cardinality
()¶ 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) sage: 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
-
to_difference_family
(B, check=True)¶ Given an evenly distributed set
B
convert it to a difference family.As for any
we have
(see
EvenlyDistributedSetsBacktracker
), the difference family is produced asThis method is useful if you want to obtain the difference family from the output of the iterator.
INPUT:
B
– an evenly distributed setcheck
– (boolean, defaultTrue
) 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
Setting
check
toFalse
is 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