Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 19204
1
r"""
2
An improved Boolean function class
3
==================================
4
5
The ``boolean_function_improved`` module defines
6
the ``BooleanFunctionImproved`` class,
7
which is a subclass of BooleanFunction that adds extra methods.
8
One such method is ``cayley_graph``,
9
which returns the Cayley graph of the Boolean function.
10
11
AUTHORS:
12
13
- Paul Leopardi (2016-08-23): initial version
14
15
EXAMPLES:
16
17
::
18
19
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
20
sage: bf = BooleanFunctionImproved([0,0,0,1])
21
sage: type(bf)
22
<class 'boolean_cayley_graphs.boolean_function_improved.BooleanFunctionImproved'>
23
sage: bf.truth_table(format='int')
24
(0, 0, 0, 1)
25
"""
26
27
#*****************************************************************************
28
# Copyright (C) 2016-2017 Paul Leopardi [email protected]
29
#
30
# Distributed under the terms of the GNU General Public License (GPL)
31
# as published by the Free Software Foundation; either version 2 of
32
# the License, or (at your option) any later version.
33
# http://www.gnu.org/licenses/
34
#*****************************************************************************
35
36
import binascii
37
import csv
38
39
from datetime import datetime
40
from sage.crypto.boolean_function import BooleanFunction
41
from sage.matrix.constructor import Matrix
42
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
43
from sage.rings.integer import Integer
44
from sage.rings.integer_ring import ZZ
45
from sys import stdout
46
47
from boolean_cayley_graphs.boolean_cayley_graph import boolean_cayley_graph
48
from boolean_cayley_graphs.boolean_linear_code import boolean_linear_code
49
from boolean_cayley_graphs.integer_bits import base2, inner
50
from boolean_cayley_graphs.linear import is_linear
51
from boolean_cayley_graphs.saveable import Saveable
52
53
import boolean_cayley_graphs.cayley_graph_controls as controls
54
55
encoding = "UTF-8"
56
57
58
class BooleanFunctionImproved(BooleanFunction, Saveable):
59
r"""
60
A subclass of BooleanFunction that adds extra methods.
61
62
The class inherits from BooleanFunction is initialized in the same way.
63
The class inherits from Saveable to obtain
64
load_mangled and save_mangled methods.
65
66
EXAMPLES:
67
68
::
69
70
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
71
sage: bf1 = BooleanFunctionImproved([0,1,0,0])
72
sage: type(bf1)
73
<class 'boolean_cayley_graphs.boolean_function_improved.BooleanFunctionImproved'>
74
sage: bf1.algebraic_normal_form()
75
x0*x1 + x0
76
sage: bf1.truth_table()
77
(False, True, False, False)
78
79
TESTS:
80
81
::
82
83
sage: from sage.crypto.boolean_function import BooleanFunction
84
sage: bf = BooleanFunctionImproved([0,1,0,0])
85
sage: print(bf)
86
Boolean function with 2 variables
87
88
sage: from sage.crypto.boolean_function import BooleanFunction
89
sage: bf = BooleanFunctionImproved([0,1,0,0])
90
sage: latex(bf)
91
\text{\texttt{Boolean{ }function{ }with{ }2{ }variables}}
92
"""
93
94
95
@classmethod
96
def from_tt_buffer(
97
cls,
98
dim,
99
tt_buffer):
100
r"""
101
Constructor from the buffer tt_buffer.
102
103
The buffer tt_buffer is assumed to be the result of method tt_buffer(),
104
which returns a result of type buffer representing a truth table in hex.
105
106
INPUT:
107
108
- ``cls`` -- the class object.
109
- ``dim`` -- integer: the dimension of the Boolean function.
110
- ``tt_buffer`` -- buffer: the result of the method tt_buffer()
111
for the Boolean function.
112
113
EXAMPLES:
114
115
::
116
117
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
118
sage: bf2 = BooleanFunctionImproved([0,1,0,0])
119
sage: bf2_tt_buffer = bf2.tt_buffer()
120
sage: bf2_test = BooleanFunctionImproved.from_tt_buffer(2, bf2_tt_buffer)
121
sage: bf2_test.algebraic_normal_form()
122
x0*x1 + x0
123
sage: bf2 == bf2_test
124
True
125
sage: bf3 = BooleanFunctionImproved([0,1,0,0]*2)
126
sage: bf3.nvariables()
127
3
128
sage: bf3_tt_buffer = bf3.tt_buffer()
129
sage: bf3_test = BooleanFunctionImproved.from_tt_buffer(3, bf3_tt_buffer)
130
sage: bf3 == bf3_test
131
True
132
"""
133
tt_hex = str(binascii.b2a_hex(tt_buffer), encoding)
134
return cls.from_tt_hex(dim, tt_hex)
135
136
137
@classmethod
138
def from_tt_hex(
139
cls,
140
dim,
141
tt_hex):
142
r"""
143
Constructor from the dimension dim, and the string tt_hex.
144
145
The string tt_hex is assumed to be the result of method tt_hex(), which returns
146
a string representing a truth table in hex.
147
148
INPUT:
149
150
- ``cls`` -- the class object.
151
- ``dim`` -- integer: the dimension of the Boolean function.
152
- ``tt_hex`` -- string: the result of the method tt_hex() for the Boolean function.
153
154
EXAMPLES:
155
156
::
157
158
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
159
sage: bf2 = BooleanFunctionImproved([0,1,0,0])
160
sage: bf2_tt_hex = bf2.tt_hex()
161
sage: bf2_test = BooleanFunctionImproved.from_tt_hex(2, bf2_tt_hex)
162
sage: bf2_test.algebraic_normal_form()
163
x0*x1 + x0
164
sage: bf2 == bf2_test
165
True
166
167
TESTS:
168
169
::
170
171
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
172
sage: bf1 = BooleanFunctionImproved([0,1])
173
sage: bf1_tt_hex = bf1.tt_hex()
174
sage: bf1_test = BooleanFunctionImproved.from_tt_hex(1, bf1_tt_hex)
175
sage: bf1_test.algebraic_normal_form()
176
x
177
sage: bf1 == bf1_test
178
True
179
sage: bf3 = BooleanFunctionImproved([0,1,0,0]*2)
180
sage: bf3.nvariables()
181
3
182
sage: bf3_tt_hex = bf3.tt_hex()
183
sage: bf3_test = BooleanFunctionImproved.from_tt_hex(3, bf3_tt_hex)
184
sage: bf3 == bf3_test
185
True
186
"""
187
if dim < 3:
188
# Convert the hex character to an Integer
189
tt_integer = ZZ(tt_hex, 16)
190
# Convert the integer to a bit string
191
v = 2 ** dim
192
tt_bits = base2(v, tt_integer)
193
return BooleanFunctionImproved(tt_bits)
194
else:
195
return BooleanFunctionImproved(tt_hex)
196
197
198
@classmethod
199
def from_csv(
200
cls,
201
csv_file_name):
202
"""
203
Constructor from a csv file.
204
205
The csv file is assumed to be produced by the method save_as_csv().
206
207
INPUT:
208
209
- ``cls`` -- the class object.
210
- ``csv_file_name`` -- string: the name of the csv file to read from.
211
212
EXAMPLES:
213
214
::
215
216
sage: import csv
217
sage: import os
218
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
219
sage: bf2 = BooleanFunctionImproved([1,0,1,1])
220
sage: bf2_csv_name = tmp_filename(ext='.csv')
221
sage: bf2.save_as_csv(bf2_csv_name)
222
sage: bf2_test = BooleanFunctionImproved.from_csv(bf2_csv_name)
223
sage: bf2 == bf2_test
224
True
225
sage: os.remove(bf2_csv_name)
226
sage: bf3 = BooleanFunctionImproved([0,1,0,0]*2)
227
sage: bf3_csv_name = tmp_filename(ext='.csv')
228
sage: bf3.save_as_csv(bf3_csv_name)
229
sage: bf3_test = BooleanFunctionImproved.from_csv(bf3_csv_name)
230
sage: bf3 == bf3_test
231
True
232
"""
233
with open(csv_file_name) as csv_file:
234
reader = csv.DictReader(csv_file)
235
row = next(reader)
236
return BooleanFunctionImproved.from_tt_hex(
237
int(row["nvariables"]),
238
row["tt_hex"])
239
240
241
def __invert__(self):
242
"""
243
Return the complement Boolean function of `self`.
244
245
INPUT:
246
247
- ``self`` -- the current object.
248
249
EXAMPLES:
250
251
::
252
253
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
254
sage: bf0 = BooleanFunctionImproved([1,0,1,1])
255
sage: bf1 = ~bf0
256
sage: type(bf1)
257
<class 'boolean_cayley_graphs.boolean_function_improved.BooleanFunctionImproved'>
258
sage: bf1.algebraic_normal_form()
259
x0*x1 + x0
260
sage: bf1.truth_table()
261
(False, True, False, False)
262
"""
263
bf_self = BooleanFunction(self)
264
return type(self)(~bf_self)
265
266
267
def __add__(self, other):
268
"""
269
Return the elementwise sum of `self`and `other` which must have the same number of variables.
270
271
INPUT:
272
273
- ``self`` -- the current object.
274
- ``other`` -- another Boolean function.
275
276
OUTPUT:
277
278
The elementwise sum of `self`and `other`
279
280
EXAMPLES:
281
282
::
283
284
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
285
sage: bf0 = BooleanFunctionImproved([1,0,1,0])
286
sage: bf1 = BooleanFunctionImproved([1,1,0,0])
287
sage: (bf0+bf1).truth_table(format='int')
288
(0, 1, 1, 0)
289
sage: S = bf0.algebraic_normal_form() + bf1.algebraic_normal_form()
290
sage: (bf0+bf1).algebraic_normal_form() == S
291
True
292
293
TESTS:
294
295
::
296
297
sage: bf0+BooleanFunctionImproved([0,1])
298
Traceback (most recent call last):
299
...
300
ValueError: the two Boolean functions must have the same number of variables
301
"""
302
bf_self = BooleanFunction(self)
303
return type(self)(bf_self + other)
304
305
306
def __mul__(self, other):
307
"""
308
Return the elementwise product of `self`and `other` which must have the same number of variables.
309
310
INPUT:
311
312
- ``self`` -- the current object.
313
- ``other`` -- another Boolean function.
314
315
OUTPUT:
316
317
The elementwise product of `self`and `other`
318
319
EXAMPLES:
320
321
::
322
323
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
324
sage: bf0 = BooleanFunctionImproved([1,0,1,0])
325
sage: bf1 = BooleanFunctionImproved([1,1,0,0])
326
sage: (bf0*bf1).truth_table(format='int')
327
(1, 0, 0, 0)
328
sage: P = bf0.algebraic_normal_form() * bf1.algebraic_normal_form()
329
sage: (bf0*bf1).algebraic_normal_form() == P
330
True
331
332
TESTS:
333
334
::
335
336
sage: bf0*BooleanFunctionImproved([0,1])
337
Traceback (most recent call last):
338
...
339
ValueError: the two Boolean functions must have the same number of variables
340
"""
341
bf_self = BooleanFunction(self)
342
return type(self)(bf_self * other)
343
344
345
def __or__(self, other):
346
"""
347
Return the concatenation of `self` and `other` which must have the same number of variables.
348
349
INPUT:
350
351
- ``self`` -- the current object.
352
- ``other`` -- another Boolean function.
353
354
OUTPUT:
355
356
The concatenation of `self`and `other`
357
358
EXAMPLES:
359
360
::
361
362
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
363
sage: bf0 = BooleanFunctionImproved([1,0,1,0])
364
sage: bf1 = BooleanFunctionImproved([1,1,0,0])
365
sage: (bf0|bf1).truth_table(format='int')
366
(1, 0, 1, 0, 1, 1, 0, 0)
367
sage: C = bf0.truth_table() + bf1.truth_table()
368
sage: (bf0|bf1).truth_table(format='int') == C
369
True
370
371
TESTS:
372
373
::
374
375
sage: bf0|BooleanFunctionImproved([0,1])
376
Traceback (most recent call last):
377
...
378
ValueError: the two Boolean functions must have the same number of variables
379
"""
380
bf_self = BooleanFunction(self)
381
return type(self)(bf_self | other)
382
383
384
def __hash__(self):
385
r"""
386
Return the hash of ``self``.
387
This makes the class hashable.
388
389
390
INPUT:
391
392
- ``self`` -- the current object.
393
394
OUTPUT:
395
396
The hash of ``self``.
397
398
EXAMPLES::
399
400
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
401
sage: bf1 = BooleanFunctionImproved([0,1,0,0])
402
sage: hash(bf1) == hash(bf1.tt_hex())
403
True
404
"""
405
return hash(self.tt_hex())
406
407
408
def cayley_graph(self):
409
r"""
410
Return the Cayley graph of ``self``.
411
412
INPUT:
413
414
- ``self`` -- the current object.
415
416
OUTPUT:
417
418
The Cayley graph of ``self`` as an object of class ``Graph``.
419
420
EXAMPLES::
421
422
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
423
sage: bf1 = BooleanFunctionImproved([0,1,0,0])
424
sage: g1 = bf1.cayley_graph()
425
sage: g1.adjacency_matrix()
426
[0 1 0 0]
427
[1 0 0 0]
428
[0 0 0 1]
429
[0 0 1 0]
430
431
"""
432
dim = self.nvariables()
433
f = self.extended_translate()
434
return boolean_cayley_graph(dim, f)
435
436
437
def extended_cayley_graph(self):
438
r"""
439
Return the extended Cayley graph of ``self``.
440
441
INPUT:
442
443
- ``self`` -- the current object.
444
445
OUTPUT:
446
447
The extended Cayley graph of ``self`` as an object of class ``Graph``.
448
This is the Cayley graph of ``self`` if ``self(0) == False``,
449
otherwise it is the Cayley graph of ``~self``.
450
451
EXAMPLES:
452
453
::
454
455
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
456
sage: bf1 = BooleanFunctionImproved([0,1,0,0])
457
sage: g1 = bf1.extended_cayley_graph()
458
sage: g1.adjacency_matrix()
459
[0 1 0 0]
460
[1 0 0 0]
461
[0 0 0 1]
462
[0 0 1 0]
463
sage: bf2 = BooleanFunctionImproved([1,0,1,1])
464
sage: g2 = bf2.extended_cayley_graph()
465
sage: g2.adjacency_matrix()
466
[0 1 0 0]
467
[1 0 0 0]
468
[0 0 0 1]
469
[0 0 1 0]
470
471
"""
472
return ((~self).cayley_graph()
473
if self(0)
474
else self.cayley_graph())
475
476
477
def extended_translate(self, b=0, c=0, d=0):
478
r"""
479
Return an extended translation equivalent function of ``self``.
480
481
Given the non-negative numbers `b`, `c` and `d`, the function
482
`extended_translate` returns the Python function
483
484
:math:`x \mapsto \mathtt{self}(x + b) + \langle c, x \rangle + d`,
485
486
as described below.
487
488
INPUT:
489
490
- ``self`` -- the current object.
491
- ``b`` -- non-negative integer (default: 0)
492
which is mapped to :math:`\mathbb{F}_2^{dim}`.
493
- ``c`` -- non-negative integer (default: 0).
494
- ``d`` -- integer, 0 or 1 (default: 0).
495
496
OUTPUT:
497
498
The Python function
499
500
:math:`x \mapsto \mathtt{self}(x + b) + \langle c, x \rangle + d`,
501
502
where `b` and `c` are mapped to :math:`\mathbb{F}_2^{dim}` by the
503
lexicographical ordering implied by the ``base2`` function, and
504
where ``dim`` is the number of variables of ``self`` as a
505
``BooleanFunction.``
506
507
.. NOTE::
508
509
While ``self`` is a ``BooleanFunctionImproved``, the result of
510
``extended_translate`` is *not* a ``BooleanFunctionImproved``,
511
but rather a Python function that takes an ``Integer`` argument.
512
513
EXAMPLES:
514
515
::
516
517
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
518
sage: bf1 = BooleanFunctionImproved([0,1,0,0])
519
sage: f001 = bf1.extended_translate(b=0,c=0,d=1)
520
sage: [f001(x) for x in range(4)]
521
[1, 0, 1, 1]
522
"""
523
dim = self.nvariables()
524
return lambda x: self(base2(dim, x ^ b)) ^ (0 if c == 0 else inner(c, x)) ^ d
525
526
527
def zero_translate(self, b=0, c=0):
528
r"""
529
Return an extended translation equivalent function of ``self`` that is 0 at 0.
530
531
Given `self` and the non-negative numbers `b` and `c`, the function
532
`zero_translate` returns the Python function
533
534
:math:`x \mapsto \mathtt{bf}(x + b) + \langle c, x \rangle + \mathtt{bf}(b)`,
535
536
as described below.
537
538
INPUT:
539
540
- ``self`` -- the current object.
541
- ``b`` -- non-negative integer (default: 0).
542
- ``c`` -- non-negative integer (default: 0).
543
544
OUTPUT:
545
546
The Python function
547
548
:math:`x \mapsto \mathtt{self}(x + b) + \langle c, x \rangle + \mathtt{bf(b)}`,
549
550
where `b` and `c` are mapped to :math:`\mathbb{F}_2^{dim}` by the
551
lexicographical ordering implied by the ``base2`` function, and
552
where ``dim`` is the number of variables of ``self`` as a ``BooleanFunction.``
553
554
.. NOTE::
555
556
While ``self`` is a ``BooleanFunctionImproved``, the result of
557
``zero_translate`` is *not* a ``BooleanFunctionImproved``,
558
but rather a Python function that takes an ``Integer`` argument.
559
560
EXAMPLES:
561
562
::
563
564
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
565
sage: bf1 = BooleanFunctionImproved([0,1,0,0])
566
sage: f001 = bf1.zero_translate(b=0,c=0)
567
sage: [f001(x) for x in range(4)]
568
[0, 1, 0, 0]
569
"""
570
return self.extended_translate(b, c, self.extended_translate()(b))
571
572
573
def is_linear_equivalent(self, other, certificate=False):
574
r"""
575
Check if there is a linear equivalence between ``self`` and ``other``:
576
577
:math:`\mathtt{other}(M x) = \mathtt{self}(x)`,
578
579
where M is a GF(2) matrix.
580
581
INPUT:
582
583
- ``self`` -- the current object.
584
- ``other`` -- another object of class BooleanFunctionImproved.
585
- ``certificate`` -- bool (default False). If true, return a GF(2) matrix
586
that defines the isomorphism.
587
588
OUTPUT:
589
590
If ``certificate`` is false, a bool value.
591
If ``certificate`` is true, a tuple consisting of either (False, None)
592
or (True, M), where M is a GF(2) matrix that defines the equivalence.
593
594
EXAMPLES:
595
596
::
597
598
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
599
sage: bf1 = BooleanFunctionImproved([0,1,0,0])
600
sage: bf2 = BooleanFunctionImproved([0,0,1,0])
601
sage: bf1.is_linear_equivalent(bf2)
602
True
603
sage: bf2.is_linear_equivalent(bf1, certificate=True)
604
(
605
[0 1]
606
True, [1 0]
607
)
608
609
"""
610
self_cg = self.cayley_graph()
611
try:
612
other_cg = other.cayley_graph()
613
except AttributeError:
614
return (False, None) if certificate else False
615
616
# Check the isomorphism between self_cg and other_cg via canonical labels.
617
# This is to work around the slow speed of is_isomorphic in some cases.
618
if self_cg.canonical_label() != other_cg.canonical_label():
619
return (False, None) if certificate else False
620
621
# Obtain the mapping that defines the isomorphism.
622
is_isomorphic, mapping_dict = self_cg.is_isomorphic(other_cg, certificate=True)
623
624
# If self_cg is not isomorphic to other_cg, it is not linear equivalent.
625
if not is_isomorphic:
626
return (False, None) if certificate else False
627
628
mapping = lambda x: mapping_dict[x]
629
630
dim = self.nvariables()
631
v = 2 ** dim
632
633
# Check that mapping is linear.
634
if certificate:
635
linear, mapping_matrix = is_linear(dim, mapping, certificate)
636
else:
637
linear = is_linear(dim, mapping)
638
if linear:
639
return (True, mapping_matrix) if certificate else True
640
641
# For each permutation p in the automorphism group of self_cg,
642
# check that the permuted mapping:
643
# 1. preserves the value of other, and
644
# 2. is linear.
645
self_et = self.extended_translate()
646
other_et = other.extended_translate()
647
auto_group = self_cg.automorphism_group()
648
test_group = auto_group.stabilizer(0) if mapping(0) == 0 else auto_group
649
linear = False
650
for p in test_group:
651
p_mapping = lambda x: p(mapping(x))
652
# Check that p_mapping preserves other.
653
preserved = True
654
# Check the basis elements
655
for a in range(dim):
656
if other_et(p_mapping(2**a)) != self_et(2**a):
657
preserved = False
658
break
659
if not preserved:
660
continue
661
662
# Check all elements
663
for x in range(v):
664
if other_et(p_mapping(x)) != self_et(x):
665
preserved = False
666
break
667
if not preserved:
668
continue
669
670
# Check that p_mapping is linear.
671
if certificate:
672
linear, mapping_matrix = is_linear(dim, p_mapping, certificate)
673
else:
674
linear = is_linear(dim, p_mapping)
675
# We only need to find one linear p_mapping that preserves other.
676
if linear:
677
break
678
679
if certificate:
680
return (True, mapping_matrix) if linear else (False, None)
681
else:
682
return linear
683
684
685
def linear_code(self):
686
r"""
687
Return the Boolean linear code corresponding to ``self``.
688
689
INPUT:
690
691
- ``self`` -- the current object.
692
693
OUTPUT:
694
695
An object of class ``LinearCode`` representing the Boolean linear code
696
corresponding to self.
697
698
EXAMPLES:
699
700
::
701
702
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
703
sage: bf2 = BooleanFunctionImproved([0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,1])
704
sage: bf2.algebraic_normal_form()
705
x0*x1*x2*x3 + x0*x1 + x0*x2*x3 + x0 + x1*x3 + x2*x3 + x3
706
sage: c2 = bf2.linear_code()
707
sage: c2.generator_matrix().echelon_form()
708
[1 0 0 0 1]
709
[0 1 0 0 0]
710
[0 0 1 0 0]
711
[0 0 0 1 1]
712
713
REFERENCES:
714
715
.. Carlet [Car2010]_ Section 8.6.
716
717
.. Ding [Ding2015]_ Corollary 10.
718
719
"""
720
dim = self.nvariables()
721
f = self.extended_translate()
722
return boolean_linear_code(dim, f)
723
724
725
def save_as_csv(self, file_name):
726
"""
727
Save the current object as a csv file.
728
729
INPUT:
730
731
- ``self`` -- the current object.
732
- ``file_name`` -- the file name.
733
734
OUTPUT:
735
736
None.
737
738
EXAMPLES:
739
740
::
741
742
sage: import csv
743
sage: import os
744
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
745
sage: bf2 = BooleanFunctionImproved([0,1,0,1])
746
sage: bf2_csv_name = tmp_filename(ext='.csv')
747
sage: bf2.save_as_csv(bf2_csv_name)
748
sage: with open(bf2_csv_name) as bf2_csv_file:
749
....: reader = csv.DictReader(bf2_csv_file)
750
....: for row in reader:
751
....: print(row["nvariables"], row["tt_hex"])
752
....:
753
2 a
754
sage: os.remove(bf2_csv_name)
755
"""
756
fieldnames = [
757
"nvariables",
758
"tt_hex"]
759
with open(file_name,"w") as file:
760
writer = csv.DictWriter(file, fieldnames=fieldnames)
761
writer.writeheader()
762
writer.writerow({
763
"nvariables":
764
self.nvariables(),
765
"tt_hex":
766
self.tt_hex()})
767
768
769
def tt_buffer(self):
770
r"""
771
Return a buffer containing a compressed version of the truth table.
772
773
INPUT:
774
775
- ``self`` -- the current object.
776
777
OUTPUT:
778
779
A buffer containing a compressed version of the truth table of ``self``.
780
781
EXAMPLES:
782
783
::
784
785
sage: import binascii
786
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
787
sage: bf2 = BooleanFunctionImproved([0,1,0,0])
788
sage: buff_bf2 = bf2.tt_buffer()
789
sage: type(buff_bf2)
790
<class 'bytes'>
791
sage: encoding = "UTF-8"
792
sage: print(str(binascii.b2a_hex(buff_bf2), encoding))
793
02
794
795
TESTS:
796
797
::
798
799
sage: bf3 = BooleanFunctionImproved([0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,1])
800
sage: buff_bf3 = bf3.tt_buffer()
801
sage: type(buff_bf3)
802
<class 'bytes'>
803
sage: encoding = "UTF-8"
804
sage: print(str(binascii.b2a_hex(buff_bf3), encoding))
805
c122
806
sage: from_buff_bf3 = BooleanFunctionImproved.from_tt_buffer(3, buff_bf3)
807
sage: from_buff_bf3 == buff_bf3
808
False
809
sage: from_buff_bf3 == bf3
810
True
811
sage: hex_str6 = "0123456789112345678921234567893123456789412345678951234567896123"
812
sage: bf6 = BooleanFunctionImproved(hex_str6)
813
sage: buff_bf6 = bf6.tt_buffer()
814
sage: from_buff_bf6 = BooleanFunctionImproved.from_tt_buffer(6, buff_bf6)
815
sage: from_buff_bf6 == bf6
816
True
817
sage: str(binascii.b2a_hex(buff_bf6), encoding) == hex_str6
818
True
819
"""
820
dim = self.nvariables()
821
822
# Use tt_hex() to otain a string representing the truth table in hex.
823
tt_hex = self.tt_hex()
824
# Pad tt_hex to the correct length for a buffer.
825
tt_string = (
826
"0" + tt_hex
827
if len(tt_hex) < 2
828
else
829
tt_hex)
830
return binascii.a2b_hex(tt_string)
831
832
833
def tt_hex(self):
834
r"""
835
Return a hex string representing the truth table of the Boolean function.
836
837
INPUT:
838
839
- ``self`` -- the current object.
840
841
OUTPUT:
842
843
A string representing the truth table of ``self`` in hex.
844
845
EXAMPLES:
846
847
::
848
849
sage: import binascii
850
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
851
sage: bf2 = BooleanFunctionImproved([0,1,0,0])
852
sage: str_bf2 = bf2.tt_hex()
853
sage: type(str_bf2)
854
<class 'str'>
855
sage: print(str_bf2)
856
2
857
sage: bf3 = BooleanFunctionImproved([0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,1])
858
sage: str_bf3 = bf3.tt_hex()
859
sage: print(str_bf3)
860
c122
861
"""
862
dim = self.nvariables()
863
# Convert the truth table into an integer.
864
ZZ_truth_table_2 = ZZ(self.truth_table(), 2)
865
# Convert the integer to a hex string.
866
tt = ZZ_truth_table_2.str(16)
867
if dim < 2:
868
# If dim < 2 then the truth table in hex fits within 1 hex digit.
869
buffer_len = 1
870
else:
871
# The following code is based on BooleanFunction.truth_table().
872
# Variable tt represents truth_table in hex.
873
# The code does not use truth_table(format='hex') because of
874
# https://trac.sagemath.org/ticket/24282
875
876
# Pad tt so that length in hex digits is a power of 2.
877
# This assumes that dim is at least 2.
878
buffer_len = 1 << (dim - 2)
879
# Pad the tt string to the correct length.
880
padding = "0" * (buffer_len - len(tt))
881
return padding + tt
882
883
884
def weight(self):
885
r"""
886
Return the Hamming weight of ``self``.
887
888
INPUT:
889
890
- ``self`` -- the current object.
891
892
OUTPUT:
893
894
A positive integer giving the number of 1 bits in the truth table of ``self``,
895
in other words, the cardinality of the support of ``self`` as a
896
Boolean function.
897
898
EXAMPLES:
899
900
::
901
902
sage: from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
903
sage: bf1 = BooleanFunctionImproved([0,1,0,0])
904
sage: bf2 = BooleanFunctionImproved([0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,1])
905
sage: bf1.truth_table()
906
(False, True, False, False)
907
sage: bf1.weight()
908
1
909
sage: bf2.truth_table(format='int')
910
(0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1)
911
sage: sum([int(bf2(x)) for x in range(16)])
912
5
913
sage: bf2.weight()
914
5
915
"""
916
return sum(self.truth_table(format='int'))
917
918