Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/designs/covering_design.py
8818 views
1
r"""
2
Covering designs: coverings of `t`-element subsets of a `v`-set by `k`-sets
3
4
A `(v,k,t)` covering design `C` is an incidence structure consisting of a
5
set of points `P` of order `v`, and a set of blocks `B`, where each
6
block contains `k` points of `P`. Every `t`-element subset of `P`
7
must be contained in at least one block.
8
9
If every `t`-set is contained in exactly one block of `C`, then we
10
have a block design. Following the block design implementation, the
11
standard representation of a covering design uses `P = [0,1,..., v-1]`.
12
13
In addition to the parameters and incidence structure for a covering
14
design from this database, we include extra information:
15
16
* Best known lower bound on the size of a `(v,k,t)`-covering design
17
* Name of the person(s) who produced the design
18
* Method of construction used
19
* Date when the design was added to the database
20
21
REFERENCES:
22
23
.. [1] La Jolla Covering Repository,
24
http://www.ccrwest.org/cover.html
25
26
.. [2] Coverings,
27
Daniel Gordon and Douglas Stinson,
28
http://www.ccrwest.org/gordon/hcd.pdf
29
from the Handbook of Combinatorial Designs
30
31
AUTHORS:
32
33
-- Daniel M. Gordon (2008-12-22): initial version
34
35
Classes and methods
36
-------------------
37
"""
38
39
#*****************************************************************************
40
# Copyright (C) 2008 Daniel M. Gordon <[email protected]>
41
#
42
# Distributed under the terms of the GNU General Public License (GPL)
43
# http://www.gnu.org/licenses/
44
#*****************************************************************************
45
46
from sage.misc.sage_eval import sage_eval
47
from sage.structure.sage_object import SageObject
48
from sage.rings.rational import Rational
49
from sage.rings.arith import binomial
50
from sage.combinat.combination import Combinations
51
from sage.combinat.designs.incidence_structures import IncidenceStructure
52
53
###################### covering design functions ##############################
54
55
56
def schonheim(v,k,t):
57
r"""
58
Schonheim lower bound for size of covering design
59
60
INPUT:
61
62
- ``v`` -- integer, size of point set
63
- ``k`` -- integer, cardinality of each block
64
- ``t`` -- integer, cardinality of sets being covered
65
66
OUTPUT:
67
68
The Schonheim lower bound for such a covering design's size:
69
`C(v,k,t) \leq \lceil(\frac{v}{k} \lceil \frac{v-1}{k-1} \cdots \lceil \frac{v-t+1}{k-t+1} \rceil \cdots \rceil \rceil`
70
71
EXAMPLES::
72
73
sage: from sage.combinat.designs.covering_design import schonheim
74
sage: schonheim(10,3,2)
75
17
76
sage: schonheim(32,16,8)
77
930
78
"""
79
bound = 1
80
for i in range(t-1,-1,-1):
81
bound = Rational((bound*(v-i),k-i)).ceil()
82
83
return bound
84
85
86
def trivial_covering_design(v,k,t):
87
r"""
88
Construct a trivial covering design.
89
90
INPUT:
91
92
- ``v`` -- integer, size of point set
93
- ``k`` -- integer, cardinality of each block
94
- ``t`` -- integer, cardinality of sets being covered
95
96
OUTPUT:
97
98
`(v,k,t)` covering design
99
100
EXAMPLE::
101
102
sage: C = trivial_covering_design(8,3,1)
103
sage: print C
104
C(8,3,1) = 3
105
Method: Trivial
106
0 1 2
107
0 6 7
108
3 4 5
109
sage: C = trivial_covering_design(5,3,2)
110
sage: print C
111
4 <= C(5,3,2) <= 10
112
Method: Trivial
113
0 1 2
114
0 1 3
115
0 1 4
116
0 2 3
117
0 2 4
118
0 3 4
119
1 2 3
120
1 2 4
121
1 3 4
122
2 3 4
123
124
NOTES:
125
126
Cases are:
127
128
* `t=0`: This could be empty, but it's a useful convention to have
129
one block (which is empty if $k=0$).
130
131
* `t=1` : This contains `\lceil v/k \rceil` blocks:
132
`[0,...,k-1],[k,...,2k-1],...`. The last block wraps around if
133
`k` does not divide `v`.
134
135
* anything else: Just use every `k`-subset of `[0,1,...,v-1]`.
136
137
"""
138
if t==0: #single block [0,...,k-1]
139
blk=[]
140
for i in range(k):
141
blk.append(i)
142
return CoveringDesign(v,k,t,1,range(v),[blk],1,"Trivial")
143
144
if t==1: #blocks [0,...,k-1],[k,...,2k-1],...
145
size = Rational((v,k)).ceil()
146
blocks=[]
147
for i in range(size-1):
148
blk=[]
149
for j in range(i*k,(i+1)*k):
150
blk.append(j)
151
blocks.append(blk)
152
153
blk=[] # last block: if k does not divide v, wrap around
154
for j in range((size-1)*k,v):
155
blk.append(j)
156
for j in range(k-len(blk)):
157
blk.append(j)
158
blk.sort()
159
blocks.append(blk)
160
return CoveringDesign(v,k,t,size,range(v),blocks,size,"Trivial")
161
162
# default case, all k-subsets
163
return CoveringDesign(v,k,t,binomial(v,k),range(v),Combinations(range(v),k),schonheim(v,k,t),"Trivial")
164
165
166
class CoveringDesign(SageObject):
167
"""
168
Covering design.
169
170
INPUT:
171
172
- ``v,k,t`` -- integer parameters of the covering design.
173
174
- ``size`` (integer)
175
176
- ``points`` -- list of points (default points are `[0,...v-1]`).
177
178
- ``blocks``
179
180
- ``low_bd`` (integer) -- lower bound for such a design
181
182
- ``method, creator, timestamp`` -- database information.
183
"""
184
185
def __init__(self, v=0, k=0, t=0, size=0, points=[], blocks=[], low_bd=0, method='', creator ='',timestamp=''):
186
"""
187
EXAMPLES::
188
189
sage: C=CoveringDesign(5,4,3,4,range(5),[[0,1,2,3],[0,1,2,4],[0,1,3,4],[0,2,3,4]],4, 'Lexicographic Covering')
190
sage: print C
191
C(5,4,3) = 4
192
Method: Lexicographic Covering
193
0 1 2 3
194
0 1 2 4
195
0 1 3 4
196
0 2 3 4
197
"""
198
self.__v = v
199
self.__k = k
200
self.__t = t
201
self.__size = size
202
if low_bd > 0:
203
self.__low_bd = low_bd
204
else:
205
self.__low_bd = schonheim(v,k,t)
206
self.__method = method
207
self.__creator = creator
208
self.__timestamp = timestamp
209
self.__incidence_structure = IncidenceStructure(points, blocks)
210
211
212
def __repr__(self):
213
"""
214
A print method, giving the parameters and any other
215
information about the covering (but not the blocks).
216
217
EXAMPLES::
218
219
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
220
sage: C
221
(7,3,2)-covering design of size 7
222
Lower bound: 7
223
Method: Projective Plane
224
"""
225
repr = '(%d,%d,%d)-covering design of size %d\n'%(self.__v,self.__k,self.__t,self.__size)
226
repr += 'Lower bound: %d\n'%(self.__low_bd)
227
if self.__creator != '':
228
repr += 'Created by: %s\n'%(self.__creator)
229
if self.__method != '':
230
repr += 'Method: %s\n'%(self.__method)
231
if self.__timestamp != '':
232
repr += 'Submitted on: %s\n'%(self.__timestamp)
233
234
return repr
235
236
def __str__(self):
237
"""
238
A print method, displaying a covering design's parameters and blocks.
239
240
OUTPUT:
241
242
covering design parameters and blocks, in a readable form
243
244
EXAMPLES::
245
246
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
247
sage: print C
248
C(7,3,2) = 7
249
Method: Projective Plane
250
0 1 2
251
0 3 4
252
0 5 6
253
1 3 5
254
1 4 6
255
2 3 6
256
2 4 5
257
"""
258
if self.__size == self.__low_bd: # check if the covering is known to be optimal
259
repr = 'C(%d,%d,%d) = %d\n'%(self.__v,self.__k,self.__t,self.__size)
260
else:
261
repr = '%d <= C(%d,%d,%d) <= %d\n'%(self.__low_bd,self.__v,self.__k,self.__t,self.__size);
262
if self.__creator != '':
263
repr += 'Created by: %s\n'%(self.__creator)
264
if self.__method != '':
265
repr += 'Method: %s\n'%(self.__method)
266
if self.__timestamp != '':
267
repr += 'Submitted on: %s\n'%(self.__timestamp)
268
for i in range(self.__size):
269
for j in range(self.__k):
270
repr = repr + str(self.__incidence_structure.blocks()[i][j]) + ' '
271
repr += '\n'
272
273
return repr
274
275
def is_covering(self):
276
"""
277
Checks that all `t`-sets are in fact covered by the blocks of
278
``self``
279
280
.. NOTE::
281
282
This is very slow and wasteful of memory.
283
284
EXAMPLES::
285
286
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
287
sage: C.is_covering()
288
True
289
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 6]],0, 'not a covering') # last block altered
290
sage: C.is_covering()
291
False
292
"""
293
v = self.__v
294
k = self.__k
295
t = self.__t
296
Svt = Combinations(range(v),t)
297
Skt = Combinations(range(k),t)
298
tset = {} # tables of t-sets: False = uncovered, True = covered
299
for i in Svt:
300
tset[tuple(i)] = False
301
302
# mark all t-sets covered by each block
303
for a in self.__incidence_structure.blocks():
304
for z in Skt:
305
y = [a[x] for x in z]
306
tset[tuple(y)] = True
307
308
for i in Svt:
309
if tset[tuple(i)] == False: # uncovered
310
return False
311
312
return True # everything was covered
313
314
315
def v(self):
316
"""
317
Return `v`, the number of points in the covering design.
318
319
EXAMPLES::
320
321
sage: from sage.combinat.designs.covering_design import CoveringDesign
322
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
323
sage: C.v()
324
7
325
"""
326
return self.__v
327
328
329
def k(self):
330
"""
331
Return `k`, the size of blocks of the covering design
332
333
EXAMPLES::
334
335
sage: from sage.combinat.designs.covering_design import CoveringDesign
336
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
337
sage: C.k()
338
3
339
"""
340
return self.__k
341
342
343
def t(self):
344
"""
345
Return `t`, the size of sets which must be covered by the
346
blocks of the covering design
347
348
EXAMPLES::
349
350
sage: from sage.combinat.designs.covering_design import CoveringDesign
351
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
352
sage: C.t()
353
2
354
"""
355
return self.__t
356
357
def size(self):
358
"""
359
Return the number of blocks in the covering design
360
361
EXAMPLES::
362
363
sage: from sage.combinat.designs.covering_design import CoveringDesign
364
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
365
sage: C.size()
366
7
367
"""
368
return self.__size
369
370
371
def low_bd(self):
372
"""
373
Return a lower bound for the number of blocks a covering
374
design with these parameters could have.
375
376
Typically this is the Schonheim bound, but for some parameters
377
better bounds have been shown.
378
379
EXAMPLES::
380
381
sage: from sage.combinat.designs.covering_design import CoveringDesign
382
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
383
sage: C.low_bd()
384
7
385
"""
386
return self.__low_bd
387
388
def method(self):
389
"""
390
Return the method used to create the covering design
391
This field is optional, and is used in a database to give information about how coverings were constructed
392
393
EXAMPLES::
394
395
sage: from sage.combinat.designs.covering_design import CoveringDesign
396
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
397
sage: C.method()
398
'Projective Plane'
399
"""
400
return self.__method
401
402
def creator(self):
403
"""
404
Return the creator of the covering design
405
406
This field is optional, and is used in a database to give
407
attribution for the covering design It can refer to the person
408
who submitted it, or who originally gave a construction
409
410
EXAMPLES::
411
412
sage: from sage.combinat.designs.covering_design import CoveringDesign
413
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane','Gino Fano')
414
sage: C.creator()
415
'Gino Fano'
416
"""
417
return self.__creator
418
419
def timestamp(self):
420
"""
421
Return the time that the covering was submitted to the database
422
423
EXAMPLES::
424
425
sage: from sage.combinat.designs.covering_design import CoveringDesign
426
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane','Gino Fano','1892-01-01 00:00:00')
427
sage: C.timestamp() #Fano had an article in 1892, I don't know the date it appeared
428
'1892-01-01 00:00:00'
429
"""
430
return self.__timestamp
431
432
433
def incidence_structure(self):
434
"""
435
Return the incidence structure of a covering design, without all the extra parameters.
436
437
EXAMPLES::
438
439
sage: from sage.combinat.designs.covering_design import CoveringDesign
440
sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
441
sage: D = C.incidence_structure()
442
sage: D.points()
443
[0, 1, 2, 3, 4, 5, 6]
444
sage: D.blocks()
445
[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]
446
447
"""
448
return self.__incidence_structure
449
450
def best_known_covering_design_www(v, k, t, verbose=False):
451
r"""
452
Gives the best known `(v,k,t)` covering design, using the database
453
available at `<http://www.ccrwest.org/>`_
454
455
INPUeT:
456
457
- ``v`` -- integer, the size of the point set for the design
458
- ``k`` -- integer, the number of points per block
459
- ``t`` -- integer, the size of sets covered by the blocks
460
- ``verbose`` -- bool (default=``False``), print verbose message
461
462
OUTPUT:
463
464
A :class:`CoveringDesign` object representing the ``(v,k,t)``-covering
465
design with smallest number of blocks available in the database.
466
467
EXAMPLES::
468
469
sage: from sage.combinat.designs.covering_design import best_known_covering_design_www
470
sage: C = best_known_covering_design_www(7, 3, 2) # optional - internet
471
sage: print C # optional - internet
472
C(7,3,2) = 7
473
Method: lex covering
474
Submitted on: 1996-12-01 00:00:00
475
0 1 2
476
0 3 4
477
0 5 6
478
1 3 5
479
1 4 6
480
2 3 6
481
2 4 5
482
483
This function raises a ValueError if the ``(v,k,t)`` parameters are not
484
found in the database.
485
"""
486
import urllib
487
from sage.misc.sage_eval import sage_eval
488
489
v = int(v)
490
k = int(k)
491
t = int(t)
492
493
param = ("?v=%s&k=%s&t=%s"%(v,k,t))
494
495
url = "http://www.ccrwest.org/cover/get_cover.php"+param
496
if verbose:
497
print "Looking up the bounds at %s"%url
498
f = urllib.urlopen(url)
499
s = f.read()
500
f.close()
501
502
if 'covering not in database' in s: #not found
503
str = "no (%d,%d,%d) covering design in database\n"%(v,k,t)
504
raise ValueError, str
505
506
return sage_eval(s)
507
508