Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 19204
1
r"""
2
Interface to a classification database using sqlite3
3
====================================================
4
5
The ``classification_database_sqlite3`` module defines interfaces
6
to manipulate an SQLite3 database of Cayley graph classifications.
7
8
AUTHORS:
9
10
- Paul Leopardi (2017-10-28)
11
12
"""
13
#*****************************************************************************
14
# Copyright (C) 2017-2018 Paul Leopardi [email protected]
15
#
16
# Distributed under the terms of the GNU General Public License (GPL)
17
# as published by the Free Software Foundation; either version 2 of
18
# the License, or (at your option) any later version.
19
# http://www.gnu.org/licenses/
20
#*****************************************************************************
21
22
23
import hashlib
24
import os
25
import sqlite3
26
27
#from exceptions import OSError
28
from sage.matrix.constructor import matrix
29
30
from boolean_cayley_graphs.bent_function import BentFunction
31
from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassification, default_algorithm
32
from boolean_cayley_graphs.weight_class import weight_class
33
34
35
def create_database(db_name):
36
"""
37
Create a database.
38
39
INPUT:
40
41
- ``db_name`` -- string. The name of the database to be created.
42
43
OUTPUT: a database connection object.
44
45
EXAMPLE:
46
47
Create a database using a temporary filename, then drop the database.
48
49
::
50
51
sage: from sage.misc.temporary_file import tmp_filename
52
sage: db_name = tmp_filename(ext='.db')
53
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
54
sage: conn = create_database(db_name)
55
sage: type(conn)
56
<class 'sqlite3.Connection'>
57
sage: drop_database(db_name)
58
"""
59
conn = sqlite3.connect(db_name)
60
conn.row_factory = sqlite3.Row
61
return conn
62
63
64
def connect_to_database(db_name):
65
"""
66
Connect to an existing database.
67
68
INPUT:
69
70
- ``db_name`` -- string. The name of the existing database.
71
72
OUTPUT: a database connection object.
73
74
EXAMPLE:
75
76
Create a database using a temporary filename, connect to it,
77
then drop the database.
78
79
::
80
81
sage: from sage.misc.temporary_file import tmp_filename
82
sage: db_name = tmp_filename(ext='.db')
83
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
84
sage: conn = create_database(db_name)
85
sage: con2 = connect_to_database(db_name)
86
sage: type(con2)
87
<class 'sqlite3.Connection'>
88
sage: drop_database(db_name)
89
"""
90
if os.path.isfile(db_name):
91
conn = sqlite3.connect(db_name)
92
conn.row_factory = sqlite3.Row
93
return conn
94
else:
95
raise IOError("File not found: {}".format(db_name))
96
97
def drop_database(db_name):
98
"""
99
Drop a database, if it exists.
100
101
INPUT:
102
103
- ``db_name`` -- string. The name of the existing database.
104
105
OUTPUT: None.
106
107
EXAMPLE:
108
109
Create a database using a temporary filename, then drop the database.
110
111
::
112
113
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
114
sage: import os
115
sage: db_name = tmp_filename(ext='.db')
116
sage: conn = create_database(db_name)
117
sage: os.path.exists(db_name)
118
True
119
sage: drop_database(db_name)
120
sage: os.path.exists(db_name)
121
False
122
sage: drop_database(db_name)
123
sage: os.path.exists(db_name)
124
False
125
"""
126
if os.path.exists(db_name):
127
try:
128
os.remove(db_name)
129
except OSError:
130
pass
131
132
133
def create_classification_tables(db_name):
134
"""
135
Create the tables used for a database of Cayley graph classifications.
136
137
INPUT:
138
139
- ``db_name`` -- string. The name of an existing database.
140
141
OUTPUT: a database connection object.
142
143
EXAMPLE:
144
145
Create a database, with tables, using a temporary filename,
146
list the table names, then drop the database.
147
148
::
149
150
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
151
sage: import os
152
sage: db_name = tmp_filename(ext='.db')
153
sage: conn = create_database(db_name)
154
sage: conn.close()
155
sage: conn = create_classification_tables(db_name)
156
sage: os.path.exists(db_name)
157
True
158
sage: curs = conn.cursor()
159
sage: result = curs.execute("SELECT name FROM sqlite_master WHERE type='table'")
160
sage: for row in curs:
161
....: for x in row:
162
....: print(x)
163
....:
164
bent_function
165
graph
166
cayley_graph
167
matrices
168
sage: conn.close()
169
sage: drop_database(db_name)
170
"""
171
conn = connect_to_database(db_name)
172
curs = conn.cursor()
173
174
curs.execute("""
175
CREATE TABLE bent_function(
176
nvariables INTEGER,
177
bent_function BLOB,
178
name TEXT UNIQUE,
179
PRIMARY KEY(nvariables, bent_function))""")
180
curs.execute("""
181
CREATE TABLE graph(
182
graph_id INTEGER,
183
canonical_label_hash BLOB UNIQUE,
184
canonical_label TEXT,
185
PRIMARY KEY(graph_id))""")
186
curs.execute("""
187
CREATE TABLE cayley_graph(
188
nvariables INTEGER,
189
bent_function BLOB,
190
cayley_graph_index INTEGER,
191
canonical_label_hash BLOB,
192
FOREIGN KEY(nvariables, bent_function)
193
REFERENCES bent_function(nvariables, bent_function),
194
FOREIGN KEY(canonical_label_hash)
195
REFERENCES graph(canonical_label_hash),
196
PRIMARY KEY(nvariables, bent_function, cayley_graph_index))""")
197
curs.execute("""
198
CREATE TABLE matrices(
199
nvariables INTEGER,
200
bent_function BLOB,
201
b INTEGER,
202
c INTEGER,
203
bent_cayley_graph_index INTEGER,
204
dual_cayley_graph_index INTEGER,
205
weight_class INTEGER,
206
FOREIGN KEY(nvariables, bent_function)
207
REFERENCES bent_function(nvariables, bent_function),
208
FOREIGN KEY(nvariables, bent_function, bent_cayley_graph_index)
209
REFERENCES cayley_graph(nvariables, bent_function, cayley_graph_index),
210
FOREIGN KEY(nvariables, bent_function, dual_cayley_graph_index)
211
REFERENCES cayley_graph(nvariables, bent_function, cayley_graph_index),
212
PRIMARY KEY(nvariables, bent_function, b, c))""")
213
conn.commit()
214
return conn
215
216
217
def canonical_label_hash(g):
218
"""
219
Hash a graph canonical label.
220
221
INPUT:
222
223
- ``g`` -- a graph canonical label.
224
225
OUTPUT: A hash digest as a bytes object.
226
227
EXAMPLE:
228
229
::
230
231
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
232
sage: from boolean_cayley_graphs.bent_function import BentFunction
233
sage: bentf = BentFunction([0,0,0,1])
234
sage: cayley_graph = bentf.extended_cayley_graph()
235
sage: cgcl = cayley_graph.canonical_label().graph6_string()
236
sage: cgcl_hash = canonical_label_hash(cgcl)
237
sage: print(type(cgcl_hash))
238
<class 'bytes'>
239
sage: print(len(cgcl_hash))
240
32
241
"""
242
encoding = "UTF-8"
243
bytes_g = bytes(g, encoding)
244
return hashlib.sha256(bytes_g).digest()
245
246
247
flatten = lambda t: [item for sublist in t for item in sublist]
248
249
250
def insert_classification(
251
conn,
252
bfcgc,
253
name=None):
254
"""
255
Insert a Cayley graph classification into a database.
256
257
INPUT:
258
259
- ``conn`` -- a connection object for the database.
260
- ``bfcgc`` -- a Cayley graph classification.
261
- ``name`` -- string (default: `None`). The name of the bent function.
262
263
OUTPUT: None.
264
265
A cursor object corresponding to state of the database after the
266
classification is inserted.
267
268
EXAMPLE:
269
270
Create a database, with tables, using a temporary filename, insert
271
a classification, retrieve it by bent function, then drop the database.
272
273
::
274
275
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
276
sage: from boolean_cayley_graphs.bent_function import BentFunction
277
sage: from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassification
278
sage: bentf = BentFunction([0,0,0,1])
279
sage: bfcgc = BentFunctionCayleyGraphClassification.from_function(bentf)
280
sage: bfcgc.algebraic_normal_form
281
x0*x1
282
sage: db_name = tmp_filename(ext='.db')
283
sage: conn = create_classification_tables(db_name)
284
sage: insert_classification(conn, bfcgc, 'bentf')
285
sage: result = select_classification_where_bent_function(conn, bentf)
286
sage: result.algebraic_normal_form
287
x0*x1
288
sage: drop_database(db_name)
289
"""
290
bentf = BentFunction(bfcgc.algebraic_normal_form)
291
dim = bentf.nvariables()
292
nvar = int(dim)
293
bftt = bentf.tt_buffer()
294
cgcl = bfcgc.cayley_graph_class_list
295
bcim = bfcgc.bent_cayley_graph_index_matrix
296
dcim = bfcgc.dual_cayley_graph_index_matrix
297
wcm = bfcgc.weight_class_matrix
298
299
curs = conn.cursor()
300
curs.execute("BEGIN")
301
curs.execute("""
302
INSERT INTO bent_function
303
VALUES (?,?,?)""",
304
(nvar, bftt, name))
305
306
cgcl_len = len(cgcl)
307
cgc_hash_list = [
308
canonical_label_hash(cgc)
309
for cgc in cgcl]
310
graph_param_list = [
311
(None, cgc_hash_list[n], cgcl[n])
312
for n in range(cgcl_len)]
313
curs.executemany("""
314
INSERT OR IGNORE INTO graph
315
VALUES (?,?,?)""",
316
graph_param_list)
317
318
cayley_graph_param_list = [
319
(nvar, bftt, n, cgc_hash_list[n])
320
for n in range(cgcl_len)]
321
curs.executemany("""
322
INSERT INTO cayley_graph
323
VALUES (?,?,?,?)""",
324
cayley_graph_param_list)
325
326
v = 2 ** dim
327
matrices_param_list = flatten([[(
328
nvar,
329
bftt,
330
b,
331
c,
332
int(bcim[c,b]),
333
int(dcim[c,b]),
334
int(wcm[c,b]))
335
for c in range(v)]
336
for b in range(v)])
337
curs.executemany("""
338
INSERT INTO matrices
339
VALUES (?,?,?,?,?,?,?)""",
340
matrices_param_list)
341
conn.commit()
342
343
344
def select_classification_where_bent_function(
345
conn,
346
bentf):
347
"""
348
Retrieve a Cayley graph classification for a given bent function from a database.
349
350
INPUT:
351
352
- ``conn`` -- a connection object for the database.
353
- ``bentf`` -- class BentFunction. A bent function.
354
355
OUTPUT:
356
357
class BentFunctionCayleyGraphClassification.
358
The corresponding Cayley graph classification.
359
360
EXAMPLE:
361
362
Create a database, with tables, using a temporary filename, insert
363
a classification, retrieve it by bent function, then drop the database.
364
365
::
366
367
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
368
sage: from boolean_cayley_graphs.bent_function import BentFunction
369
sage: from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassification
370
sage: bentf = BentFunction([0,0,0,1])
371
sage: bfcgc = BentFunctionCayleyGraphClassification.from_function(bentf)
372
sage: bfcgc.algebraic_normal_form
373
x0*x1
374
sage: db_name = tmp_filename(ext='.db')
375
sage: conn = create_classification_tables(db_name)
376
sage: insert_classification(conn, bfcgc, 'bentf')
377
sage: result = select_classification_where_bent_function(conn, bentf)
378
sage: result.algebraic_normal_form
379
x0*x1
380
sage: type(result)
381
<class 'boolean_cayley_graphs.bent_function_cayley_graph_classification.BentFunctionCayleyGraphClassification'>
382
sage: result.report(report_on_matrix_details=True)
383
Algebraic normal form of Boolean function: x0*x1
384
Function is bent.
385
<BLANKLINE>
386
Weight class matrix:
387
[0 0 0 1]
388
[0 1 0 0]
389
[0 0 1 0]
390
[1 0 0 0]
391
<BLANKLINE>
392
SDP design incidence structure t-design parameters: (True, (1, 4, 1, 1))
393
<BLANKLINE>
394
Classification of Cayley graphs and classification of Cayley graphs of duals are the same:
395
<BLANKLINE>
396
There are 2 extended Cayley classes in the extended translation class.
397
<BLANKLINE>
398
Matrix of indices of Cayley graphs:
399
[0 0 0 1]
400
[0 1 0 0]
401
[0 0 1 0]
402
[1 0 0 0]
403
sage: drop_database(db_name)
404
"""
405
dim = bentf.nvariables()
406
nvar = int(dim)
407
bftt = bentf.tt_buffer()
408
curs = conn.cursor()
409
curs.execute("""
410
SELECT COUNT(*)
411
FROM cayley_graph
412
WHERE nvariables = (?)
413
AND bent_function = (?)""",
414
(nvar, bftt))
415
row = curs.fetchone()
416
if row == None:
417
return None
418
419
cgcl_len = row[0]
420
cgcl = [None] * cgcl_len
421
curs.execute("""
422
SELECT cayley_graph_index, canonical_label
423
FROM cayley_graph, graph
424
WHERE nvariables = (?)
425
AND bent_function = (?)
426
AND cayley_graph.canonical_label_hash = graph.canonical_label_hash""",
427
(nvar, bftt))
428
for row in curs:
429
cayley_graph_index = row["cayley_graph_index"]
430
canonical_label = row["canonical_label"]
431
cgcl[cayley_graph_index] = str(canonical_label)
432
433
v = 2 ** dim
434
bcim = matrix(v, v)
435
dcim = matrix(v, v)
436
wcm = matrix(v, v)
437
curs.execute("""
438
SELECT *
439
FROM matrices
440
WHERE nvariables = (?)
441
AND bent_function = (?)""",
442
(nvar, bftt))
443
for row in curs:
444
b = row["b"]
445
c = row["c"]
446
447
bent_cayley_graph_index = row["bent_cayley_graph_index"]
448
bcim[c, b] = bent_cayley_graph_index
449
450
dual_cayley_graph_index = row["dual_cayley_graph_index"]
451
dcim[c, b] = dual_cayley_graph_index
452
453
weight_class = row["weight_class"]
454
wcm[c, b] = weight_class
455
456
return BentFunctionCayleyGraphClassification(
457
algebraic_normal_form=bentf.algebraic_normal_form(),
458
cayley_graph_class_list=cgcl,
459
bent_cayley_graph_index_matrix=bcim,
460
dual_cayley_graph_index_matrix=dcim,
461
weight_class_matrix=wcm)
462
463
464
def select_classification_where_bent_function_cayley_graph(
465
conn,
466
bentf,
467
algorithm=default_algorithm):
468
"""
469
Given a bent function ``bentf``, retrieve all classifications that
470
contain a Cayley graph isomorphic to the Cayley graph of ``bentf``.
471
472
INPUT:
473
474
- ``conn`` -- a connection object for the database.
475
- ``bentf`` -- class BentFunction. A bent function.
476
- ``algorithm`` -- string (default: BentFunctionCayleyGraphClassification.default_algorithm).
477
Algorithm used for canonical labelling.
478
479
OUTPUT:
480
481
A list where each entry has class BentFunctionCayleyGraphClassification.
482
The corresponding list of Cayley graph classifications.
483
484
NOTE:
485
486
::
487
488
The list is not sorted in any way.
489
490
EXAMPLE:
491
492
Create a database, with tables, using a temporary filename, insert
493
a classification, retrieve it by bent function Cayley graph, then drop the database.
494
495
::
496
497
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
498
sage: from boolean_cayley_graphs.bent_function import BentFunction
499
sage: from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassification
500
sage: db_name = 'doctest_select_classification_where_bent_function_db_name'
501
sage: drop_database(db_name)
502
sage: conn = create_database(db_name)
503
sage: conn.close()
504
sage: conn = create_classification_tables(db_name)
505
sage: bentf0 = BentFunction([0,0,0,1])
506
sage: bfcgc0 = BentFunctionCayleyGraphClassification.from_function(bentf0)
507
sage: bfcgc0.algebraic_normal_form
508
x0*x1
509
sage: insert_classification(conn, bfcgc0, 'bentf0')
510
sage: bentf1 = BentFunction([1,0,0,0])
511
sage: bfcgc1 = BentFunctionCayleyGraphClassification.from_function(bentf1)
512
sage: bfcgc1.algebraic_normal_form
513
x0*x1 + x0 + x1 + 1
514
sage: insert_classification(conn, bfcgc1, 'bentf1')
515
sage: result = select_classification_where_bent_function_cayley_graph(conn, bentf1)
516
sage: type(result)
517
<class 'list'>
518
sage: len(result)
519
2
520
sage: sorted_result = sorted(result, key=lambda c: str(c.algebraic_normal_form))
521
sage: for c in sorted_result:
522
....: type(c)
523
....: c.algebraic_normal_form
524
....: c.report()
525
<class 'boolean_cayley_graphs.bent_function_cayley_graph_classification.BentFunctionCayleyGraphClassification'>
526
x0*x1
527
Algebraic normal form of Boolean function: x0*x1
528
Function is bent.
529
<BLANKLINE>
530
<BLANKLINE>
531
SDP design incidence structure t-design parameters: (True, (1, 4, 1, 1))
532
<BLANKLINE>
533
Classification of Cayley graphs and classification of Cayley graphs of duals are the same:
534
<BLANKLINE>
535
There are 2 extended Cayley classes in the extended translation class.
536
<class 'boolean_cayley_graphs.bent_function_cayley_graph_classification.BentFunctionCayleyGraphClassification'>
537
x0*x1 + x0 + x1 + 1
538
Algebraic normal form of Boolean function: x0*x1 + x0 + x1 + 1
539
Function is bent.
540
<BLANKLINE>
541
<BLANKLINE>
542
SDP design incidence structure t-design parameters: (True, (1, 4, 1, 1))
543
<BLANKLINE>
544
Classification of Cayley graphs and classification of Cayley graphs of duals are the same:
545
<BLANKLINE>
546
There are 2 extended Cayley classes in the extended translation class.
547
sage: conn.close()
548
sage: drop_database(db_name)
549
"""
550
# The result is a list of classifications.
551
result = []
552
553
cayley_graph = bentf.extended_cayley_graph()
554
cgcl = cayley_graph.canonical_label(algorithm=algorithm).graph6_string()
555
cgcl_hash = canonical_label_hash(cgcl)
556
557
# Check for a hash collision -- very unlikely.
558
curs = conn.cursor()
559
curs.execute("""
560
SELECT canonical_label
561
FROM graph
562
WHERE canonical_label_hash = (?)""",
563
(cgcl_hash,))
564
row = curs.fetchone()
565
canonical_label = row["canonical_label"]
566
if canonical_label != cgcl:
567
return result
568
569
curs.execute("""
570
SELECT DISTINCT nvariables, bent_function
571
FROM cayley_graph
572
WHERE canonical_label_hash = (?)""",
573
(cgcl_hash,))
574
575
for row in curs:
576
nvar = row["nvariables"]
577
bftt = row["bent_function"]
578
row_bentf = BentFunction.from_tt_buffer(nvar, bftt)
579
result.append(
580
select_classification_where_bent_function(
581
conn,
582
row_bentf))
583
return result
584
585
586
def select_classification_where_name(
587
conn,
588
name):
589
"""
590
Retrieve a Cayley graph classification for a bent function with a given name from a database.
591
592
INPUT:
593
594
- ``conn`` -- a connection object for the database.
595
- ``name`` -- string. The name of the bent function.
596
597
OUTPUT: class BentFunctionCayleyGraphClassification.
598
The corresponding a Cayley graph classification.
599
600
EXAMPLE:
601
602
Create a database, with tables, using a temporary filename, insert
603
a classification, retrieve it by name, then drop the database.
604
605
::
606
607
sage: from boolean_cayley_graphs.classification_database_sqlite3 import *
608
sage: from boolean_cayley_graphs.bent_function import BentFunction
609
sage: from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassification
610
sage: db_name = tmp_filename(ext='.db')
611
sage: conn = create_classification_tables(db_name)
612
sage: bentf = BentFunction([0,0,0,1])
613
sage: bfcgc = BentFunctionCayleyGraphClassification.from_function(bentf)
614
sage: bfcgc.algebraic_normal_form
615
x0*x1
616
sage: insert_classification(conn, bfcgc,'bentf')
617
sage: result = select_classification_where_name(conn, 'bentf')
618
sage: result.algebraic_normal_form
619
x0*x1
620
sage: type(result)
621
<class 'boolean_cayley_graphs.bent_function_cayley_graph_classification.BentFunctionCayleyGraphClassification'>
622
sage: result.report(report_on_matrix_details=True)
623
Algebraic normal form of Boolean function: x0*x1
624
Function is bent.
625
<BLANKLINE>
626
Weight class matrix:
627
[0 0 0 1]
628
[0 1 0 0]
629
[0 0 1 0]
630
[1 0 0 0]
631
<BLANKLINE>
632
SDP design incidence structure t-design parameters: (True, (1, 4, 1, 1))
633
<BLANKLINE>
634
Classification of Cayley graphs and classification of Cayley graphs of duals are the same:
635
<BLANKLINE>
636
There are 2 extended Cayley classes in the extended translation class.
637
<BLANKLINE>
638
Matrix of indices of Cayley graphs:
639
[0 0 0 1]
640
[0 1 0 0]
641
[0 0 1 0]
642
[1 0 0 0]
643
sage: drop_database(db_name)
644
"""
645
curs = conn.cursor()
646
curs.execute("""
647
SELECT nvariables, bent_function
648
FROM bent_function
649
WHERE name = (?)""",
650
(name,))
651
row = curs.fetchone()
652
if row == None:
653
return None
654
655
nvar = row["nvariables"]
656
bftt = row["bent_function"]
657
bentf = BentFunction.from_tt_buffer(nvar, bftt)
658
659
return select_classification_where_bent_function(
660
conn,
661
bentf)
662
663