Skip to content

Commit 54b0172

Browse files
committed
For efficiency made is_covering_array only consider the arrays where
the symbols are 0,..,v-1. To allow for easy transitions between this "standard symbol set" and others, edits were made to the orthogonal arrays file to include functions that map symbol sets of arrays and these functions are imported to the file for covering array functions Because the covering array file was added back, documentation and links to it were added back as well
1 parent 21dcab5 commit 54b0172

File tree

5 files changed

+200
-89
lines changed

5 files changed

+200
-89
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

+106-88
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ def is_covering_array(array, strength=None, levels=None, verbose=False, paramete
2222
r"""
2323
Check if the input is a covering array with given strength.
2424
25-
- ``array`` -- The Covering Array to be tested.
25+
- ``array`` -- the Covering Array to be tested.
2626
27-
- ``strength`` (integer) -- The parameter `t` of the covering array,
27+
- ``strength`` (integer) -- the parameter `t` of the covering array,
2828
such that in any selection of `t` columns of the array, every `t`
2929
-tuple appears at least once. If set to None then all t > 0 are
3030
tested to and the maximal strength is used.
3131
32-
- ``levels`` -- The number of symbols that appear in ``array``.
32+
- ``levels`` -- the number of symbols that appear in ``array``.
3333
If set to None, then each unique entry in ``array`` is counted.
3434
3535
- ``verbose`` (boolean) -- whether to display some information about
@@ -42,98 +42,116 @@ def is_covering_array(array, strength=None, levels=None, verbose=False, paramete
4242
EXAMPLES::
4343
4444
sage: from sage.combinat.designs.designs_pyx import is_covering_array
45-
sage: C = ((1, 1, 1, 0),
46-
....: (1, 1, 0, 0),
47-
....: (0, 0, 0))
45+
sage: C = [[1, 1, 1, 0],
46+
....: [1, 1, 0, 0],
47+
....: [0, 0, 0]]
4848
sage: is_covering_array(C)
4949
Traceback (most recent call last):
5050
...
5151
ValueError: Not all rows are the same length, row 2 is not the same length as row 0
5252
53-
sage: from sage.combinat.designs.designs_pyx import is_covering_array
54-
sage: C = ((0, 1, 0),
55-
....: (1, 1, 0),
56-
....: (1, 0, 0))
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
61+
62+
sage: C = [[0, 1, 1],
63+
....: [1, 1, 1],
64+
....: [1, 0, 1]]
5765
sage: is_covering_array(C,verbose=True)
58-
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
5967
True
6068
61-
sage: C = ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
62-
....: (0, 0, 0, 0, 1, 1, 1, 1, 1, 1),
63-
....: (0, 1, 1, 1, 0, 0, 0, 1, 1, 1),
64-
....: (1, 0, 1, 1, 0, 1, 1, 0, 0, 1),
65-
....: (1, 1, 0, 1, 1, 0, 1, 0, 1, 0),
66-
....: (1, 1, 1, 0, 1, 1, 0, 1, 2, 0))
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]]
6775
sage: is_covering_array(C,levels=2)
6876
Traceback (most recent call last):
6977
...
70-
ValueError: array should contain integer symbols from 0 to 1
71-
72-
sage: C = ((1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2),
73-
....: (1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2),
74-
....: (1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0),
75-
....: (0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1),
76-
....: (2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2),
77-
....: (1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2),
78-
....: (1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1),
79-
....: (2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2),
80-
....: (1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0),
81-
....: (0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2),
82-
....: (1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0),
83-
....: (0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0),
84-
....: (0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1),
85-
....: (2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1),
86-
....: (2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1),
87-
....: (2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0),
88-
....: (0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2),
89-
....: (1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1),
90-
....: (2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1),
91-
....: (2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2),
92-
....: (1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1),
93-
....: (2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0),
94-
....: (0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1),
95-
....: (2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0),
96-
....: (0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0),
97-
....: (0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2),
98-
....: (1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2),
99-
....: (1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0),
100-
....: (0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0),
101-
....: (0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1),
102-
....: (2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0),
103-
....: (0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1),
104-
....: (2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2),
105-
....: (1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1),
106-
....: (2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1),
107-
....: (2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2),
108-
....: (1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0),
109-
....: (0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1),
110-
....: (2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1),
111-
....: (2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1),
112-
....: (2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0),
113-
....: (0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0),
114-
....: (0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2),
115-
....: (1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0),
116-
....: (0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2),
117-
....: (1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1),
118-
....: (2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2),
119-
....: (1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2),
120-
....: (1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1),
121-
....: (2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0),
122-
....: (0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2),
123-
....: (1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2),
124-
....: (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]]
125133
sage: is_covering_array(C,parameters=True)
126134
(True, (53, 3, 13, 3))
127135
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+
128147
"""
129148
from itertools import product, combinations
130-
from sage.rings.integer import Integer
131149

132150
if levels is None:
133-
symbol_set = {x for l in array for x in l}
134-
levels = len(symbol_set)
151+
symbol_list = list({x for l in array for x in l})
152+
levels = len(symbol_list)
135153
else:
136-
symbol_set = {num for num in range(levels)}
154+
symbol_list = [num for num in range(levels)]
137155

138156
number_rows = len(array)
139157
number_columns = len(array[0])
@@ -143,28 +161,28 @@ def is_covering_array(array, strength=None, levels=None, verbose=False, paramete
143161
wstrength = 1
144162
else:
145163
if strength > number_columns:
146-
raise ValueError("strength must be equal or less than number of columns")
164+
raise ValueError("Strength must be equal or less than number of columns")
147165
wstrength = strength
148166

149167
for row in array:
150168
if len(row) != number_columns:
151169
raise ValueError("Not all rows are the same length, row {} is not the same length as row 0".format(array.index(row)))
152170
else:
153171
for entry in row:
154-
if type(entry) != Integer or entry < -1 or entry >= levels:
155-
raise ValueError("array should contain integer symbols from 0 to {}".format(levels-1))
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))
156174

157175
finished = False
176+
result = True
158177
# If no strength inputted, try increasing values for t until one
159178
# does not work. If strength is inputted end after one check
160179
while finished is False:
161180
# Iterate over every possible selections of t columns, and
162181
# count the t-tuples appearing in each selection
163182
for comb in combinations(range(number_columns), wstrength):
164-
tuple_dictionary = {item: 0 for item in product(symbol_set, repeat=wstrength)}
183+
tuple_dictionary = {item: 0 for item in product(symbol_list, repeat=wstrength)}
165184
for row in array:
166185
tuple_dictionary[tuple([row[ti] for ti in comb])] += 1
167-
168186
# Check if any t-tuple is not covered in current columns
169187
if 0 in tuple_dictionary.values():
170188
if strength is None:
@@ -177,15 +195,15 @@ def is_covering_array(array, strength=None, levels=None, verbose=False, paramete
177195
finished = True
178196
break
179197

180-
if strength is None and finished is False and wstrength < number_columns:
181-
wstrength += 1
182-
else:
183-
result = True
184-
finished = True
185-
break
198+
if finished is False:
199+
if strength is None and wstrength < number_columns:
200+
wstrength += 1
201+
else:
202+
finished = True
203+
break
186204

187205
if verbose:
188-
print('A {} by {} Covering Array with strength {} with entries from {}'.format(number_rows,number_columns,wstrength,symbol_set))
206+
print('A {} by {} Covering Array with strength {} with entries from a symbol set of size {}'.format(number_rows,number_columns,wstrength,levels))
189207

190208
if parameters:
191209
return (result, (number_rows, wstrength, number_columns, levels))

0 commit comments

Comments
 (0)