Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strength 2 Covering Array constructions #37372

Merged
merged 12 commits into from
Aug 10, 2024
22 changes: 16 additions & 6 deletions src/doc/en/reference/references/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1812,8 +1812,8 @@ REFERENCES:
With an appendix by Ernst Kani.
Canad. Math. Bull. 48 (2005), no. 1, 16--31.

.. [Colb2004] C.J. Colbourn. Combinatorial aspects of covering arrays.
Matematiche (Catania) 59 (2004), pp. 125172.
.. [Colb2004] C.J. Colbourn. *Combinatorial aspects of covering arrays*.
Matematiche (Catania) 59 (2004), pp. 125-172.

.. [Col2004] Pierre Colmez, Invariant `\mathcal{L}` et derivees de
valeurs propres de Frobenius, preprint, 2004.
Expand Down Expand Up @@ -3746,6 +3746,10 @@ REFERENCES:
.. [Kas2018] András Kaszanyitzky. *The GraftalLace Cellular Automata*.
Preprint, :arxiv:`1805.11532`.

.. [Kat1973] G. Katona. *Two applications (for search theory and truth
functions) of Sperner type theorems*. Periodica Math.,
3:19-26, 1973.

.. [Kat1991] Nicholas M. Katz, *Exponential sums and differential equations*,
Princeton University Press, Princeton NJ, 1991.

Expand Down Expand Up @@ -4050,6 +4054,9 @@ REFERENCES:
.. [KS] Sheldon Katz and Stein Arild Stromme, "Schubert",
A Maple package for intersection theory and enumerative geometry.

.. [KS1973] D. Kleitman and J. Spencer. *Families of k-independent sets*.
Discrete Math, 6:255-262, 1973.

.. [KS1998] Maximilian Kreuzer and Harald Skarke, *Classification of
Reflexive Polyhedra in Three Dimensions*,
:arxiv:`hep-th/9805190`
Expand Down Expand Up @@ -5082,6 +5089,9 @@ REFERENCES:
:doi:`10.1007/s00453-006-1225-y`,
http://www.cs.uoi.gr/~stavros/C-Papers/C-2004-SODA.pdf

.. [Nur2004] K. Nurmela. *Upper bounds for covering arrays by tabu search*.
Discrete Applied Math., 138 (2004), 143-152.

.. [NWS2002] Newman, M.E.J., Watts, D.J. and Strogatz, S.H. *Random
graph models of social networks*. Proc. Nat. Acad. Sci. USA
99:1 (2002), 2566-2572. :doi:`10.1073/pnas.012582999`
Expand Down Expand Up @@ -5853,8 +5863,8 @@ REFERENCES:

.. [SloaHada] \N.J.A. Sloane's Library of Hadamard Matrices, at https://neilsloane.com/hadamard/

.. [SMC2006] \G.B. Sherwood, S.S Martirosyan, and C.J. Colbourn, "Covering
arrays of higher strength from permutation vectors". J. Combin.
.. [SMC2006] \G.B. Sherwood, S.S Martirosyan, and C.J. Colbourn, *Covering
arrays of higher strength from permutation vectors*. J. Combin.
Designs, 14 (2006) pp. 202-213.

.. [SMMK2013] \T. Suzaki, K. Minematsu, S. Morioka, and E. Kobayashi,
Expand Down Expand Up @@ -6547,8 +6557,8 @@ REFERENCES:
.. [Wat2010] Watkins, David S. Fundamentals of Matrix Computations,
Third Edition. Wiley, Hoboken, New Jersey, 2010.

.. [WC2007] \R.A. Walker II, and C.J. Colbourn, "Perfect Hash Families:
Constructions and Existence". J. Math. Crypt. 1 (2007),
.. [WC2007] \R.A. Walker II, and C.J. Colbourn, *Perfect Hash Families:
Constructions and Existence*. J. Math. Crypt. 1 (2007),
pp.125-150

.. [Web2007] James Webb. *Game theory: decisions, interaction and
Expand Down
224 changes: 221 additions & 3 deletions src/sage/combinat/designs/covering_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@

.. csv-table::
:class: contentstable
:widths: 30, 70
:widths: 50, 50
:delim: |

:meth:`~sage.combinat.designs.designs_pyx.is_covering_array` | Check that an input list of lists is a `CA(N;t,k,v)`.
:meth:`~sage.combinat.designs.covering_array.CA_relabel` | Return a relabelled version of the CA.
:meth:`~sage.combinat.designs.covering_array.CA_standard_label` | Return a version of the CA relabelled to symbols `(0,\dots,n-1)`.
:meth:`~sage.combinat.designs.covering_array.CA_relabel` | Return a relabelled version of the `CA`.
:meth:`~sage.combinat.designs.covering_array.CA_standard_label` | Return a version of the `CA` relabelled to symbols `(0,\dots,n-1)`.
:meth:`~sage.combinat.designs.covering_array.truncate_columns` | Return an array with `k` columns from a larger one.
:meth:`~sage.combinat.designs.covering_array.Kleitman_Spencer_Katona` | Return a `CA(N; 2, k, 2)` using N as input.
:meth:`~sage.combinat.designs.covering_array.column_Kleitman_Spencer_Katona` | Return a `CA(N; 2, k, 2)` using k as input.
:meth:`~sage.combinat.designs.covering_array.database_check` | Check if CA can be made from the database of combinatorial designs.
:meth:`~sage.combinat.designs.covering_array.covering_array` | Return a `CA` with given parameters.

REFERENCES:

Expand Down Expand Up @@ -49,3 +54,216 @@
from .orthogonal_arrays import OA_relabel, OA_standard_label
CA_relabel = OA_relabel
CA_standard_label = OA_standard_label


def truncate_columns(array, k):
r"""
Return a covering array with `k` columns, obtained by removing excess
columns from a larger covering array.

INPUT:

- ``array`` -- the array to be truncated.

- ``k`` -- the number of columns desired. Must be less than the
number of columns in ``array``.

EXAMPLES::

sage: from sage.combinat.designs.designs_pyx import is_covering_array
sage: from sage.combinat.designs.covering_array import truncate_columns
sage: from sage.combinat.designs.database import ca_11_2_5_3
sage: C = ca_11_2_5_3()
sage: D = truncate_columns(C,7)
Traceback (most recent call last):
...
ValueError: array only has 5 columns
sage: E = truncate_columns(C,4)
sage: is_covering_array(E,parameters=True)
(True, (11, 2, 4, 3))

"""
oldk = len(array[0])

if oldk == k:
return array

elif oldk < k:
aadwyer marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError("array only has {} columns".format(oldk))

else:
return [row[:k] for row in array]


def Kleitman_Spencer_Katona(N):
r"""
Return a `CA(N; 2, k, 2)` where `k = \binom {N-1}{\lceil N/2 \rceil}`.

INPUT:

- ``N`` -- the number of rows in the array, must be an integer greater
than 3 since any smaller would not produce enough columns for a
strength 2 array.

This construction is referenced in [Colb2004]_ from [KS1973]_ and [Kat1973]_

**Construction**

Take all distinct binary `N`-tuples of weight `N/2` that have a 0
in the first position and place them as columns in an array.

EXAMPLES::

sage: from sage.combinat.designs.covering_array import Kleitman_Spencer_Katona
sage: from sage.combinat.designs.designs_pyx import is_covering_array
sage: C = Kleitman_Spencer_Katona(2)
Traceback (most recent call last):
...
ValueError: N must be greater than 3
sage: C = Kleitman_Spencer_Katona(5)
sage: is_covering_array(C,parameters=True)
(True, (5, 2, 4, 2))

"""
from itertools import combinations
from sage.arith.misc import integer_ceil
if N < 4:
raise ValueError("N must be greater than 3")

col_list = []
for p in combinations(range(N-1), integer_ceil(N/2)):
S = [0]*N
for i in p:
S[i] = 1
col_list.append(S)
return [[col_list[j][i] for j in range(len(col_list))] for i in range(N)]


def column_Kleitman_Spencer_Katona(k):
r"""
Return a covering array with `k` columns using the Kleitman-Spencer-Katona
method.

See :func:`~sage.combinat.designs.covering_array.Kleitman_Spencer_Katona`

INPUT:

- ``k`` -- the number of columns in the array, must be an integer
greater than 3 since any smaller is a trivial array for strength 2.

EXAMPLES::

sage: from sage.combinat.designs.designs_pyx import is_covering_array
sage: from sage.combinat.designs.covering_array import column_Kleitman_Spencer_Katona
sage: C = column_Kleitman_Spencer_Katona(20)
sage: is_covering_array(C,parameters=True)
(True, (8, 2, 20, 2))
sage: column_Kleitman_Spencer_Katona(25000)
Traceback (most recent call last):
...
NotImplementedError: not implemented for k > 24310

"""
kdict = [(3, 4), (4, 5), (10, 6), (15, 7), (35, 8), (56, 9),
(126, 10), (210, 11), (462, 12), (792, 13), (1716, 14),
(3003, 15), (6435, 16), (11440, 17), (24310, 18)]

if k > kdict[-1][0]:
raise NotImplementedError("not implemented for k > {}".format(kdict[-1][0]))

for (ki, N) in kdict:
if k <= ki:
return truncate_columns(Kleitman_Spencer_Katona(N), k)


def database_check(number_columns, strength, levels):
r"""
Check if the database can be used to build a CA with the given parameters.
If so return the CA, if not return False.

INPUT:

- ``strength`` (integer) -- the parameter `t` of the covering array,
such that in any selection of `t` columns of the array, every
`t`-tuple appears at least once.

- ``levels`` (integer) -- the parameter `v` which is the number of
unique symbols that appear in the covering array.

- ``number_columns`` (integer) -- the number of columns desired for
the covering array.

EXAMPLES::

sage: from sage.combinat.designs.designs_pyx import is_covering_array
sage: from sage.combinat.designs.covering_array import database_check
sage: C = database_check(6, 2, 3)
sage: is_covering_array(C, parameters=True)
(True, (12, 2, 6, 3))
sage: database_check(6, 3, 3)
False

"""
import sage.combinat.designs.database as DB

if (strength, levels) in DB.CA_constructions:
for i in DB.CA_constructions[(strength, levels)]:
if number_columns <= i[1]:
CA = "ca_{}_{}_{}_{}".format(i[0], strength, i[1], levels)
f = getattr(DB, CA)
return truncate_columns(f(), number_columns)
return False

Check warning on line 215 in src/sage/combinat/designs/covering_array.py

View check run for this annotation

Codecov / codecov/patch

src/sage/combinat/designs/covering_array.py#L215

Added line #L215 was not covered by tests
else:
return False


def covering_array(strength, number_columns, levels):
r"""
Build a `CA(N; t, k, v)` using direct constructions, where `N` is the
smallest size known.

INPUT:

- ``strength`` (integer) -- the parameter `t` of the covering array,
such that in any selection of `t` columns of the array, every
`t`-tuple appears at least once.

- ``levels`` (integer) -- the parameter `v` which is the number of
unique symbols that appear in the covering array.

- ``number_columns`` (integer) -- the number of columns desired for
the covering array.

EXAMPLES::

sage: from sage.combinat.designs.designs_pyx import is_covering_array
sage: from sage.combinat.designs.covering_array import covering_array
sage: C1 = covering_array(2, 7, 3)
sage: is_covering_array(C1,parameters=True)
(True, (12, 2, 7, 3))
sage: C2 = covering_array(2, 11, 2)
sage: is_covering_array(C2,parameters=True)
(True, (7, 2, 11, 2))
sage: C3 = covering_array(2, 8, 7)
sage: is_covering_array(C3,parameters=True)
(True, (49, 2, 8, 7))
sage: C4 = covering_array(2, 50, 7)
No direct construction known and/or implemented for a CA(N; 2, 50, 7)

"""
from sage.combinat.designs.orthogonal_arrays import orthogonal_array

if levels == 2 and strength == 2:
return column_Kleitman_Spencer_Katona(number_columns)

in_database = database_check(number_columns, strength, levels)
if in_database:
return in_database

aadwyer marked this conversation as resolved.
Show resolved Hide resolved
if orthogonal_array(number_columns, levels, strength, existence=True) == True:

Check failure on line 263 in src/sage/combinat/designs/covering_array.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (E712)

sage/combinat/designs/covering_array.py:263:8: E712 Avoid equality comparisons to `True`; use `if ...:` for truth checks
aadwyer marked this conversation as resolved.
Show resolved Hide resolved
return orthogonal_array(number_columns, levels, strength)

else:
print("No direct construction known and/or implemented for a CA(N; {}, {}, {})".format(
strength, number_columns, levels))
return
Loading
Loading