boolean_function/
big_boolean_function.rs

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/// Struct representing a boolean function with a big truth table.
17///
18/// As the [crate::SmallBooleanFunction] struct internally uses a [u64] to store the truth table, this struct allows to store Boolean functions with more than 6 variables.
19///
20/// For a variable count less or equal to 6, the [crate::SmallBooleanFunction] struct is more efficient. You could use the [crate::BooleanFunction] to store both types of Boolean functions.
21#[derive(Debug, Clone, Eq, PartialEq)]
22pub struct BigBooleanFunction {
23    variables_count: usize,
24    truth_table: BigUint,
25}
26
27impl BigBooleanFunction {
28    /// Creates a new [BigBooleanFunction] from a truth table and the number of variables.
29    ///
30    /// # Parameters
31    /// - `truth_table` - The truth table of the Boolean function, where the lower bit represents the output of the Boolean function for the input 0.
32    /// - `variables_count` - The number of variables of the Boolean function.
33    ///
34    /// # Returns
35    /// A [BigBooleanFunction] instance from the truth table and the number of variables.
36    ///
37    /// # Panics
38    /// Panics if the truth table is too big for the number of variables or if the number of variables is greater than 31, and the `unsafe_disable_safety_checks` feature is not enabled.
39    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    /// Computes the [derivative](crate::BooleanFunctionImpl::derivative) of the Boolean function for a given direction.
55    ///
56    /// # Parameters
57    /// * `direction` - The direction of the derivative.
58    ///
59    /// # Returns
60    /// The derivative of the Boolean function for the given direction, or an error if the direction is greater than the maximum input value and the `unsafe_disable_safety_checks` feature is not enabled.
61    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    /// Computes the [reverse](crate::BooleanFunctionImpl::reverse) of the Boolean function.
86    ///
87    /// # Returns
88    /// The reverse of the Boolean function.
89    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    /// Computes the [annihilator](crate::BooleanFunctionImpl::annihilator) of the Boolean function for a given maximum degree.
98    ///
99    /// # Parameters
100    /// * `max_degree` - An optional maximum degree of the annihilator to search for. If set to `None`, the value is set to the variable count.
101    ///
102    /// # Returns
103    /// A tuple containing the annihilator function, its degree and the dimension of the annihilator vector space, or `None` no annihilator was found.
104    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); // performance bottleneck
154            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    /// Computes a [BigBooleanFunction] from [Walsh-Hadamard values](crate::BooleanFunctionImpl::walsh_hadamard_values), by applying the inverse Walsh-Hadamard transform.
185    ///
186    /// # Parameters
187    /// * `walsh_values` - The Walsh-Hadamard values of the Boolean function.
188    ///
189    /// # Returns
190    /// The Boolean function created from the Walsh-Hadamard values list, or an error if the list length is less than 4, or not a power of 2.
191    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    /// Computes a [BigBooleanFunction] from [Walsh-Fourier values](crate::BooleanFunctionImpl::walsh_fourier_values), by applying the inverse Walsh-Fourier transform.
220    ///
221    /// # Parameters
222    /// * `walsh_values` - The Walsh-Fourier values of the Boolean function.
223    ///
224    /// # Returns
225    /// The Boolean function created from the Walsh-Fourier values list, or an error if the list length is less than 4, or not a power of 2.
226    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    /// Returns a [1-local neighbor](crate::BooleanFunctionImpl::get_1_local_neighbor) of the Boolean function, at a specific position
255    ///
256    /// # Parameters
257    /// - `position`: The position $i$ at which to compute the 1-local neighbor.
258    ///
259    /// # Returns
260    /// The 1-local neighbor of the Boolean function at the given position.
261    ///
262    /// # Panics
263    /// If the position is greater than the maximum input value, and the `unsafe_disable_safety_checks` feature is not enabled.
264    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    /// Returns an iterator over the closest possible balanced Boolean functions.
281    ///
282    /// See [BooleanFunctionImpl::close_balanced_functions_iterator](crate::BooleanFunctionImpl::close_balanced_functions_iterator) for more details.
283    ///
284    /// # Returns
285    ///
286    /// An iterator over close balanced Boolean functions, or an error if the function is already balanced.
287    ///
288    /// # Note
289    /// It is assumed that the function truth table is correctly sanitized, so be careful if you generated it with `unsafe_disable_safety_checks` feature activated.
290    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    /// Computes BigBooleanFunction from string ANF representation
313    ///
314    /// The ANF string representation must be in exact form "`x0*x2*x3 + x2*x3 + x1 + 1`".
315    ///
316    /// X's index starts at 0, meaning the maximum index is variable count - 1.
317    ///
318    /// # Parameters:
319    /// - `anf_polynomial`: The string representation of the ANF form
320    /// - `num_variables`: Variable count of the polynomial
321    ///
322    /// # Returns
323    /// The BigBooleanFunction corresponding to the ANF string representation, or an error if the input string doesn't respect the format,
324    /// and `unsafe_disable_safety_checks` feature is not activated.
325    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    /// Computes BigBooleanFunction from ANF polynomial
332    ///
333    /// # Parameters:
334    /// - `anf_polynomial`: The polynomial in Algebraic Normal Form
335    ///
336    /// # Returns
337    /// The BigBooleanFunction corresponding to the ANF polynomial
338    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
439/// In-place XOR operator for Boolean functions truth tables.
440///
441/// # Panics
442/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
443impl 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
453/// XOR operator for Boolean functions truth tables.
454///
455/// # Panics
456/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
457impl 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
466/// ADD operator for Boolean functions truth tables.
467///
468/// It is equivalent to [crate::BigBooleanFunction::bitxor] operator.
469///
470/// # Panics
471/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
472impl Add for BigBooleanFunction {
473    type Output = Self;
474
475    fn add(self, rhs: Self) -> Self::Output {
476        self ^ rhs
477    }
478}
479
480/// In-place ADD operator for Boolean functions truth tables.
481///
482/// It is equivalent to [crate::BigBooleanFunction::bitxor_assign] operator.
483///
484/// # Panics
485/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
486impl AddAssign for BigBooleanFunction {
487    fn add_assign(&mut self, rhs: Self) {
488        *self ^= rhs;
489    }
490}
491
492/// In-place AND operator for Boolean functions truth tables.
493///
494/// # Panics
495/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
496impl 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
506/// AND operator for Boolean functions truth tables.
507///
508/// # Panics
509/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
510impl 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
519/// MUL operator for Boolean functions truth tables.
520///
521/// It is equivalent to [crate::BigBooleanFunction::bitand] operator.
522///
523/// # Panics
524/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
525impl Mul for BigBooleanFunction {
526    type Output = Self;
527    fn mul(self, rhs: Self) -> Self::Output {
528        self & rhs
529    }
530}
531
532/// In-place MUL operator for Boolean functions truth tables.
533///
534/// It is equivalent to [crate::BigBooleanFunction::bitand_assign] operator.
535///
536/// # Panics
537/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
538impl MulAssign for BigBooleanFunction {
539    fn mul_assign(&mut self, rhs: Self) {
540        *self &= rhs;
541    }
542}
543
544/// NOT operator for Boolean functions.
545///
546/// This is equivalent to the [crate::BooleanFunctionImpl::reverse] operation: it reverses each output of the Boolean function.
547impl 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        //assert_eq!(close_balanced_iterator.into_iter().count(), 840261910995); // 120 choose 8, but it's too large for unit test :')
1186        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}