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 , XOR_DIFFERENT_VAR_COUNT_PANIC_MSG } ;
4
+ use crate :: boolean_function_error:: { POLYNOMIAL_ANF_TOO_BIG_VAR_COUNT_PANIC_MSG , XOR_DIFFERENT_VAR_COUNT_PANIC_MSG , AND_DIFFERENT_VAR_COUNT_PANIC_MSG } ;
5
5
use itertools:: Itertools ;
6
6
use num_bigint:: BigUint ;
7
7
use num_traits:: { FromPrimitive , One , ToPrimitive , Zero } ;
8
8
use std:: fmt:: Display ;
9
- use std:: ops:: { BitXor , BitXorAssign } ;
9
+ use std:: ops:: { BitAnd , BitAndAssign , BitXor , BitXorAssign } ;
10
10
use fast_boolean_anf_transform:: fast_bool_anf_transform_unsigned;
11
11
use crate :: { BigBooleanFunction , BooleanFunction , BooleanFunctionError , SmallBooleanFunction } ;
12
12
use crate :: utils:: fast_anf_transform_biguint;
@@ -277,12 +277,12 @@ impl BitXorAssign for AnfPolynomial {
277
277
if self . num_variables != rhs. num_variables {
278
278
panic ! ( "{}" , XOR_DIFFERENT_VAR_COUNT_PANIC_MSG ) ;
279
279
}
280
- match ( & mut self . polynomial , rhs. polynomial ) {
280
+ match ( & mut self . polynomial , & rhs. polynomial ) {
281
281
( PolynomialFormat :: Small ( self_poly) , PolynomialFormat :: Small ( rhs_poly) ) => {
282
282
* self_poly ^= rhs_poly;
283
283
} ,
284
284
( PolynomialFormat :: Big ( self_poly) , PolynomialFormat :: Small ( rhs_poly) ) => {
285
- * self_poly ^= BigUint :: from_u64 ( rhs_poly) . unwrap ( ) ;
285
+ * self_poly ^= BigUint :: from_u64 ( * rhs_poly) . unwrap ( ) ;
286
286
} ,
287
287
( PolynomialFormat :: Small ( self_poly) , PolynomialFormat :: Big ( rhs_poly) ) => {
288
288
* self_poly ^= rhs_poly. to_u64 ( ) . unwrap ( ) ;
@@ -307,6 +307,90 @@ impl BitXor for AnfPolynomial {
307
307
}
308
308
}
309
309
310
+ /// In-place AND operator for Boolean functions ANF polynomial
311
+ ///
312
+ /// # Panics
313
+ /// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
314
+ impl BitAndAssign for AnfPolynomial {
315
+ fn bitand_assign ( & mut self , rhs : Self ) {
316
+ * self = self . clone ( ) & rhs;
317
+ }
318
+ }
319
+
320
+ /// AND operator for Boolean functions ANF polynomial
321
+ ///
322
+ /// # Panics
323
+ /// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
324
+ impl BitAnd for AnfPolynomial {
325
+ type Output = AnfPolynomial ;
326
+
327
+ fn bitand ( self , rhs : Self ) -> Self :: Output {
328
+ #[ cfg( not( feature = "unsafe_disable_safety_checks" ) ) ]
329
+ if self . num_variables != rhs. num_variables {
330
+ panic ! ( "{}" , AND_DIFFERENT_VAR_COUNT_PANIC_MSG ) ;
331
+ }
332
+
333
+ fn small_anf_polynomial_multiply ( left_poly : u64 , right_poly : u64 , num_variables : usize ) -> u64 {
334
+ let mut res = 0u64 ;
335
+ for left_bit_pos in 0u64 ..( 1 << num_variables) {
336
+ if ( left_poly >> left_bit_pos) & 1 == 0 {
337
+ continue ;
338
+ }
339
+ for right_bit_pos in 0u64 ..( 1 << num_variables) {
340
+ if ( right_poly >> right_bit_pos) & 1 == 0 {
341
+ continue ;
342
+ }
343
+ res ^= 1 << ( left_bit_pos | right_bit_pos) ;
344
+ }
345
+ }
346
+ res
347
+ }
348
+
349
+ fn big_anf_polynomial_multiply ( left_poly : & BigUint , right_poly : & BigUint , num_variables : usize ) -> BigUint {
350
+ let mut res = BigUint :: zero ( ) ;
351
+ for left_bit_pos in 0u64 ..( 1 << num_variables) {
352
+ if !left_poly. bit ( left_bit_pos) {
353
+ continue ;
354
+ }
355
+ for right_bit_pos in 0u64 ..( 1 << num_variables) {
356
+ if !right_poly. bit ( right_bit_pos) {
357
+ continue ;
358
+ }
359
+ let pos_to_flip = left_bit_pos | right_bit_pos;
360
+ res. set_bit ( pos_to_flip, !res. bit ( pos_to_flip) ) ;
361
+ }
362
+ }
363
+ res
364
+ }
365
+
366
+ let new_polynomial = match ( self . polynomial , rhs. polynomial ) {
367
+ ( PolynomialFormat :: Small ( self_poly) , PolynomialFormat :: Small ( rhs_poly) ) => {
368
+ PolynomialFormat :: Small ( small_anf_polynomial_multiply ( self_poly, rhs_poly, self . num_variables ) )
369
+ } ,
370
+ ( PolynomialFormat :: Big ( self_poly) , PolynomialFormat :: Small ( rhs_poly) ) => {
371
+ PolynomialFormat :: Big (
372
+ BigUint :: from_u64 (
373
+ small_anf_polynomial_multiply ( self_poly. to_u64 ( ) . unwrap ( ) , rhs_poly, self . num_variables )
374
+ ) . unwrap ( )
375
+ )
376
+ } ,
377
+ ( PolynomialFormat :: Small ( self_poly) , PolynomialFormat :: Big ( rhs_poly) ) => {
378
+ PolynomialFormat :: Small (
379
+ small_anf_polynomial_multiply ( self_poly, rhs_poly. to_u64 ( ) . unwrap ( ) , self . num_variables )
380
+ )
381
+ } ,
382
+ ( PolynomialFormat :: Big ( self_poly) , PolynomialFormat :: Big ( rhs_poly) ) => {
383
+ PolynomialFormat :: Big ( big_anf_polynomial_multiply ( & self_poly, & rhs_poly, self . num_variables ) )
384
+ }
385
+ } ;
386
+
387
+ AnfPolynomial {
388
+ polynomial : new_polynomial,
389
+ num_variables : self . num_variables
390
+ }
391
+ }
392
+ }
393
+
310
394
#[ cfg( test) ]
311
395
mod tests {
312
396
use crate :: anf_polynom:: AnfPolynomial ;
@@ -502,11 +586,105 @@ mod tests {
502
586
anf_2 ^= anf_1;
503
587
assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2*x4*x7 + x0*x1*x4*x7 + x1 + x3 + 1" ) ;
504
588
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 ( ) ;
589
+ let anf_1 = AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ;
590
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x1*x2 + x0*x2 + x1*x0 + x1 + 1" , 3 ) . unwrap ( ) ;
507
591
let anf_3 = anf_1. clone ( ) ^ anf_2. clone ( ) ;
508
592
assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2 + x0*x2 + x0 + x2 + 1" ) ;
509
593
anf_2 ^= anf_1;
510
594
assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2 + x0*x2 + x0 + x2 + 1" ) ;
511
595
}
596
+
597
+ #[ test]
598
+ fn test_and ( ) {
599
+ let anf_1 = AnfPolynomial :: from_str ( "x0*x1" , 3 ) . unwrap ( ) ;
600
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x2" , 3 ) . unwrap ( ) ;
601
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
602
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2" ) ;
603
+ anf_2 &= anf_1;
604
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2" ) ;
605
+
606
+ let anf_1 = AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ;
607
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x1 + x0*x1*x2 + x1 + 1" , 3 ) . unwrap ( ) ;
608
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
609
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2 + x1*x2 + x0 + x2" ) ;
610
+ anf_2 &= anf_1;
611
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2 + x1*x2 + x0 + x2" ) ;
612
+
613
+ let anf_1 = AnfPolynomial :: from_str ( "x0*x1 + x0*x1*x2 + x1 + 1" , 3 ) . unwrap ( ) ;
614
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ;
615
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
616
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2 + x1*x2 + x0 + x2" ) ;
617
+ anf_2 &= anf_1;
618
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2 + x1*x2 + x0 + x2" ) ;
619
+
620
+ let anf_1 = AnfPolynomial :: from_str ( "x3*x2*x1 + x0*x1 + x0*x1*x2 + x1 + 1" , 4 ) . unwrap ( ) ;
621
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x2*x3 + x0*x1 + x0 + x1 + x2" , 4 ) . unwrap ( ) ;
622
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
623
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2 + x0*x2*x3 + x1*x2 + x0 + x2" ) ;
624
+ anf_2 &= anf_1;
625
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2 + x0*x2*x3 + x1*x2 + x0 + x2" ) ;
626
+
627
+ let anf_1 = AnfPolynomial :: from_str ( "x3*x2*x1 + x0*x1 + x0*x1*x2 + x1 + 1" , 8 ) . unwrap ( ) ;
628
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x2*x3 + x0*x1 + x0 + x1 + x2" , 8 ) . unwrap ( ) ;
629
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
630
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2 + x0*x2*x3 + x1*x2 + x0 + x2" ) ;
631
+ anf_2 &= anf_1;
632
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2 + x0*x2*x3 + x1*x2 + x0 + x2" ) ;
633
+
634
+ let anf_1 = AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ;
635
+ let mut anf_2 = AnfPolynomial :: from_str ( "0" , 3 ) . unwrap ( ) ;
636
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
637
+ assert_eq ! ( anf_3. to_string( ) , "0" ) ;
638
+ anf_2 &= anf_1;
639
+ assert_eq ! ( anf_2. to_string( ) , "0" ) ;
640
+
641
+ let anf_1 = AnfPolynomial :: from_str ( "0" , 3 ) . unwrap ( ) ;
642
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ;
643
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
644
+ assert_eq ! ( anf_3. to_string( ) , "0" ) ;
645
+ anf_2 &= anf_1;
646
+ assert_eq ! ( anf_2. to_string( ) , "0" ) ;
647
+
648
+ let anf_1 = AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ;
649
+ let mut anf_2 = AnfPolynomial :: from_str ( "1" , 3 ) . unwrap ( ) ;
650
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
651
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1 + x0 + x1 + x2" ) ;
652
+ anf_2 &= anf_1;
653
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1 + x0 + x1 + x2" ) ;
654
+
655
+ let anf_1 = AnfPolynomial :: from_str ( "1" , 3 ) . unwrap ( ) ;
656
+ let mut anf_2 = AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ;
657
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
658
+ assert_eq ! ( anf_3. to_string( ) , "x0*x1 + x0 + x1 + x2" ) ;
659
+ anf_2 &= anf_1;
660
+ assert_eq ! ( anf_2. to_string( ) , "x0*x1 + x0 + x1 + x2" ) ;
661
+
662
+ let anf_1 = AnfPolynomial :: from_str ( "x3*x7 + x3 + x4*x5 + x4*x6 + x5*x6*x7 + x6 + x7 + 1" , 8 ) . unwrap ( ) ;
663
+ let mut anf_2 = AnfPolynomial :: from_str ( "x3*x5*x6*x7 + x3*x6*x7 + x3*x6 + x3*x7 + x3 + x4*x5*x6 + x4*x5*x7 + x4*x7 + x4 + x6*x7 + x6 + x7 + 1" , 8 ) . unwrap ( ) ;
664
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
665
+ assert_eq ! ( anf_3. to_string( ) , "x3*x4*x5*x7 + x3*x4*x5 + x4*x5*x6 + x3*x4*x7 + x4*x5*x7 + x3*x6*x7 + x3*x4 + x3*x6 + x3*x7 + x4*x7 + x6*x7 + x3 + x4 + x6 + x7 + 1" ) ;
666
+ anf_2 &= anf_1;
667
+ assert_eq ! ( anf_2. to_string( ) , "x3*x4*x5*x7 + x3*x4*x5 + x4*x5*x6 + x3*x4*x7 + x4*x5*x7 + x3*x6*x7 + x3*x4 + x3*x6 + x3*x7 + x4*x7 + x6*x7 + x3 + x4 + x6 + x7 + 1" ) ;
668
+
669
+ let anf_1 = AnfPolynomial :: from_str ( "x3*x5*x6*x7 + x3*x6*x7 + x3*x6 + x3*x7 + x3 + x4*x5*x6 + x4*x5*x7 + x4*x7 + x4 + x6*x7 + x6 + x7 + 1" , 8 ) . unwrap ( ) ;
670
+ let mut anf_2 = AnfPolynomial :: from_str ( "x3*x7 + x3 + x4*x5 + x4*x6 + x5*x6*x7 + x6 + x7 + 1" , 8 ) . unwrap ( ) ;
671
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
672
+ assert_eq ! ( anf_3. to_string( ) , "x3*x4*x5*x7 + x3*x4*x5 + x4*x5*x6 + x3*x4*x7 + x4*x5*x7 + x3*x6*x7 + x3*x4 + x3*x6 + x3*x7 + x4*x7 + x6*x7 + x3 + x4 + x6 + x7 + 1" ) ;
673
+ anf_2 &= anf_1;
674
+ assert_eq ! ( anf_2. to_string( ) , "x3*x4*x5*x7 + x3*x4*x5 + x4*x5*x6 + x3*x4*x7 + x4*x5*x7 + x3*x6*x7 + x3*x4 + x3*x6 + x3*x7 + x4*x7 + x6*x7 + x3 + x4 + x6 + x7 + 1" ) ;
675
+
676
+ let anf_1 = AnfPolynomial :: from_str ( "0" , 8 ) . unwrap ( ) ;
677
+ let mut anf_2 = AnfPolynomial :: from_str ( "x3*x7 + x3 + x4*x5 + x4*x6 + x5*x6*x7 + x6 + x7 + 1" , 8 ) . unwrap ( ) ;
678
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
679
+ assert_eq ! ( anf_3. to_string( ) , "0" ) ;
680
+ anf_2 &= anf_1;
681
+ assert_eq ! ( anf_2. to_string( ) , "0" ) ;
682
+
683
+ let anf_1 = AnfPolynomial :: from_str ( "1" , 8 ) . unwrap ( ) ;
684
+ let mut anf_2 = AnfPolynomial :: from_str ( "x3*x7 + x3 + x4*x5 + x4*x6 + x5*x6*x7 + x6 + x7 + 1" , 8 ) . unwrap ( ) ;
685
+ let anf_3 = anf_1. clone ( ) & anf_2. clone ( ) ;
686
+ assert_eq ! ( anf_3. to_string( ) , "x5*x6*x7 + x4*x5 + x4*x6 + x3*x7 + x3 + x6 + x7 + 1" ) ;
687
+ anf_2 &= anf_1;
688
+ assert_eq ! ( anf_2. to_string( ) , "x5*x6*x7 + x4*x5 + x4*x6 + x3*x7 + x3 + x6 + x7 + 1" ) ;
689
+ }
512
690
}
0 commit comments