Skip to content

Commit 0a1a2f3

Browse files
authored
Merge pull request #11 from Aaron-Dwyer/coveringarray
Coveringarray
2 parents 2054d99 + 54b0172 commit 0a1a2f3

File tree

5 files changed

+236
-136
lines changed

5 files changed

+236
-136
lines changed

src/doc/en/reference/combinat/module_list.rst

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ Comprehensive Module List
9292
sage/combinat/designs/resolvable_bibd
9393
sage/combinat/designs/group_divisible_designs
9494
sage/combinat/designs/block_design
95+
sage/combinat/designs/covering_array
9596
sage/combinat/designs/covering_design
9697
sage/combinat/designs/database
9798
sage/combinat/designs/design_catalog
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
r"""
2+
Covering Arrays (CA)
3+
4+
A Covering Array, denoted CA`(N,k,v,t)`, is an `n` by `k` array with
5+
entries from a set of `v` elements with the property that in every
6+
selection of `t` columns, eachrow contains every sequence of
7+
`t`-elements at least once.
8+
9+
An Orthogonal Array, denoted OA`(N,k,v,t)` is a covering array with the
10+
property that each row contains every sequence of `t`-elements exactly
11+
once
12+
13+
REFERENCES:
14+
15+
- [Colb2004]_
16+
17+
- [Sher2006]_
18+
19+
- [Wal2007]_
20+
21+
AUTHORS:
22+
23+
- Aaron Dwyer and brett stevens (2022): initial version
24+
25+
.. TODO::
26+
27+
Implement various construction methods for CAs
28+
29+
Functions
30+
---------
31+
32+
"""
33+
34+
# **********************************************************************
35+
# Copyright (C) 2022 Aaron Dwyer <[email protected]>
36+
#
37+
# This program is free software: you can redistribute it and/or modify
38+
# it under the terms of the GNU General Public License as published by
39+
# the Free Software Foundation, either version 2 of the License, or
40+
# (at your option) any later version.
41+
# https://www.gnu.org/licenses/
42+
# **********************************************************************
43+
44+
from .orthogonal_arrays import OA_relabel, OA_standard_label
45+
CA_relabel = OA_relabel
46+
CA_standard_label = OA_standard_label

src/sage/combinat/designs/design_catalog.py

+2
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,5 @@
119119

120120
lazy_import('sage.combinat.designs.gen_quadrangles_with_spread',
121121
('generalised_quadrangle_with_spread', 'generalised_quadrangle_hermitian_with_ovoid'))
122+
123+
lazy_import('sage.combinat.designs.covering_array', 'CoveringArray')

src/sage/combinat/designs/designs_pyx.pyx

+142-135
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,22 @@ from cysignals.memory cimport sig_malloc, sig_calloc, sig_realloc, sig_free
1515

1616
from sage.misc.unknown import Unknown
1717

18-
def is_covering_array(array,strength=None,symbol_set=None,verbose=False,parameters=False):
18+
#Current Version
19+
#***********************************************************#
20+
21+
def is_covering_array(array, strength=None, levels=None, verbose=False, parameters=False):
1922
r"""
20-
Checks if the input is a covering array with given strength.
23+
Check if the input is a covering array with given strength.
2124
22-
- ``array`` -- The Covering Array to be tested.
25+
- ``array`` -- the Covering Array to be tested.
2326
24-
- ``strength`` (integer) -- The parameter `t` of the covering array,
25-
such thatin any selection of `t` columns of the array, every `t`
26-
-tuple appearsat least once. If set to None then all t>0 are
27-
tested to and themaximal strength is used.
27+
- ``strength`` (integer) -- the parameter `t` of the covering array,
28+
such that in any selection of `t` columns of the array, every `t`
29+
-tuple appears at least once. If set to None then all t > 0 are
30+
tested to and the maximal strength is used.
2831
29-
- ``symbol_set`` -- The collection of symbols that is used in
30-
``array``. If set to None, then a symbol set will be assumed by
31-
checking for each unique entry in the given ``array``.
32+
- ``levels`` -- the number of symbols that appear in ``array``.
33+
If set to None, then each unique entry in ``array`` is counted.
3234
3335
- ``verbose`` (boolean) -- whether to display some information about
3436
the covering array.
@@ -38,171 +40,176 @@ def is_covering_array(array,strength=None,symbol_set=None,verbose=False,paramete
3840
pair ``(boolean_answer,(N,t,k,v))``.
3941
4042
EXAMPLES::
43+
4144
sage: from sage.combinat.designs.designs_pyx import is_covering_array
42-
sage: C = ((1, 1, 1, 0),
43-
....: (1, 1, 0, 0),
44-
....: (0, 0, 0))
45+
sage: C = [[1, 1, 1, 0],
46+
....: [1, 1, 0, 0],
47+
....: [0, 0, 0]]
4548
sage: is_covering_array(C)
4649
Traceback (most recent call last):
4750
...
4851
ValueError: Not all rows are the same length, row 2 is not the same length as row 0
4952
50-
sage: C = (('a', 'a', 'a', 'b'),
51-
....: ('a', 'a', 'b', 'a'),
52-
....: ('a', 'b', 'a', 'a'),
53-
....: ('b', 'a', 'a', 'a'),
54-
....: ('b', 'b', 'b', 'b'))
55-
sage: is_covering_array(C,verbose=True)
56-
A 5 by 4 Covering Array with strength 2 with entries from ['a', 'b']
57-
True
58-
sage: is_covering_array(C,strength=3,verbose=True)
59-
A 5 by 4 Covering Array with strength 0 with entries from ['a', 'b']
60-
False
53+
sage: C = [[0, 1, 1],
54+
....: [1, 1, 0],
55+
....: [1, 0, 1],
56+
....: [0, 0, 0,]]
57+
sage: is_covering_array(C,strength=4)
58+
Traceback (most recent call last):
59+
...
60+
ValueError: Strength must be equal or less than number of columns
6161
62-
sage: from sage.combinat.designs.designs_pyx import is_covering_array
63-
sage: C = ((0, 1, 0),
64-
....: (1, 1, 0),
65-
....: (1, 0, 0))
62+
sage: C = [[0, 1, 1],
63+
....: [1, 1, 1],
64+
....: [1, 0, 1]]
6665
sage: is_covering_array(C,verbose=True)
67-
A 3 by 3 Covering Array with strength 0 with entries from [0, 1]
66+
A 3 by 3 Covering Array with strength 0 with entries from a symbol set of size 2
6867
True
6968
70-
sage: C = ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
71-
....: (0, 0, 0, 0, 1, 1, 1, 1, 1, 1),
72-
....: (0, 1, 1, 1, 0, 0, 0, 1, 1, 1),
73-
....: (1, 0, 1, 1, 0, 1, 1, 0, 0, 1),
74-
....: (1, 1, 0, 1, 1, 0, 1, 0, 1, 0),
75-
....: (1, 1, 1, 0, 1, 1, 0, 1, 2, 0))
76-
sage: is_covering_array(C,symbol_set=(0,1))
69+
sage: C = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
70+
....: [0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
71+
....: [0, 1, 1, 1, 0, 0, 0, 1, 1, 1],
72+
....: [1, 0, 1, 1, 0, 1, 1, 0, 0, 1],
73+
....: [1, 1, 0, 1, 1, 0, 1, 0, 1, 0],
74+
....: [1, 1, 1, 0, 1, 1, 0, 1, 2, 0]]
75+
sage: is_covering_array(C,levels=2)
7776
Traceback (most recent call last):
7877
...
79-
ValueError: 2 appears in the array but not in the given symbol set
80-
81-
sage: C = ((1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2),
82-
....: (1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2),
83-
....: (1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0),
84-
....: (0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1),
85-
....: (2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2),
86-
....: (1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2),
87-
....: (1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1),
88-
....: (2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2),
89-
....: (1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0),
90-
....: (0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2),
91-
....: (1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0),
92-
....: (0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0),
93-
....: (0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1),
94-
....: (2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1),
95-
....: (2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1),
96-
....: (2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0),
97-
....: (0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2),
98-
....: (1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1),
99-
....: (2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1),
100-
....: (2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2),
101-
....: (1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1),
102-
....: (2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0),
103-
....: (0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1),
104-
....: (2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0),
105-
....: (0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0),
106-
....: (0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2),
107-
....: (1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2),
108-
....: (1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0),
109-
....: (0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0),
110-
....: (0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1),
111-
....: (2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0),
112-
....: (0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1),
113-
....: (2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2),
114-
....: (1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1),
115-
....: (2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1),
116-
....: (2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2),
117-
....: (1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0),
118-
....: (0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1),
119-
....: (2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1),
120-
....: (2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1),
121-
....: (2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0),
122-
....: (0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0),
123-
....: (0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2),
124-
....: (1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0),
125-
....: (0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2),
126-
....: (1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1),
127-
....: (2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2),
128-
....: (1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2),
129-
....: (1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1),
130-
....: (2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0),
131-
....: (0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2),
132-
....: (1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2),
133-
....: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
78+
ValueError: Array should contain integer symbols from 0 to 1
79+
80+
sage: C = [[1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2],
81+
....: [1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2],
82+
....: [1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0],
83+
....: [0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1],
84+
....: [2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2],
85+
....: [1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2],
86+
....: [1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1],
87+
....: [2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2],
88+
....: [1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0],
89+
....: [0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2],
90+
....: [1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0],
91+
....: [0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0],
92+
....: [0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1],
93+
....: [2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1],
94+
....: [2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1],
95+
....: [2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0],
96+
....: [0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2],
97+
....: [1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1],
98+
....: [2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1],
99+
....: [2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2],
100+
....: [1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1],
101+
....: [2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0],
102+
....: [0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1],
103+
....: [2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0],
104+
....: [0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0],
105+
....: [0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2],
106+
....: [1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2],
107+
....: [1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0],
108+
....: [0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0],
109+
....: [0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1],
110+
....: [2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0],
111+
....: [0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1],
112+
....: [2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2],
113+
....: [1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1],
114+
....: [2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1],
115+
....: [2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2],
116+
....: [1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0],
117+
....: [0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1],
118+
....: [2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1],
119+
....: [2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1],
120+
....: [2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0],
121+
....: [0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0],
122+
....: [0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2],
123+
....: [1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0],
124+
....: [0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2],
125+
....: [1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1],
126+
....: [2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2],
127+
....: [1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2],
128+
....: [1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1],
129+
....: [2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0],
130+
....: [0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2],
131+
....: [1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2],
132+
....: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
134133
sage: is_covering_array(C,parameters=True)
135134
(True, (53, 3, 13, 3))
136135
136+
sage: C = [[1, 0, 1, 1, 2, 0, 2, 2],
137+
....: [2, 1, 0, 1, 1, 2, 0, 2],
138+
....: [2, 2, 1, 0, 1, 1, 2, 0],
139+
....: [0, 2, 2, 1, 0, 1, 1, 2],
140+
....: [2, 0, 2, 2, 1, 0, 1, 1],
141+
....: [1, 2, 0, 2, 2, 1, 0, 1],
142+
....: [1, 1, 2, 0, 2, 2, 1, 0],
143+
....: [0, 1, 1, 2, 0, 2, 2, 1]]
144+
sage: is_covering_array(C,strength=2,parameters=True)
145+
(False, (8, 0, 8, 3))
146+
137147
"""
138148
from itertools import product, combinations
139149

140-
number_rows=len(array)
141-
number_columns=len(array[0])
142-
143-
for row in range(number_rows):
144-
if len(array[row]) != number_columns:
145-
raise ValueError("Not all rows are the same length, row {} is not the same length as row 0".format(row))
146-
147-
if symbol_set is None:
148-
symbol_set = list({x for l in array for x in l})
149-
symbol_set.sort()
150+
if levels is None:
151+
symbol_list = list({x for l in array for x in l})
152+
levels = len(symbol_list)
150153
else:
151-
for l in array:
152-
for x in l:
153-
if x not in symbol_set:
154-
raise ValueError("{} appears in the array but not in the given symbol set".format(x))
154+
symbol_list = [num for num in range(levels)]
155+
156+
number_rows = len(array)
157+
number_columns = len(array[0])
155158

159+
# Set wstrength to be the current t value to be checked
156160
if strength is None:
157161
wstrength = 1
158162
else:
163+
if strength > number_columns:
164+
raise ValueError("Strength must be equal or less than number of columns")
159165
wstrength = strength
160-
finished = False
161166

162-
# if no strength inputted, tries increasing values for t until one
163-
# does not work. If strength is inputted ends after one check
167+
for row in array:
168+
if len(row) != number_columns:
169+
raise ValueError("Not all rows are the same length, row {} is not the same length as row 0".format(array.index(row)))
170+
else:
171+
for entry in row:
172+
if int(entry) != entry or entry < -1 or entry >= levels:
173+
raise ValueError("Array should contain integer symbols from 0 to {}".format(levels-1))
174+
175+
finished = False
176+
result = True
177+
# If no strength inputted, try increasing values for t until one
178+
# does not work. If strength is inputted end after one check
164179
while finished is False:
165-
# Iterates over every possible selections of t columns, and
180+
# Iterate over every possible selections of t columns, and
166181
# count the t-tuples appearing in each selection
167-
for comb in combinations(range(number_columns),wstrength):
168-
tuple_dictionary = {item: 0 for item in product(symbol_set, repeat=wstrength)}
182+
for comb in combinations(range(number_columns), wstrength):
183+
tuple_dictionary = {item: 0 for item in product(symbol_list, repeat=wstrength)}
169184
for row in array:
170-
tuple_dictionary[tuple([row[ti] for ti in comb])]+=1
171-
172-
# Checks if any t-tuple is not covered in current columns
185+
tuple_dictionary[tuple([row[ti] for ti in comb])] += 1
186+
# Check if any t-tuple is not covered in current columns
173187
if 0 in tuple_dictionary.values():
174-
if strength != None:
175-
wstrength = 0
176-
result = False
188+
if strength is None:
189+
wstrength -= 1
177190
finished = True
178191
break
179192
else:
180-
wstrength -=1
193+
wstrength = 0
194+
result = False
181195
finished = True
182196
break
183197

184-
else:
185-
if strength != None:
186-
result = True
187-
finished = True
188-
break
189198
if finished is False:
190-
wstrength +=1
199+
if strength is None and wstrength < number_columns:
200+
wstrength += 1
201+
else:
202+
finished = True
203+
break
191204

192205
if verbose:
193-
print('A {} by {} Covering Array with strength {} with entries from {}'.format(number_rows,number_columns,wstrength,symbol_set))
194-
195-
if strength is None:
196-
if parameters:
197-
return (True,(number_rows,wstrength,number_columns,len(symbol_set)))
198-
else:
199-
return True
206+
print('A {} by {} Covering Array with strength {} with entries from a symbol set of size {}'.format(number_rows,number_columns,wstrength,levels))
200207

208+
if parameters:
209+
return (result, (number_rows, wstrength, number_columns, levels))
201210
else:
202-
if parameters:
203-
return (result,(number_rows,wstrength,number_columns,len(symbol_set)))
204-
else:
205-
return result
211+
return result
212+
206213

207214
def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology="OA"):
208215
r"""

0 commit comments

Comments
 (0)