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 ;
4+ use crate :: boolean_function_error:: { POLYNOMIAL_ANF_TOO_BIG_VAR_COUNT_PANIC_MSG , XOR_DIFFERENT_VAR_COUNT_PANIC_MSG } ;
55use itertools:: Itertools ;
66use num_bigint:: BigUint ;
7- use num_traits:: { One , Zero } ;
7+ use num_traits:: { FromPrimitive , One , ToPrimitive , Zero } ;
88use std:: fmt:: Display ;
9+ use std:: ops:: { BitXor , BitXorAssign } ;
910use fast_boolean_anf_transform:: fast_bool_anf_transform_unsigned;
1011use crate :: { BigBooleanFunction , BooleanFunction , BooleanFunctionError , SmallBooleanFunction } ;
1112use crate :: utils:: fast_anf_transform_biguint;
@@ -149,7 +150,14 @@ impl AnfPolynomial {
149150 num_variables,
150151 } ;
151152
153+ if anf_polynomial. is_empty ( ) {
154+ return Ok ( anf_polynomial_obj) ;
155+ }
156+
152157 for monomial_string in anf_polynomial_filtered. split ( '+' ) {
158+ if monomial_string == "0" {
159+ continue ;
160+ }
153161 if monomial_string == "1" {
154162 anf_polynomial_obj. flip_bit_pos ( 0 ) ?;
155163 continue ;
@@ -253,6 +261,52 @@ impl Into<BooleanFunction> for AnfPolynomial {
253261 }
254262}
255263
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+
256310#[ cfg( test) ]
257311mod tests {
258312 use crate :: anf_polynom:: AnfPolynomial ;
@@ -360,6 +414,11 @@ mod tests {
360414 assert_eq ! ( anf_polynomial. to_string( ) , "x0*x1 + x0 + x2" ) ;
361415 assert_eq ! ( anf_polynomial. get_boolean_function_type( ) , crate :: BooleanFunctionType :: Small ) ;
362416
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+
363422 let anf_str = "x0*x1 + x2 + x0 + 1" ;
364423 let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 2 ) ;
365424 assert ! ( anf_polynomial. is_err( ) ) ;
@@ -389,6 +448,31 @@ mod tests {
389448 let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 8 ) ;
390449 assert ! ( anf_polynomial. is_err( ) ) ;
391450 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 ) ;
392476 }
393477
394478 #[ test]
@@ -408,4 +492,21 @@ mod tests {
408492 let boolean_function = anf_polynomial. to_boolean_function ( ) ;
409493 assert_eq ! ( boolean_function. printable_hex_truth_table( ) , "7fffffffffffffffffffffffffffffff80000000000000000000000000000000" ) ;
410494 }
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+ }
411512}
0 commit comments