@@ -617,6 +617,40 @@ pub trait BooleanFunctionImpl: Debug {
617617 . count ( )
618618 }
619619
620+ /// Checks if the Boolean function is left-permutive.
621+ ///
622+ /// A Boolean function is left-permutive if changing the left-most input bit always changes the output.
623+ fn is_left_permutive ( & self ) -> bool {
624+ let num_variables = self . variables_count ( ) ;
625+ let max_input_value = self . get_max_input_value ( ) ;
626+ let left_most_bit_mask = 1 << ( num_variables - 1 ) ;
627+ ( 0 ..=max_input_value >> 1 )
628+ . into_iter ( )
629+ . all ( |x| {
630+ self . compute_cellular_automata_rule ( x) != self . compute_cellular_automata_rule ( x | left_most_bit_mask)
631+ } )
632+ }
633+
634+ /// Checks if the Boolean function is right-permutive.
635+ ///
636+ /// A Boolean function is right-permutive if changing the right-most input bit always changes the output.
637+ fn is_right_permutive ( & self ) -> bool {
638+ let max_input_value = self . get_max_input_value ( ) ;
639+ let right_most_bit_mask = 1 ;
640+ ( 0 ..=max_input_value >> 1 )
641+ . into_iter ( )
642+ . all ( |x| {
643+ self . compute_cellular_automata_rule ( x << 1 ) != self . compute_cellular_automata_rule ( ( x << 1 ) | right_most_bit_mask)
644+ } )
645+ }
646+
647+ /// Checks if the Boolean function is bipermutive.
648+ ///
649+ /// A Boolean function is bipermutive if it is both left-permutive and right-permutive.
650+ fn is_bipermutive ( & self ) -> bool {
651+ self . is_left_permutive ( ) && self . is_right_permutive ( )
652+ }
653+
620654 /// Returns a 1-local neighbor of the Boolean function, at a specific position
621655 ///
622656 /// A 1-local neighbor of a Boolean function $f$ at position $i$ is a Boolean function $f_i$ such that:
@@ -2632,4 +2666,67 @@ mod tests {
26322666 let boolean_function = BooleanFunction :: from_anf_polynomial ( & anf) ;
26332667 assert_eq ! ( boolean_function. printable_hex_truth_table( ) , "7fffffffffffffffffffffffffffffff80000000000000000000000000000000" ) ;
26342668 }
2669+
2670+ #[ test]
2671+ fn test_is_left_permutive ( ) {
2672+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2673+ assert ! ( boolean_function. is_left_permutive( ) ) ;
2674+
2675+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2676+ assert ! ( boolean_function. is_left_permutive( ) ) ;
2677+
2678+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x2*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2679+ assert ! ( !boolean_function. is_left_permutive( ) ) ;
2680+
2681+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "ff" ) . unwrap ( ) ;
2682+ assert ! ( !boolean_function. is_left_permutive( ) ) ;
2683+
2684+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "00" ) . unwrap ( ) ;
2685+ assert ! ( !boolean_function. is_left_permutive( ) ) ;
2686+
2687+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "0f" ) . unwrap ( ) ;
2688+ assert ! ( boolean_function. is_left_permutive( ) ) ;
2689+ }
2690+
2691+ #[ test]
2692+ fn test_is_right_permutive ( ) {
2693+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2694+ assert ! ( boolean_function. is_right_permutive( ) ) ;
2695+
2696+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2697+ assert ! ( !boolean_function. is_right_permutive( ) ) ;
2698+
2699+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x2*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2700+ assert ! ( boolean_function. is_right_permutive( ) ) ;
2701+
2702+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "ff" ) . unwrap ( ) ;
2703+ assert ! ( !boolean_function. is_right_permutive( ) ) ;
2704+
2705+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "00" ) . unwrap ( ) ;
2706+ assert ! ( !boolean_function. is_right_permutive( ) ) ;
2707+
2708+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "0f" ) . unwrap ( ) ;
2709+ assert ! ( !boolean_function. is_right_permutive( ) ) ;
2710+ }
2711+
2712+ #[ test]
2713+ fn test_is_bipermutive ( ) {
2714+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2715+ assert ! ( boolean_function. is_bipermutive( ) ) ;
2716+
2717+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x0*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2718+ assert ! ( !boolean_function. is_bipermutive( ) ) ;
2719+
2720+ let boolean_function = BooleanFunction :: from_anf_polynomial ( & AnfPolynomial :: from_str ( "x2*x1 + x0 + x1 + x2" , 3 ) . unwrap ( ) ) ;
2721+ assert ! ( !boolean_function. is_bipermutive( ) ) ;
2722+
2723+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "ff" ) . unwrap ( ) ;
2724+ assert ! ( !boolean_function. is_bipermutive( ) ) ;
2725+
2726+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "00" ) . unwrap ( ) ;
2727+ assert ! ( !boolean_function. is_bipermutive( ) ) ;
2728+
2729+ let boolean_function = BooleanFunction :: from_hex_string_truth_table ( "0f" ) . unwrap ( ) ;
2730+ assert ! ( !boolean_function. is_bipermutive( ) ) ;
2731+ }
26352732}
0 commit comments