1use crate::anf_polynom::AnfPolynomial;
2#[cfg(not(feature = "unsafe_disable_safety_checks"))]
3use crate::boolean_function_error::TRUTH_TABLE_TOO_BIG_VAR_COUNT_PANIC_MSG;
4#[cfg(not(feature = "unsafe_disable_safety_checks"))]
5use crate::boolean_function_error::{XOR_DIFFERENT_VAR_COUNT_PANIC_MSG, AND_DIFFERENT_VAR_COUNT_PANIC_MSG};
6use crate::iterator::{BigCloseBalancedFunctionIterator, BooleanFunctionIterator, CloseBalancedFunctionIterator};
7use crate::utils::{fast_anf_transform_biguint, left_kernel_boolean};
8use crate::{BooleanFunction, BooleanFunctionError, BooleanFunctionImpl, BooleanFunctionType};
9use itertools::{enumerate, Itertools};
10use num_bigint::BigUint;
11use num_integer::binomial;
12use num_traits::{FromPrimitive, One, Zero};
13use std::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Mul, MulAssign, Not};
14use hackfn::hackfn;
15
16#[derive(Debug, Clone, Eq, PartialEq)]
22pub struct BigBooleanFunction {
23 variables_count: usize,
24 truth_table: BigUint,
25}
26
27impl BigBooleanFunction {
28 pub fn from_truth_table(truth_table: BigUint, variables_count: usize) -> Self {
40 #[cfg(not(feature = "unsafe_disable_safety_checks"))]
41 if truth_table.bits() > (1 << variables_count) {
42 panic!("{}", TRUTH_TABLE_TOO_BIG_VAR_COUNT_PANIC_MSG);
43 }
44 #[cfg(not(feature = "unsafe_disable_safety_checks"))]
45 if variables_count > 31 {
46 panic!("Variables count must be less or equal than 31");
47 }
48 BigBooleanFunction {
49 variables_count,
50 truth_table,
51 }
52 }
53
54 pub fn derivative_inner(&self, direction: u32) -> Result<Self, BooleanFunctionError> {
62 #[cfg(not(feature = "unsafe_disable_safety_checks"))]
63 {
64 let max_input_value = self.get_max_input_value();
65 if direction > max_input_value {
66 return Err(BooleanFunctionError::TooBigDerivativeDirection(
67 max_input_value,
68 ));
69 }
70 }
71 let mut derivative_truth_table: BigUint = BigUint::zero();
72 for x in 0..=self.get_max_input_value() {
73 if self.compute_cellular_automata_rule(x)
74 ^ self.compute_cellular_automata_rule(x ^ direction)
75 {
76 derivative_truth_table |= BigUint::one() << x;
77 }
78 }
79 Ok(BigBooleanFunction {
80 variables_count: self.variables_count,
81 truth_table: derivative_truth_table,
82 })
83 }
84
85 pub fn reverse_inner(&self) -> Self {
90 BigBooleanFunction {
91 variables_count: self.variables_count,
92 truth_table: self.truth_table.clone()
93 ^ ((BigUint::one() << (1 << self.variables_count)) - BigUint::one()),
94 }
95 }
96
97 pub fn annihilator_inner(
105 &self,
106 max_degree: Option<usize>,
107 ) -> Option<(BigBooleanFunction, usize, usize)> {
108 let max_degree = max_degree.unwrap_or(self.variables_count);
109 if self.truth_table == BigUint::zero() {
110 let max_possible_function_tt =
111 (BigUint::one() << (1 << self.variables_count)) - BigUint::one();
112 let dim_annihilator_vec_space = (0..=max_degree)
113 .map(|i| binomial(self.variables_count as u64, i as u64))
114 .sum::<u64>() as usize;
115 return Some((
116 Self::from_truth_table(max_possible_function_tt, self.variables_count),
117 0,
118 dim_annihilator_vec_space,
119 ));
120 }
121
122 let truth_table_non_zero_positions = (0u32..(1 << self.variables_count))
123 .filter(|bit_pos| {
124 self.truth_table.clone() & (BigUint::one() << bit_pos) != BigUint::zero()
125 })
126 .collect::<Vec<u32>>();
127
128 let matrix_out_len = (0..=max_degree)
129 .map(|i| binomial(self.variables_count as u64, i as u64))
130 .sum::<u64>() as usize;
131 let matrix_in_len = truth_table_non_zero_positions.len();
132 let mut matrix: Vec<Vec<bool>> = vec![vec![false; matrix_in_len]; matrix_out_len];
133
134 let mut r = [AnfPolynomial::from_anf_big(
135 &BigUint::one(),
136 self.variables_count,
137 )]
138 .to_vec();
139
140 for i in 1..=max_degree {
141 for comb in (0..self.variables_count).combinations(i) {
142 let mut bit_index = 0;
143 for monomial in comb {
144 bit_index |= 1 << monomial;
145 }
146 let anf = BigUint::one() << bit_index;
147 r.push(AnfPolynomial::from_anf_big(&anf, self.variables_count));
148 }
149 }
150
151 for (i, m) in enumerate(r.iter()) {
152 let truth_table =
153 fast_anf_transform_biguint(&m.get_polynomial_big(), self.variables_count); for (j, v) in enumerate(truth_table_non_zero_positions.iter()) {
155 matrix[i][j] = truth_table.bit(*v as u64)
156 }
157 }
158
159 let left_kernel = left_kernel_boolean(&matrix);
160
161 if left_kernel.is_empty() {
162 return None;
163 }
164
165 let annihilator_anf = enumerate(r.iter())
166 .filter(|(i, _)| left_kernel[0][*i])
167 .map(|(_, v)| v.get_polynomial_big())
168 .fold(BigUint::zero(), |mut sum, val| {
169 sum += val;
170 sum
171 });
172
173 let annihilator_function = Self::from_truth_table(
174 fast_anf_transform_biguint(&annihilator_anf, self.variables_count),
175 self.variables_count,
176 );
177
178 let annihilator_degree =
179 AnfPolynomial::from_anf_big(&annihilator_anf, self.variables_count).get_degree();
180
181 Some((annihilator_function, annihilator_degree, left_kernel.len()))
182 }
183
184 pub fn from_walsh_hadamard_values(walsh_values: &[i32]) -> Result<Self, BooleanFunctionError> {
192 let walsh_values_count = walsh_values.len();
193 if walsh_values_count < 4 || walsh_values_count.count_ones() != 1 {
194 return Err(BooleanFunctionError::InvalidWalshValuesCount(
195 walsh_values_count,
196 ));
197 }
198 let num_variables = walsh_values_count.trailing_zeros() as usize;
199 let mut truth_table = BigUint::zero();
200 for i in 0..(1 << num_variables) {
201 let value = walsh_values
202 .iter()
203 .enumerate()
204 .map(|(w, walsh_value)| {
205 walsh_value * (if (w & i).count_ones() & 1 == 0 { 1 } else { -1 })
206 })
207 .sum::<i32>()
208 < 0;
209 if value {
210 truth_table.set_bit(i as u64, true);
211 }
212 }
213 Ok(Self {
214 variables_count: num_variables,
215 truth_table,
216 })
217 }
218
219 pub fn from_walsh_fourier_values(walsh_values: &[i32]) -> Result<Self, BooleanFunctionError> {
227 let walsh_values_count = walsh_values.len();
228 if walsh_values_count < 4 || walsh_values_count.count_ones() != 1 {
229 return Err(BooleanFunctionError::InvalidWalshValuesCount(
230 walsh_values_count,
231 ));
232 }
233 let num_variables = walsh_values_count.trailing_zeros() as usize;
234 let mut truth_table = BigUint::zero();
235 for i in 0..(1 << num_variables) {
236 let value = walsh_values
237 .iter()
238 .enumerate()
239 .map(|(w, walsh_value)| {
240 walsh_value * (if (w & i).count_ones() & 1 == 0 { 1 } else { -1 })
241 })
242 .sum::<i32>()
243 != 0;
244 if value {
245 truth_table.set_bit(i as u64, true);
246 }
247 }
248 Ok(Self {
249 variables_count: num_variables,
250 truth_table,
251 })
252 }
253
254 pub fn get_1_local_neighbor_inner(&self, position: u32) -> Self {
265 #[cfg(not(feature = "unsafe_disable_safety_checks"))]
266 {
267 let max_input_value = self.get_max_input_value();
268 if position > max_input_value {
269 panic!("Position must be less or equal than {}", max_input_value);
270 }
271 }
272 let mut new_truth_table = self.truth_table.clone();
273 new_truth_table.set_bit(position as u64, !new_truth_table.bit(position as u64));
274 Self {
275 variables_count: self.variables_count,
276 truth_table: new_truth_table,
277 }
278 }
279
280 pub fn close_balanced_functions_iterator_inner(&self) -> Result<BigCloseBalancedFunctionIterator, BooleanFunctionError> {
291 if self.is_balanced() {
292 return Err(BooleanFunctionError::AlreadyBalanced);
293 }
294 let ones_count = self.truth_table.count_ones();
295 let zeros_count = (1 << self.variables_count) - ones_count;
296
297 let bits_to_flip_count = (ones_count.abs_diff(zeros_count) / 2) as usize;
298
299 let flippable_positions = if ones_count > zeros_count {
300 (0..(1 << self.variables_count))
301 .filter(|i| self.truth_table.bit(*i as u64))
302 .collect::<Vec<usize>>()
303 } else {
304 (0..(1 << self.variables_count))
305 .filter(|i| !self.truth_table.bit(*i as u64))
306 .collect::<Vec<usize>>()
307 };
308
309 Ok(BigCloseBalancedFunctionIterator::create(self, flippable_positions, bits_to_flip_count))
310 }
311
312 pub fn from_anf_polynomial_str_inner(anf_polynomial: &str, num_variables: usize) -> Result<Self, BooleanFunctionError> {
326 Ok(Self::from_anf_polynomial_inner(
327 &AnfPolynomial::from_str(anf_polynomial, num_variables)?
328 ))
329 }
330
331 pub fn from_anf_polynomial_inner(anf_polynomial: &AnfPolynomial) -> Self {
339 match anf_polynomial.to_boolean_function() {
340 BooleanFunction::Small(small_bf) => BigBooleanFunction::from_truth_table(
341 BigUint::from_u64(small_bf.get_truth_table_u64()).unwrap(), small_bf.variables_count()
342 ),
343 BooleanFunction::Big(big_bf) => big_bf
344 }
345 }
346}
347impl BooleanFunctionImpl for BigBooleanFunction {
348 #[inline]
349 fn variables_count(&self) -> usize {
350 self.variables_count
351 }
352
353 fn get_boolean_function_type(&self) -> BooleanFunctionType {
354 BooleanFunctionType::Big
355 }
356
357 fn is_balanced(&self) -> bool {
358 let expected_set_number: u64 = 1 << (self.variables_count - 1);
359 self.truth_table.count_ones() == expected_set_number
360 }
361
362 #[inline]
363 fn compute_cellular_automata_rule(&self, input_bits: u32) -> bool {
364 #[cfg(not(feature = "unsafe_disable_safety_checks"))]
365 {
366 let max_input_value = self.get_max_input_value();
367 if input_bits > max_input_value {
368 panic!("Input bits must be less or equal than {}", max_input_value);
369 }
370 }
371 (self.truth_table.clone() & (BigUint::one() << input_bits)) != BigUint::zero()
372 }
373
374 fn derivative(&self, direction: u32) -> Result<BooleanFunction, BooleanFunctionError> {
375 Ok(self.derivative_inner(direction)?.into())
376 }
377
378 fn is_linear(&self) -> bool {
379 let max_input_value = self.get_max_input_value();
380 [&self.truth_table, &self.reverse_inner().truth_table]
381 .iter()
382 .any(|rule| {
383 let mut equivalent_xor_function = BigUint::zero();
384 for i in 0..=max_input_value {
385 let mut equivalent_xor_function_eval_i = false;
386 for j in 0..self.variables_count {
387 if (*rule & (BigUint::one() << (1 << j))) != BigUint::zero() {
388 equivalent_xor_function_eval_i ^= (i & (1 << j)) == 0;
389 }
390 }
391 equivalent_xor_function |= BigUint::from(equivalent_xor_function_eval_i) << i;
392 }
393 **rule == equivalent_xor_function
394 || **rule
395 == (Self {
396 variables_count: self.variables_count,
397 truth_table: equivalent_xor_function,
398 })
399 .reverse_inner()
400 .truth_table
401 })
402 }
403
404 fn reverse(&self) -> BooleanFunction {
405 (self.reverse_inner()).into()
406 }
407
408 fn algebraic_normal_form(&self) -> AnfPolynomial {
409 let anf_form = fast_anf_transform_biguint(&self.truth_table, self.variables_count);
410 AnfPolynomial::from_anf_big(&anf_form, self.variables_count)
411 }
412
413 fn annihilator(&self, max_degree: Option<usize>) -> Option<(BooleanFunction, usize, usize)> {
414 let annihilator = self.annihilator_inner(max_degree)?;
415 Some(((annihilator.0).into(), annihilator.1, annihilator.2))
416 }
417
418 fn get_1_local_neighbor(&self, position: u32) -> BooleanFunction {
419 BooleanFunction::Big(self.get_1_local_neighbor_inner(position))
420 }
421
422 fn iter(&self) -> BooleanFunctionIterator {
423 BooleanFunctionIterator::new((self.clone()).into())
424 }
425
426 fn printable_hex_truth_table(&self) -> String {
427 format!("{:01$x}", self.truth_table, 1 << (self.variables_count - 2))
428 }
429
430 fn biguint_truth_table(&self) -> BigUint {
431 self.truth_table.clone()
432 }
433
434 fn close_balanced_functions_iterator(&self) -> Result<CloseBalancedFunctionIterator, BooleanFunctionError> {
435 Ok(CloseBalancedFunctionIterator::Big(self.close_balanced_functions_iterator_inner()?))
436 }
437}
438
439impl BitXorAssign for BigBooleanFunction {
444 fn bitxor_assign(&mut self, rhs: Self) {
445 #[cfg(not(feature = "unsafe_disable_safety_checks"))]
446 if self.variables_count != rhs.variables_count {
447 panic!("{}", XOR_DIFFERENT_VAR_COUNT_PANIC_MSG);
448 }
449 self.truth_table ^= rhs.truth_table;
450 }
451}
452
453impl BitXor for BigBooleanFunction {
458 type Output = Self;
459
460 fn bitxor(mut self, rhs: Self) -> Self::Output {
461 self ^= rhs;
462 self
463 }
464}
465
466impl Add for BigBooleanFunction {
473 type Output = Self;
474
475 fn add(self, rhs: Self) -> Self::Output {
476 self ^ rhs
477 }
478}
479
480impl AddAssign for BigBooleanFunction {
487 fn add_assign(&mut self, rhs: Self) {
488 *self ^= rhs;
489 }
490}
491
492impl BitAndAssign for BigBooleanFunction {
497 fn bitand_assign(&mut self, rhs: Self) {
498 #[cfg(not(feature = "unsafe_disable_safety_checks"))]
499 if self.variables_count != rhs.variables_count {
500 panic!("{}", AND_DIFFERENT_VAR_COUNT_PANIC_MSG);
501 }
502 self.truth_table &= rhs.truth_table;
503 }
504}
505
506impl BitAnd for BigBooleanFunction {
511 type Output = Self;
512
513 fn bitand(mut self, rhs: Self) -> Self::Output {
514 self &= rhs;
515 self
516 }
517}
518
519impl Mul for BigBooleanFunction {
526 type Output = Self;
527 fn mul(self, rhs: Self) -> Self::Output {
528 self & rhs
529 }
530}
531
532impl MulAssign for BigBooleanFunction {
539 fn mul_assign(&mut self, rhs: Self) {
540 *self &= rhs;
541 }
542}
543
544impl Not for BigBooleanFunction {
548 type Output = Self;
549
550 fn not(self) -> Self::Output {
551 self.reverse_inner()
552 }
553}
554
555#[hackfn]
556impl BigBooleanFunction {
557 fn call(&self, input_bits: u32) -> bool {
558 self.compute_cellular_automata_rule(input_bits)
559 }
560}
561
562#[cfg(test)]
563mod tests {
564 use crate::{AnfPolynomial, BigBooleanFunction, BooleanFunctionError, BooleanFunctionImpl};
565 use num_bigint::BigUint;
566 use num_traits::{Num, One, Zero};
567
568 #[test]
569 fn test_variables_count() {
570 let boolean_function = BigBooleanFunction::from_truth_table(
571 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
572 7,
573 );
574 assert_eq!(boolean_function.variables_count(), 7);
575 }
576
577 #[test]
578 fn test_is_balanced() {
579 let boolean_function = BigBooleanFunction::from_truth_table(
580 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
581 7,
582 );
583 assert_eq!(boolean_function.is_balanced(), true);
584
585 let boolean_function = BigBooleanFunction::from_truth_table(
586 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD1", 16).unwrap(),
587 7,
588 );
589 assert_eq!(boolean_function.is_balanced(), false);
590 }
591
592 #[test]
593 fn test_compute_cellular_automata_rule() {
594 let boolean_function = BigBooleanFunction::from_truth_table(
595 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
596 7,
597 );
598 assert_eq!(boolean_function.compute_cellular_automata_rule(13), false);
599 assert_eq!(boolean_function.compute_cellular_automata_rule(62), false);
600 assert_eq!(boolean_function.compute_cellular_automata_rule(64), false);
601 assert_eq!(boolean_function.compute_cellular_automata_rule(80), true);
602 assert_eq!(boolean_function.compute_cellular_automata_rule(100), true);
603
604 assert_eq!(boolean_function(13), false);
605 assert_eq!(boolean_function(62), false);
606 assert_eq!(boolean_function(64), false);
607 assert_eq!(boolean_function(80), true);
608 assert_eq!(boolean_function(100), true);
609 }
610
611 #[test]
612 fn test_derivative() {
613 let boolean_function = BigBooleanFunction::from_truth_table(
614 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
615 7,
616 );
617 let derivative = boolean_function.derivative(1).unwrap();
618 assert_eq!(derivative.variables_count(), 7);
619 assert_eq!(
620 derivative.printable_hex_truth_table(),
621 "cfffc3c00fcf0cfff003f3ccf3f0ff30"
622 );
623
624 let derivative = boolean_function.derivative(2).unwrap();
625 assert_eq!(
626 derivative.printable_hex_truth_table(),
627 "afffa5aff0aff50f0ffaf55af5f000a0"
628 );
629
630 let derivative = boolean_function.derivative(3).unwrap();
631 assert_eq!(
632 derivative.printable_hex_truth_table(),
633 "9000999fff90f6f0fff609690900ff60"
634 );
635
636 let derivative = boolean_function.derivative(128);
637 assert!(derivative.is_err());
638 }
639
640 #[test]
641 fn test_printable_hex_truth_table() {
642 let boolean_function = BigBooleanFunction::from_truth_table(
643 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
644 7,
645 );
646 assert_eq!(
647 boolean_function.printable_hex_truth_table(),
648 "7969817cc5893ba6ac326e47619f5ad0"
649 );
650
651 let boolean_function = BigBooleanFunction::from_truth_table(BigUint::one(), 7);
652 assert_eq!(
653 boolean_function.printable_hex_truth_table(),
654 "00000000000000000000000000000001"
655 );
656
657 let boolean_function = BigBooleanFunction::from_truth_table(BigUint::zero(), 7);
658 assert_eq!(
659 boolean_function.printable_hex_truth_table(),
660 "00000000000000000000000000000000"
661 );
662 }
663
664 #[test]
665 fn test_algebraic_normal_form() {
666 let boolean_function = BigBooleanFunction::from_truth_table(BigUint::from(30u32), 3);
667 assert_eq!(
668 boolean_function
669 .algebraic_normal_form()
670 .get_polynomial_big(),
671 BigUint::from(30u32)
672 );
673
674 let boolean_function = BigBooleanFunction::from_truth_table(BigUint::zero(), 3);
675 assert_eq!(
676 boolean_function
677 .algebraic_normal_form()
678 .get_polynomial_big(),
679 BigUint::zero()
680 );
681
682 let boolean_function = BigBooleanFunction::from_truth_table(BigUint::from(0xffu32), 3);
683 assert_eq!(
684 boolean_function
685 .algebraic_normal_form()
686 .get_polynomial_big(),
687 BigUint::one()
688 );
689
690 let boolean_function = BigBooleanFunction::from_truth_table(
691 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
692 7,
693 );
694 assert_eq!(boolean_function.algebraic_normal_form().to_string(), "x0*x1*x2*x3 + x0*x1*x2*x4 + x0*x1*x3*x4 + x1*x2*x3*x4 + x0*x1*x2*x5 + x0*x2*x3*x5 + x1*x2*x3*x5 + x0*x2*x4*x5 + x1*x2*x4*x5 + x1*x3*x4*x5 + x2*x3*x4*x5 + x0*x1*x2*x6 + x0*x1*x3*x6 + x0*x2*x3*x6 + x1*x2*x3*x6 + x0*x2*x4*x6 + x1*x2*x4*x6 + x0*x3*x4*x6 + x2*x3*x4*x6 + x0*x1*x5*x6 + x0*x2*x5*x6 + x1*x2*x5*x6 + x1*x3*x5*x6 + x2*x3*x5*x6 + x3*x4*x5*x6 + x0*x1*x2 + x0*x2*x3 + x1*x2*x4 + x1*x3*x4 + x2*x3*x4 + x0*x1*x5 + x0*x2*x5 + x1*x2*x5 + x1*x3*x5 + x2*x3*x5 + x0*x4*x5 + x2*x4*x5 + x3*x4*x5 + x0*x2*x6 + x1*x2*x6 + x3*x4*x6 + x0*x5*x6 + x2*x5*x6 + x3*x5*x6 + x0*x2 + x0*x3 + x2*x4 + x3*x5 + x0*x6 + x1*x6 + x2*x6 + x3*x6 + x5*x6 + x2 + x4 + x5");
695
696 let boolean_function = BigBooleanFunction::from_truth_table(
697 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD1", 16).unwrap(),
698 7,
699 );
700 assert_eq!(boolean_function.algebraic_normal_form().to_string(), "x0*x1*x2*x3*x4*x5*x6 + x0*x1*x2*x3*x4*x5 + x0*x1*x2*x3*x4*x6 + x0*x1*x2*x3*x5*x6 + x0*x1*x2*x4*x5*x6 + x0*x1*x3*x4*x5*x6 + x0*x2*x3*x4*x5*x6 + x1*x2*x3*x4*x5*x6 + x0*x1*x2*x3*x4 + x0*x1*x2*x3*x5 + x0*x1*x2*x4*x5 + x0*x1*x3*x4*x5 + x0*x2*x3*x4*x5 + x1*x2*x3*x4*x5 + x0*x1*x2*x3*x6 + x0*x1*x2*x4*x6 + x0*x1*x3*x4*x6 + x0*x2*x3*x4*x6 + x1*x2*x3*x4*x6 + x0*x1*x2*x5*x6 + x0*x1*x3*x5*x6 + x0*x2*x3*x5*x6 + x1*x2*x3*x5*x6 + x0*x1*x4*x5*x6 + x0*x2*x4*x5*x6 + x1*x2*x4*x5*x6 + x0*x3*x4*x5*x6 + x1*x3*x4*x5*x6 + x2*x3*x4*x5*x6 + x0*x2*x3*x4 + x0*x1*x3*x5 + x0*x1*x4*x5 + x0*x3*x4*x5 + x0*x1*x4*x6 + x1*x3*x4*x6 + x0*x3*x5*x6 + x0*x4*x5*x6 + x1*x4*x5*x6 + x2*x4*x5*x6 + x0*x1*x3 + x1*x2*x3 + x0*x1*x4 + x0*x2*x4 + x0*x3*x4 + x0*x3*x5 + x1*x4*x5 + x0*x1*x6 + x0*x3*x6 + x1*x3*x6 + x2*x3*x6 + x0*x4*x6 + x1*x4*x6 + x2*x4*x6 + x1*x5*x6 + x4*x5*x6 + x0*x1 + x1*x2 + x1*x3 + x2*x3 + x0*x4 + x1*x4 + x3*x4 + x0*x5 + x1*x5 + x2*x5 + x4*x5 + x4*x6 + x0 + x1 + x3 + x6 + 1");
701 }
702
703 #[test]
704 fn test_reverse_inner() {
705 let boolean_function = BigBooleanFunction::from_truth_table(
706 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
707 7,
708 );
709 let reversed_boolean_function = boolean_function.reverse_inner();
710 assert_eq!(
711 reversed_boolean_function.printable_hex_truth_table(),
712 "86967e833a76c45953cd91b89e60a52f"
713 );
714 assert_eq!(reversed_boolean_function.variables_count(), 7);
715
716 let reversed_boolean_function = !boolean_function;
717 assert_eq!(
718 reversed_boolean_function.printable_hex_truth_table(),
719 "86967e833a76c45953cd91b89e60a52f"
720 );
721 assert_eq!(reversed_boolean_function.variables_count(), 7);
722 }
723
724 #[test]
725 fn test_is_linear() {
726 let boolean_function = BigBooleanFunction::from_truth_table(
727 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
728 7,
729 );
730 assert!(!boolean_function.is_linear());
731
732 let boolean_function = BigBooleanFunction::from_truth_table(
733 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD1", 16).unwrap(),
734 7,
735 );
736 assert!(!boolean_function.is_linear());
737
738 let boolean_function = BigBooleanFunction::from_truth_table(
739 BigUint::from_str_radix("00000000000000000000000000000000", 16).unwrap(),
740 7,
741 );
742 assert!(boolean_function.is_linear());
743
744 let boolean_function = BigBooleanFunction::from_truth_table(
745 BigUint::from_str_radix("ffffffffffffffffffffffffffffffff", 16).unwrap(),
746 7,
747 );
748 assert!(boolean_function.is_linear());
749
750 let boolean_function = BigBooleanFunction::from_truth_table(
751 BigUint::from_str_radix("0000000000000000ffffffffffffffff", 16).unwrap(),
752 7,
753 );
754 assert!(boolean_function.is_linear());
755 }
756
757 #[test]
758 fn test_annihilator_inner() {
759 let boolean_function = BigBooleanFunction::from_truth_table(
760 BigUint::from_str_radix("00000000000000000000000000000000", 16).unwrap(),
761 7,
762 );
763 let annihilator = boolean_function.annihilator_inner(Some(0)).unwrap();
764 assert_eq!(
765 annihilator.0.printable_hex_truth_table(),
766 "ffffffffffffffffffffffffffffffff"
767 );
768 assert_eq!(annihilator.1, 0);
769 assert_eq!(annihilator.2, 1);
770
771 let boolean_function = BigBooleanFunction::from_truth_table(
772 BigUint::from_str_radix("ffffffffffffffffffffffffffffffff", 16).unwrap(),
773 7,
774 );
775 let annihilator = boolean_function.annihilator_inner(Some(7));
776 assert!(annihilator.is_none());
777
778 let boolean_function = BigBooleanFunction::from_truth_table(
779 BigUint::from_str_radix("ffffffffffffffffffffffffffffffff", 16).unwrap(),
780 7,
781 );
782 let annihilator = boolean_function.annihilator_inner(None);
783 assert!(annihilator.is_none());
784
785 let boolean_function = BigBooleanFunction::from_truth_table(
786 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
787 7,
788 );
789 let annihilator = boolean_function.annihilator_inner(Some(2));
790 assert!(annihilator.is_none());
791
792 let annihilator = boolean_function.annihilator_inner(Some(3)).unwrap();
793 assert_eq!(
794 annihilator.0.printable_hex_truth_table(),
795 "80921c010276c440400810a80e200425"
796 );
797 assert_eq!(annihilator.1, 3);
798 assert_eq!(annihilator.2, 2);
799
800 let annihilator = boolean_function.annihilator_inner(Some(7)).unwrap();
801 assert_eq!(
802 annihilator.0.printable_hex_truth_table(),
803 "80921c010276c440400810a80e200425"
804 );
805 assert_eq!(annihilator.1, 3);
806 assert_eq!(annihilator.2, 64);
807
808 let annihilator = boolean_function.annihilator_inner(None).unwrap();
809 assert_eq!(
810 annihilator.0.printable_hex_truth_table(),
811 "80921c010276c440400810a80e200425"
812 );
813 assert_eq!(annihilator.1, 3);
814 assert_eq!(annihilator.2, 64);
815
816 let boolean_function = BigBooleanFunction::from_truth_table(
817 BigUint::from_str_radix("80921c010276c440400810a80e200425", 16).unwrap(),
818 7,
819 );
820 let annihilator = boolean_function.annihilator_inner(Some(1));
821 assert!(annihilator.is_none());
822
823 let annihilator = boolean_function.annihilator_inner(Some(2)).unwrap();
824 assert_eq!(
825 annihilator.0.printable_hex_truth_table(),
826 "22442244118811882244224411881188"
827 );
828 assert_eq!(annihilator.1, 2);
829 assert_eq!(annihilator.2, 5);
830
831 let boolean_function = BigBooleanFunction::from_truth_table(
832 BigUint::from_str_radix("0000000000000000ffffffffffffffff", 16).unwrap(),
833 7,
834 );
835 let annihilator = boolean_function.annihilator_inner(Some(0));
836 assert!(annihilator.is_none());
837
838 let annihilator = boolean_function.annihilator_inner(Some(1)).unwrap();
839 assert_eq!(
840 annihilator.0.printable_hex_truth_table(),
841 "ffffffffffffffff0000000000000000"
842 );
843 assert_eq!(annihilator.1, 1);
844 assert_eq!(annihilator.2, 1);
845
846 let annihilator = boolean_function.annihilator_inner(Some(4)).unwrap();
847 assert_eq!(
848 annihilator.0.printable_hex_truth_table(),
849 "ffffffffffffffff0000000000000000"
850 );
851 assert_eq!(annihilator.1, 1);
852 assert_eq!(annihilator.2, 42);
853
854 let annihilator = boolean_function.annihilator_inner(Some(7)).unwrap();
855 assert_eq!(
856 annihilator.0.printable_hex_truth_table(),
857 "ffffffffffffffff0000000000000000"
858 );
859 assert_eq!(annihilator.1, 1);
860 assert_eq!(annihilator.2, 64);
861
862 let annihilator = boolean_function.annihilator_inner(None).unwrap();
863 assert_eq!(
864 annihilator.0.printable_hex_truth_table(),
865 "ffffffffffffffff0000000000000000"
866 );
867 assert_eq!(annihilator.1, 1);
868 assert_eq!(annihilator.2, 64);
869
870 let boolean_function = BigBooleanFunction::from_truth_table(
871 BigUint::from_str_radix(
872 "80921c010276c44224422441188118822442244118811880400810a80e200425",
873 16,
874 )
875 .unwrap(),
876 8,
877 );
878 let annihilator = boolean_function.annihilator_inner(Some(0));
879 assert!(annihilator.is_none());
880 let annihilator = boolean_function.annihilator_inner(Some(1));
881 assert!(annihilator.is_none());
882
883 let annihilator = boolean_function.annihilator_inner(Some(2)).unwrap();
884 assert_eq!(
885 annihilator.0.printable_hex_truth_table(),
886 "2244224411881188d2b4d2b4e178e178d2b4d2b4e178e1782244224411881188"
887 );
888 assert_eq!(annihilator.1, 2);
889 assert_eq!(annihilator.2, 2);
890
891 let annihilator = boolean_function.annihilator_inner(Some(5)).unwrap();
892 assert_eq!(
893 annihilator.0.printable_hex_truth_table(),
894 "2244224411881188d2b4d2b4e178e178d2b4d2b4e178e1782244224411881188"
895 );
896 assert_eq!(annihilator.1, 2);
897 assert_eq!(annihilator.2, 155);
898
899 let boolean_function = BigBooleanFunction::from_truth_table(
900 BigUint::from_str_radix(
901 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
902 16,
903 )
904 .unwrap(),
905 8,
906 );
907 let annihilator = boolean_function.annihilator_inner(Some(4));
908 assert!(annihilator.is_none());
909
910 let boolean_function = BigBooleanFunction::from_truth_table(
911 BigUint::from_str_radix(
912 "0000000000000000000000000000000000000000000000000000000000000000",
913 16,
914 )
915 .unwrap(),
916 8,
917 );
918 let annihilator = boolean_function.annihilator_inner(Some(4)).unwrap();
919 assert_eq!(
920 annihilator.0.printable_hex_truth_table(),
921 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
922 );
923 assert_eq!(annihilator.1, 0);
924 assert_eq!(annihilator.2, 163);
925 }
926
927 #[test]
928 fn test_from_walsh_hadamard_values() {
929 let boolean_function = BigBooleanFunction::from_walsh_hadamard_values(&[
930 -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
931 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
932 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
933 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
934 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
935 ])
936 .unwrap();
937 assert_eq!(
938 boolean_function.printable_hex_truth_table(),
939 "ffffffffffffffffffffffffffffffff"
940 );
941
942 let boolean_function = BigBooleanFunction::from_walsh_hadamard_values(&[
943 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
944 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
945 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
946 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
947 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
948 ])
949 .unwrap();
950 assert_eq!(
951 boolean_function.printable_hex_truth_table(),
952 "00000000000000000000000000000000"
953 );
954
955 let boolean_function = BigBooleanFunction::from_walsh_hadamard_values(&[
956 128, 0, 8, 8, 0, 0, 8, 8, -8, 8, -16, 0, 8, -8, -64, -16, 0, -16, 8, -8, 0, -16, 8, -8,
957 8, 8, 0, 0, -8, -8, -16, -16, -8, 8, 0, -16, -8, 8, 0, 16, 0, 0, -8, 24, 16, -48, 8, 8,
958 8, 8, 16, 16, 8, 8, -16, 16, 0, 16, -8, 8, -16, 32, 8, 24, 8, 8, 0, 0, -8, -8, 16, -16,
959 0, 16, 8, -8, 0, -16, 8, -8, -8, 8, -16, 0, 8, -8, 0, 16, -32, 0, 8, 8, 0, 0, 8, 8, 0,
960 0, -8, -8, -16, -16, 8, 8, 8, -8, -16, 0, 8, -8, -16, 0, 0, -16, -8, 8, -16, 0, 8, -8,
961 -8, -8, 0, 0, -8, -8, 0, 0, 12, 4, 4, -4, -4, -12, 20, -20, 4, 12, 12, -12, 4, -20, 12,
962 -12, -4, 4, -12, -4, 12, -12, 4, 12, -28, -4, 12, 4, 4, -4, 12, 4, 4, -4, -4, -12, -12,
963 -20, 12, 4, 12, -12, -12, -4, 12, -12, -12, -4, 4, -20, -4, 4, -12, -4, 12, -12, -4,
964 -12, 4, -4, -4, -12, 4, -4, -4, 4, 4, 12, -4, 4, 4, 12, -12, 12, -20, 4, 4, -4, 60,
965 -12, -4, -12, 4, -4, -4, -12, 4, -4, 4, 12, -4, 4, -12, -4, -20, -12, -12, -20, -4, 84,
966 -12, -20, -4, -12, -4, -28, -12, -4, 12, 52, 4, -20, 4, -20, 12, -12, 4, -20, -20, -12,
967 -4, -12, -12, -20, -20, 4, 4, -4,
968 ])
969 .unwrap();
970 assert_eq!(
971 boolean_function.printable_hex_truth_table(),
972 "80921c010276c44224422441188118822442244118811880400810a80e200425"
973 );
974
975 let boolean_function = BigBooleanFunction::from_walsh_hadamard_values(&[
976 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
977 0, 0, 0, 0, 0, 0, 0, -64, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
978 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
979 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
980 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
981 ])
982 .unwrap();
983 assert_eq!(
984 boolean_function.printable_hex_truth_table(),
985 "22442244118811882244224411881188"
986 );
987
988 let boolean_function =
989 BigBooleanFunction::from_walsh_hadamard_values(&[0, 0, 0, 0, 4, -4, -4]);
990 assert!(boolean_function.is_err());
991 assert_eq!(
992 boolean_function.unwrap_err(),
993 crate::BooleanFunctionError::InvalidWalshValuesCount(7)
994 );
995
996 let boolean_function = BigBooleanFunction::from_walsh_hadamard_values(&[0]);
997 assert!(boolean_function.is_err());
998 assert_eq!(
999 boolean_function.unwrap_err(),
1000 crate::BooleanFunctionError::InvalidWalshValuesCount(1)
1001 );
1002 }
1003
1004 #[test]
1005 fn test_xor() {
1006 let mut boolean_function = BigBooleanFunction::from_truth_table(
1007 BigUint::from_str_radix("80921c010276c440400810a80e200425", 16).unwrap(),
1008 7,
1009 );
1010 let boolean_function2 = BigBooleanFunction::from_truth_table(
1011 BigUint::from_str_radix("22442244118811882244224411881188", 16).unwrap(),
1012 7,
1013 );
1014 let boolean_function3 = boolean_function.clone() ^ boolean_function2.clone();
1015 boolean_function ^= boolean_function2;
1016 assert_eq!(
1017 boolean_function.printable_hex_truth_table(),
1018 "a2d63e4513fed5c8624c32ec1fa815ad"
1019 );
1020 assert_eq!(boolean_function.variables_count(), 7);
1021 assert_eq!(
1022 boolean_function3.printable_hex_truth_table(),
1023 "a2d63e4513fed5c8624c32ec1fa815ad"
1024 );
1025 assert_eq!(boolean_function3.variables_count(), 7);
1026 }
1027
1028 #[test]
1029 fn test_add() {
1030 let mut boolean_function = BigBooleanFunction::from_truth_table(
1031 BigUint::from_str_radix("80921c010276c440400810a80e200425", 16).unwrap(),
1032 7,
1033 );
1034 let boolean_function2 = BigBooleanFunction::from_truth_table(
1035 BigUint::from_str_radix("22442244118811882244224411881188", 16).unwrap(),
1036 7,
1037 );
1038 let boolean_function3 = boolean_function.clone() + boolean_function2.clone();
1039 boolean_function += boolean_function2;
1040 assert_eq!(
1041 boolean_function.printable_hex_truth_table(),
1042 "a2d63e4513fed5c8624c32ec1fa815ad"
1043 );
1044 assert_eq!(boolean_function.variables_count(), 7);
1045 assert_eq!(
1046 boolean_function3.printable_hex_truth_table(),
1047 "a2d63e4513fed5c8624c32ec1fa815ad"
1048 );
1049 assert_eq!(boolean_function3.variables_count(), 7);
1050 }
1051
1052 #[test]
1053 fn test_and() {
1054 let mut boolean_function = BigBooleanFunction::from_truth_table(
1055 BigUint::from_str_radix("4f1ead396f247a0410bdb210c006eab568ab4bfa8acb7a13b14ede67096c6eed", 16).unwrap(),
1056 8,
1057 );
1058 let boolean_function2 = BigBooleanFunction::from_truth_table(
1059 BigUint::from_str_radix("c870974094ead8a96a450b2ef33486b4e61a4c5e97816f7a7bae007d4c53fc7d", 16).unwrap(),
1060 8,
1061 );
1062 let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
1063 boolean_function &= boolean_function2;
1064 assert_eq!(
1065 boolean_function.printable_hex_truth_table(),
1066 "481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
1067 );
1068 assert_eq!(boolean_function.variables_count(), 8);
1069 assert_eq!(
1070 boolean_function3.printable_hex_truth_table(),
1071 "481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
1072 );
1073 assert_eq!(boolean_function3.variables_count(), 8);
1074 }
1075
1076 #[test]
1077 fn test_mul() {
1078 let mut boolean_function = BigBooleanFunction::from_truth_table(
1079 BigUint::from_str_radix("4f1ead396f247a0410bdb210c006eab568ab4bfa8acb7a13b14ede67096c6eed", 16).unwrap(),
1080 8,
1081 );
1082 let boolean_function2 = BigBooleanFunction::from_truth_table(
1083 BigUint::from_str_radix("c870974094ead8a96a450b2ef33486b4e61a4c5e97816f7a7bae007d4c53fc7d", 16).unwrap(),
1084 8,
1085 );
1086 let boolean_function3 = boolean_function.clone() * boolean_function2.clone();
1087 boolean_function *= boolean_function2;
1088 assert_eq!(
1089 boolean_function.printable_hex_truth_table(),
1090 "481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
1091 );
1092 assert_eq!(boolean_function.variables_count(), 8);
1093 assert_eq!(
1094 boolean_function3.printable_hex_truth_table(),
1095 "481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
1096 );
1097 assert_eq!(boolean_function3.variables_count(), 8);
1098 }
1099
1100 #[test]
1101 fn test_biguint_truth_table() {
1102 let boolean_function = BigBooleanFunction::from_truth_table(
1103 BigUint::from_str_radix("80921c010276c440400810a80e200425", 16).unwrap(),
1104 7,
1105 );
1106 assert_eq!(
1107 boolean_function.biguint_truth_table(),
1108 BigUint::from_str_radix("80921c010276c440400810a80e200425", 16).unwrap()
1109 );
1110 }
1111
1112 #[test]
1113 fn test_from_walsh_fourier_values() {
1114 let boolean_function = BigBooleanFunction::from_walsh_fourier_values(&[
1115 2, 0, 0, 2, 0, 2, 2, 0, 0, 2, 2, 0, 2, 0, 0, 2,
1116 ])
1117 .unwrap();
1118 assert_eq!(boolean_function.printable_hex_truth_table(), "8001");
1119
1120 let boolean_function =
1121 BigBooleanFunction::from_walsh_fourier_values(&[8, 0, 0, 0, 0, 0, 0, 0]).unwrap();
1122 assert_eq!(boolean_function.printable_hex_truth_table(), "ff");
1123
1124 let boolean_function =
1125 BigBooleanFunction::from_walsh_fourier_values(&[0, 0, 0, 0, 0, 0, 0, 0]).unwrap();
1126 assert_eq!(boolean_function.printable_hex_truth_table(), "00");
1127
1128 let boolean_function =
1129 BigBooleanFunction::from_walsh_fourier_values(&[4, -4, 0, 0, 0, 0, 0, 0]).unwrap();
1130 assert_eq!(boolean_function.printable_hex_truth_table(), "aa");
1131
1132 let boolean_function = BigBooleanFunction::from_walsh_fourier_values(&[
1133 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1135 0, 0, 0, 0, 0, 0,
1136 ])
1137 .unwrap();
1138 assert_eq!(
1139 boolean_function.printable_hex_truth_table(),
1140 "ffffffffffffffff"
1141 );
1142 assert_eq!(boolean_function.variables_count(), 6);
1143 }
1144
1145 #[test]
1146 fn test_iter() {
1147 let boolean_function = BigBooleanFunction::from_truth_table(
1148 BigUint::from_str_radix("7969817CC5893BA6AC326E47619F5AD0", 16).unwrap(),
1149 8,
1150 );
1151 let mut iterator = boolean_function.iter();
1152 assert_eq!(iterator.next(), Some(false));
1153 assert_eq!(iterator.next(), Some(false));
1154 assert_eq!(iterator.next(), Some(false));
1155 assert_eq!(iterator.next(), Some(false));
1156 assert_eq!(iterator.next(), Some(true));
1157 }
1158
1159 #[test]
1160 fn test_get_1_local_neighbor_inner() {
1161 let function = BigBooleanFunction::from_truth_table(
1162 BigUint::from_str_radix("80921c010276c440400810a80e200425", 16).unwrap(),
1163 7,
1164 );
1165 let neighbor = function.get_1_local_neighbor_inner(0);
1166 assert_eq!(
1167 neighbor.printable_hex_truth_table(),
1168 "80921c010276c440400810a80e200424"
1169 );
1170 }
1171
1172 #[test]
1173 fn test_close_balanced_functions_iterator_inner() {
1174 let already_balanced_function = BigBooleanFunction::from_truth_table(
1175 BigUint::from_str_radix("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 16).unwrap(),
1176 8);
1177 assert!(already_balanced_function.close_balanced_functions_iterator_inner().is_err());
1178
1179 let bent_function = BigBooleanFunction::from_truth_table(
1180 BigUint::from_str_radix("80329780469d0b85cd2ad63e1a6ba42adbd83c9a0c55e4e8c99f227b0ffc1418", 16).unwrap(),
1181 8);
1182 let close_balanced_iterator = bent_function.close_balanced_functions_iterator_inner();
1183 assert!(close_balanced_iterator.is_ok());
1184 let mut close_balanced_iterator = close_balanced_iterator.unwrap();
1185 for _ in 0..10 {
1187 assert!(close_balanced_iterator.next().unwrap().is_balanced());
1188 }
1189
1190 let bent_function = BigBooleanFunction::from_truth_table(
1191 BigUint::from_str_radix("7fcd687fb962f47a32d529c1e5945bd52427c365f3aa1b173660dd84f003ebe7", 16).unwrap(),
1192 8);
1193 let close_balanced_iterator = bent_function.close_balanced_functions_iterator_inner();
1194 assert!(close_balanced_iterator.is_ok());
1195 let mut close_balanced_iterator = close_balanced_iterator.unwrap();
1196 for _ in 0..10 {
1197 assert!(close_balanced_iterator.next().unwrap().is_balanced());
1198 }
1199 }
1200
1201 #[test]
1202 fn test_from_anf_polynomial_str_inner() {
1203 let rule_30_anf_str = "x0*x1 + x0 + x1 + x2";
1204 let rule_30_function = BigBooleanFunction::from_anf_polynomial_str_inner(rule_30_anf_str, 3).unwrap();
1205 assert_eq!(rule_30_function.printable_hex_truth_table(), "1e");
1206
1207 let anf_str = "x7*x6*x0*x1 + x0 + x1 + x2";
1208 let boolean_function = BigBooleanFunction::from_anf_polynomial_str_inner(anf_str, 3);
1209 assert!(boolean_function.is_err());
1210 assert_eq!(boolean_function.unwrap_err(), BooleanFunctionError::AnfFormNVariableTooBigFactor(3, 7));
1211
1212 let anf_str = "x7*x6*x0*x1 + x0 + x1 + x2";
1213 let boolean_function = BigBooleanFunction::from_anf_polynomial_str_inner(anf_str, 8).unwrap();
1214 assert_eq!(boolean_function.printable_hex_truth_table(), "1e1e1e1e1e1e1e1e969696969696969696969696969696969696969696969696");
1215
1216 let anf_str = "x0*y1 + x0 + x1 + x2";
1217 let boolean_function = BigBooleanFunction::from_anf_polynomial_str_inner(anf_str, 3);
1218 assert!(boolean_function.is_err());
1219 assert_eq!(boolean_function.unwrap_err(), BooleanFunctionError::ErrorParsingAnfString);
1220 }
1221
1222 #[test]
1223 fn test_from_anf_polynomial_inner() {
1224 let anf = AnfPolynomial::from_str("x7*x6*x0*x1 + x0 + x1 + x2", 8).unwrap();
1225 let boolean_function = BigBooleanFunction::from_anf_polynomial_inner(&anf);
1226 assert_eq!(boolean_function.printable_hex_truth_table(), "1e1e1e1e1e1e1e1e969696969696969696969696969696969696969696969696");
1227 }
1228}