1
1
//! Algebraic Normal Form (ANF) representation of Boolean functions.
2
2
3
3
#[ cfg( not( feature = "unsafe_disable_safety_checks" ) ) ]
4
- use crate :: boolean_function_error:: POLYNOMIAL_ANF_TOO_BIG_VAR_COUNT_PANIC_MSG ;
4
+ use crate :: boolean_function_error:: { POLYNOMIAL_ANF_TOO_BIG_VAR_COUNT_PANIC_MSG , XOR_DIFFERENT_VAR_COUNT_PANIC_MSG } ;
5
5
use itertools:: Itertools ;
6
6
use num_bigint:: BigUint ;
7
- use num_traits:: { One , Zero } ;
7
+ use num_traits:: { FromPrimitive , One , ToPrimitive , Zero } ;
8
8
use std:: fmt:: Display ;
9
+ use std:: ops:: { BitXor , BitXorAssign } ;
9
10
use fast_boolean_anf_transform:: fast_bool_anf_transform_unsigned;
10
11
use crate :: { BigBooleanFunction , BooleanFunction , BooleanFunctionError , SmallBooleanFunction } ;
11
12
use crate :: utils:: fast_anf_transform_biguint;
@@ -149,7 +150,14 @@ impl AnfPolynomial {
149
150
num_variables,
150
151
} ;
151
152
153
+ if anf_polynomial. is_empty ( ) {
154
+ return Ok ( anf_polynomial_obj) ;
155
+ }
156
+
152
157
for monomial_string in anf_polynomial_filtered. split ( '+' ) {
158
+ if monomial_string == "0" {
159
+ continue ;
160
+ }
153
161
if monomial_string == "1" {
154
162
anf_polynomial_obj. flip_bit_pos ( 0 ) ?;
155
163
continue ;
@@ -253,6 +261,52 @@ impl Into<BooleanFunction> for AnfPolynomial {
253
261
}
254
262
}
255
263
264
+ impl Into < String > for AnfPolynomial {
265
+ fn into ( self ) -> String {
266
+ self . to_string ( )
267
+ }
268
+ }
269
+
270
+ /// In-place XOR operator for Boolean functions ANF polynomial
271
+ ///
272
+ /// # Panics
273
+ /// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
274
+ impl BitXorAssign for AnfPolynomial {
275
+ fn bitxor_assign ( & mut self , rhs : Self ) {
276
+ #[ cfg( not( feature = "unsafe_disable_safety_checks" ) ) ]
277
+ if self . num_variables != rhs. num_variables {
278
+ panic ! ( "{}" , XOR_DIFFERENT_VAR_COUNT_PANIC_MSG ) ;
279
+ }
280
+ match ( & mut self . polynomial , rhs. polynomial ) {
281
+ ( PolynomialFormat :: Small ( self_poly) , PolynomialFormat :: Small ( rhs_poly) ) => {
282
+ * self_poly ^= rhs_poly;
283
+ } ,
284
+ ( PolynomialFormat :: Big ( self_poly) , PolynomialFormat :: Small ( rhs_poly) ) => {
285
+ * self_poly ^= BigUint :: from_u64 ( rhs_poly) . unwrap ( ) ;
286
+ } ,
287
+ ( PolynomialFormat :: Small ( self_poly) , PolynomialFormat :: Big ( rhs_poly) ) => {
288
+ * self_poly ^= rhs_poly. to_u64 ( ) . unwrap ( ) ;
289
+ } ,
290
+ ( PolynomialFormat :: Big ( self_poly) , PolynomialFormat :: Big ( rhs_poly) ) => {
291
+ * self_poly ^= rhs_poly;
292
+ } ,
293
+ }
294
+ }
295
+ }
296
+
297
+ /// XOR operator for Boolean functions ANF polynomial
298
+ ///
299
+ /// # Panics
300
+ /// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
301
+ impl BitXor for AnfPolynomial {
302
+ type Output = AnfPolynomial ;
303
+
304
+ fn bitxor ( mut self , rhs : Self ) -> Self :: Output {
305
+ self ^= rhs;
306
+ self
307
+ }
308
+ }
309
+
256
310
#[ cfg( test) ]
257
311
mod tests {
258
312
use crate :: anf_polynom:: AnfPolynomial ;
@@ -360,6 +414,11 @@ mod tests {
360
414
assert_eq ! ( anf_polynomial. to_string( ) , "x0*x1 + x0 + x2" ) ;
361
415
assert_eq ! ( anf_polynomial. get_boolean_function_type( ) , crate :: BooleanFunctionType :: Small ) ;
362
416
417
+ let anf_str = "x2 + x0*x1 + x0 + 0 + 0" ;
418
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 3 ) . unwrap ( ) ;
419
+ assert_eq ! ( anf_polynomial. to_string( ) , "x0*x1 + x0 + x2" ) ;
420
+ assert_eq ! ( anf_polynomial. get_boolean_function_type( ) , crate :: BooleanFunctionType :: Small ) ;
421
+
363
422
let anf_str = "x0*x1 + x2 + x0 + 1" ;
364
423
let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 2 ) ;
365
424
assert ! ( anf_polynomial. is_err( ) ) ;
@@ -389,6 +448,31 @@ mod tests {
389
448
let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 8 ) ;
390
449
assert ! ( anf_polynomial. is_err( ) ) ;
391
450
assert_eq ! ( anf_polynomial. unwrap_err( ) , BooleanFunctionError :: ErrorParsingAnfString ) ;
451
+
452
+ let anf_str = "" ;
453
+ let polynomial = AnfPolynomial :: from_str ( anf_str, 3 ) . unwrap ( ) ;
454
+ let boolean_function = polynomial. to_boolean_function ( ) ;
455
+ assert_eq ! ( boolean_function. printable_hex_truth_table( ) , "00" ) ;
456
+
457
+ let anf_str = "0" ;
458
+ let polynomial = AnfPolynomial :: from_str ( anf_str, 3 ) . unwrap ( ) ;
459
+ let boolean_function = polynomial. to_boolean_function ( ) ;
460
+ assert_eq ! ( boolean_function. printable_hex_truth_table( ) , "00" ) ;
461
+
462
+ let anf_str = "" ;
463
+ let polynomial = AnfPolynomial :: from_str ( anf_str, 7 ) . unwrap ( ) ;
464
+ let boolean_function = polynomial. to_boolean_function ( ) ;
465
+ assert_eq ! ( boolean_function. printable_hex_truth_table( ) , "00000000000000000000000000000000" ) ;
466
+
467
+ let anf_str = "0" ;
468
+ let polynomial = AnfPolynomial :: from_str ( anf_str, 7 ) . unwrap ( ) ;
469
+ let boolean_function = polynomial. to_boolean_function ( ) ;
470
+ assert_eq ! ( boolean_function. printable_hex_truth_table( ) , "00000000000000000000000000000000" ) ;
471
+
472
+ let anf_str = "x0*x0" ;
473
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 3 ) . unwrap ( ) ;
474
+ assert_eq ! ( anf_polynomial. to_string( ) , "x0" ) ;
475
+ assert_eq ! ( anf_polynomial. get_boolean_function_type( ) , crate :: BooleanFunctionType :: Small ) ;
392
476
}
393
477
394
478
#[ test]
@@ -408,4 +492,21 @@ mod tests {
408
492
let boolean_function = anf_polynomial. to_boolean_function ( ) ;
409
493
assert_eq ! ( boolean_function. printable_hex_truth_table( ) , "7fffffffffffffffffffffffffffffff80000000000000000000000000000000" ) ;
410
494
}
495
+
496
+ #[ test]
497
+ fn test_xor ( ) {
498
+ let anf_1 = AnfPolynomial :: from_str ( "x0*x1*x4*x7 + x2*x3 + x1 + 0" , 8 ) . unwrap ( ) ;
499
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x1*x2*x4*x7 + x2*x3 + x3 + 1" , 8 ) . unwrap ( ) ;
500
+ let anf_3 = anf_1. clone ( ) ^ anf_2. clone ( ) ;
501
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2*x4*x7 + x0*x1*x4*x7 + x1 + x3 + 1" ) ;
502
+ anf_2 ^= anf_1;
503
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2*x4*x7 + x0*x1*x4*x7 + x1 + x3 + 1" ) ;
504
+
505
+ let anf_1 = AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 8 ) . unwrap ( ) ;
506
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x1*x2 + x0*x2 + x1*x0 + x1 + 1" , 8 ) . unwrap ( ) ;
507
+ let anf_3 = anf_1. clone ( ) ^ anf_2. clone ( ) ;
508
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2 + x0*x2 + x0 + x2 + 1" ) ;
509
+ anf_2 ^= anf_1;
510
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2 + x0*x2 + x0 + x2 + 1" ) ;
511
+ }
411
512
}
0 commit comments