11//! Algebraic Normal Form (ANF) representation of Boolean functions.
22
33#[ 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 } ;
55use itertools:: Itertools ;
66use num_bigint:: BigUint ;
77use num_traits:: { FromPrimitive , One , ToPrimitive , Zero } ;
88use std:: fmt:: Display ;
9- use std:: ops:: { BitXor , BitXorAssign } ;
9+ use std:: ops:: { BitAnd , BitAndAssign , BitXor , BitXorAssign } ;
1010use fast_boolean_anf_transform:: fast_bool_anf_transform_unsigned;
1111use crate :: { BigBooleanFunction , BooleanFunction , BooleanFunctionError , SmallBooleanFunction } ;
1212use crate :: utils:: fast_anf_transform_biguint;
@@ -277,12 +277,12 @@ impl BitXorAssign for AnfPolynomial {
277277 if self . num_variables != rhs. num_variables {
278278 panic ! ( "{}" , XOR_DIFFERENT_VAR_COUNT_PANIC_MSG ) ;
279279 }
280- match ( & mut self . polynomial , rhs. polynomial ) {
280+ match ( & mut self . polynomial , & rhs. polynomial ) {
281281 ( PolynomialFormat :: Small ( self_poly) , PolynomialFormat :: Small ( rhs_poly) ) => {
282282 * self_poly ^= rhs_poly;
283283 } ,
284284 ( 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 ( ) ;
286286 } ,
287287 ( PolynomialFormat :: Small ( self_poly) , PolynomialFormat :: Big ( rhs_poly) ) => {
288288 * self_poly ^= rhs_poly. to_u64 ( ) . unwrap ( ) ;
@@ -307,6 +307,90 @@ impl BitXor for AnfPolynomial {
307307 }
308308}
309309
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+
310394#[ cfg( test) ]
311395mod tests {
312396 use crate :: anf_polynom:: AnfPolynomial ;
@@ -502,11 +586,105 @@ mod tests {
502586 anf_2 ^= anf_1;
503587 assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2*x4*x7 + x0*x1*x4*x7 + x1 + x3 + 1" ) ;
504588
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 ( ) ;
507591 let anf_3 = anf_1. clone ( ) ^ anf_2. clone ( ) ;
508592 assert_eq ! ( anf_3. to_string( ) , "x0*x1*x2 + x0*x2 + x0 + x2 + 1" ) ;
509593 anf_2 ^= anf_1;
510594 assert_eq ! ( anf_2. to_string( ) , "x0*x1*x2 + x0*x2 + x0 + x2 + 1" ) ;
511595 }
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+ }
512690}
0 commit comments