Skip to content

Commit

Permalink
Add support for AND operation between Boolean functions
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasarmel committed Nov 9, 2024
1 parent f78e924 commit f2c8317
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 23 deletions.
55 changes: 53 additions & 2 deletions src/big_boolean_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use crate::anf_polynom::AnfPolynomial;
#[cfg(not(feature = "unsafe_disable_safety_checks"))]
use crate::boolean_function_error::TRUTH_TABLE_TOO_BIG_VAR_COUNT_PANIC_MSG;
#[cfg(not(feature = "unsafe_disable_safety_checks"))]
use crate::boolean_function_error::XOR_DIFFERENT_VAR_COUNT_PANIC_MSG;
use crate::boolean_function_error::{XOR_DIFFERENT_VAR_COUNT_PANIC_MSG, AND_DIFFERENT_VAR_COUNT_PANIC_MSG};
use crate::iterator::{BigCloseBalancedFunctionIterator, BooleanFunctionIterator, CloseBalancedFunctionIterator};
use crate::utils::{fast_anf_transform_biguint, left_kernel_boolean};
use crate::{BooleanFunction, BooleanFunctionError, BooleanFunctionImpl, BooleanFunctionType};
use itertools::{enumerate, Itertools};
use num_bigint::BigUint;
use num_integer::binomial;
use num_traits::{FromPrimitive, One, Zero};
use std::ops::{BitXor, BitXorAssign, Not};
use std::ops::{BitAnd, BitAndAssign, BitXor, BitXorAssign, Not};

/// Struct representing a boolean function with a big truth table.
///
Expand Down Expand Up @@ -461,6 +461,33 @@ impl BitXor for BigBooleanFunction {
}
}

/// In-place AND operator for Boolean functions truth tables.
///
/// # Panics
/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
impl BitAndAssign for BigBooleanFunction {
fn bitand_assign(&mut self, rhs: Self) {
#[cfg(not(feature = "unsafe_disable_safety_checks"))]
if self.variables_count != rhs.variables_count {
panic!("{}", AND_DIFFERENT_VAR_COUNT_PANIC_MSG);
}
self.truth_table &= rhs.truth_table;
}
}

/// AND operator for Boolean functions truth tables.
///
/// # Panics
/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
impl BitAnd for BigBooleanFunction {
type Output = Self;

fn bitand(mut self, rhs: Self) -> Self::Output {
self &= rhs;
self
}
}

/// NOT operator for Boolean functions.
///
/// This is equivalent to the [crate::BooleanFunctionImpl::reverse] operation: it reverses each output of the Boolean function.
Expand Down Expand Up @@ -909,6 +936,30 @@ mod tests {
assert_eq!(boolean_function3.variables_count(), 7);
}

#[test]
fn test_and() {
let mut boolean_function = BigBooleanFunction::from_truth_table(
BigUint::from_str_radix("4f1ead396f247a0410bdb210c006eab568ab4bfa8acb7a13b14ede67096c6eed", 16).unwrap(),
8,
);
let boolean_function2 = BigBooleanFunction::from_truth_table(
BigUint::from_str_radix("c870974094ead8a96a450b2ef33486b4e61a4c5e97816f7a7bae007d4c53fc7d", 16).unwrap(),
8,
);
let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
boolean_function &= boolean_function2;
assert_eq!(
boolean_function.printable_hex_truth_table(),
"481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
);
assert_eq!(boolean_function.variables_count(), 8);
assert_eq!(
boolean_function3.printable_hex_truth_table(),
"481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
);
assert_eq!(boolean_function3.variables_count(), 8);
}

#[test]
fn test_biguint_truth_table() {
let boolean_function = BigBooleanFunction::from_truth_table(
Expand Down
3 changes: 3 additions & 0 deletions src/boolean_function_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ pub enum BooleanFunctionError {
pub(crate) const XOR_DIFFERENT_VAR_COUNT_PANIC_MSG: &'static str =
"XOR operation requires the same number of variables in both functions";

pub(crate) const AND_DIFFERENT_VAR_COUNT_PANIC_MSG: &'static str =
"AND operation requires the same number of variables in both functions";

#[cfg(not(feature = "unsafe_disable_safety_checks"))]
pub(crate) const TRUTH_TABLE_TOO_BIG_VAR_COUNT_PANIC_MSG: &'static str =
"Truth table is too big for variables count";
Expand Down
178 changes: 161 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mod small_boolean_function;
mod utils;

pub use crate::anf_polynom::AnfPolynomial;
use crate::boolean_function_error::XOR_DIFFERENT_VAR_COUNT_PANIC_MSG;
use crate::boolean_function_error::{AND_DIFFERENT_VAR_COUNT_PANIC_MSG, XOR_DIFFERENT_VAR_COUNT_PANIC_MSG};
pub use crate::iterator::BooleanFunctionIterator;
use crate::BooleanFunctionError::{
StringHexParseError, UnexpectedError, WrongStringHexTruthTableLength,
Expand All @@ -32,7 +32,7 @@ use num_traits::{Num, ToPrimitive};
pub use small_boolean_function::SmallBooleanFunction;
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::ops::{BitXor, BitXorAssign, Not};
use std::ops::{BitAnd, BitAndAssign, BitXor, BitXorAssign, Not};
use crate::iterator::CloseBalancedFunctionIterator;

/// Internal representation of Boolean function
Expand Down Expand Up @@ -765,6 +765,62 @@ impl BitXor for BooleanFunction {
}
}

/// In-place AND operator for Boolean functions truth tables.
///
/// # Panics
/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
impl BitAndAssign for BooleanFunction {
fn bitand_assign(&mut self, rhs: Self) {
let self_num_variables = self.variables_count();
let rhs_num_variables = rhs.variables_count();
if self_num_variables != rhs_num_variables {
panic!("{}", AND_DIFFERENT_VAR_COUNT_PANIC_MSG);
}
match (
self,
rhs,
) {
(BooleanFunction::Small(self_small_boolean_function), BooleanFunction::Small(rhs_small_boolean_function)) => {
*self_small_boolean_function &= rhs_small_boolean_function;
},
(BooleanFunction::Small(self_small_boolean_function), BooleanFunction::Big(rhs_big_boolean_function)) => {
let rhs_small_boolean_function = SmallBooleanFunction::from_truth_table(
rhs_big_boolean_function
.biguint_truth_table()
.to_u64()
.unwrap(),
self_num_variables,
)
.unwrap();
*self_small_boolean_function &= rhs_small_boolean_function;
},
(BooleanFunction::Big(self_big_boolean_function), BooleanFunction::Small(rhs_small_boolean_function)) => {
let rhs_big_boolean_function = BigBooleanFunction::from_truth_table(
rhs_small_boolean_function.biguint_truth_table(),
rhs_num_variables,
);
*self_big_boolean_function &= rhs_big_boolean_function;
},
(BooleanFunction::Big(self_big_boolean_function), BooleanFunction::Big(rhs_big_boolean_function)) => {
*self_big_boolean_function &= rhs_big_boolean_function;
}
}
}
}

/// AND operator for Boolean functions truth tables.
///
/// # Panics
/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
impl BitAnd for BooleanFunction {
type Output = Self;

fn bitand(mut self, rhs: Self) -> Self::Output {
self &= rhs;
self
}
}

/// NOT operator for Boolean functions.
///
/// This is equivalent to the [BooleanFunctionImpl::reverse] operation: it reverses each output of the Boolean function.
Expand All @@ -776,6 +832,15 @@ impl Not for BooleanFunction {
}
}

/// Create Boolean Function from hex string truth table representation
impl TryFrom<&str> for BooleanFunction {
type Error = BooleanFunctionError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::from_hex_string_truth_table(value)
}
}

impl BooleanFunction {
/// Creates a new BooleanFunction from a hexadecimal string representing the truth table.
///
Expand Down Expand Up @@ -954,15 +1019,6 @@ impl BooleanFunction {
}
}

/// Create Boolean Function from hex string truth table representation
impl TryFrom<&str> for BooleanFunction {
type Error = BooleanFunctionError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::from_hex_string_truth_table(value)
}
}

#[cfg(test)]
mod tests {
use crate::BooleanFunctionError::InvalidWalshValuesCount;
Expand Down Expand Up @@ -1916,11 +1972,10 @@ mod tests {

let mut boolean_function =
BooleanFunction::from_hex_string_truth_table("1e").unwrap();
let boolean_function2: BooleanFunction = (super::BigBooleanFunction::from_truth_table(
let boolean_function2: BooleanFunction = super::BigBooleanFunction::from_truth_table(
BigUint::from_str_radix("ab", 16).unwrap(),
3,
))
.into();
).into();
let boolean_function3 = boolean_function.clone() ^ boolean_function2.clone();
boolean_function ^= boolean_function2.clone();
assert_eq!(&boolean_function, &boolean_function3);
Expand All @@ -1939,11 +1994,10 @@ mod tests {
BooleanFunctionType::Small
);

let mut boolean_function: BooleanFunction = (super::BigBooleanFunction::from_truth_table(
let mut boolean_function: BooleanFunction = super::BigBooleanFunction::from_truth_table(
BigUint::from_str_radix("ab", 16).unwrap(),
3,
))
.into();
).into();
let boolean_function2 = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
let boolean_function3 = boolean_function.clone() ^ boolean_function2.clone();
boolean_function ^= boolean_function2.clone();
Expand All @@ -1964,6 +2018,96 @@ mod tests {
);
}

#[test]
fn test_and() {
let mut boolean_function =
BooleanFunction::from_hex_string_truth_table("4f1ead396f247a0410bdb210c006eab568ab4bfa8acb7a13b14ede67096c6eed")
.unwrap();
let boolean_function2 =
BooleanFunction::from_hex_string_truth_table("c870974094ead8a96a450b2ef33486b4e61a4c5e97816f7a7bae007d4c53fc7d")
.unwrap();
let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
boolean_function &= boolean_function2.clone();
assert_eq!(&boolean_function, &boolean_function3);
assert_eq!(
boolean_function.printable_hex_truth_table(),
"481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
);
assert_eq!(boolean_function.variables_count(), 8);
assert_eq!(
boolean_function.get_boolean_function_type(),
BooleanFunctionType::Big
);
assert_eq!(
boolean_function3.get_boolean_function_type(),
BooleanFunctionType::Big
);

let mut boolean_function =
BooleanFunction::from_hex_string_truth_table("1e").unwrap();
let boolean_function2 = BooleanFunction::from_hex_string_truth_table("ab").unwrap();
let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
boolean_function &= boolean_function2.clone();
assert_eq!(&boolean_function, &boolean_function3);
assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
assert_eq!(boolean_function.variables_count(), 3);
assert_eq!(
boolean_function.get_boolean_function_type(),
BooleanFunctionType::Small
);
assert_eq!(
boolean_function3.get_boolean_function_type(),
BooleanFunctionType::Small
);

let mut boolean_function =
BooleanFunction::from_hex_string_truth_table("1e").unwrap();
let boolean_function2: BooleanFunction = super::BigBooleanFunction::from_truth_table(
BigUint::from_str_radix("ab", 16).unwrap(),
3,
).into();
let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
boolean_function &= boolean_function2.clone();
assert_eq!(&boolean_function, &boolean_function3);
assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
assert_eq!(boolean_function.variables_count(), 3);
assert_eq!(
boolean_function.get_boolean_function_type(),
BooleanFunctionType::Small
);
assert_eq!(
boolean_function2.get_boolean_function_type(),
BooleanFunctionType::Big
);
assert_eq!(
boolean_function3.get_boolean_function_type(),
BooleanFunctionType::Small
);

let mut boolean_function: BooleanFunction = super::BigBooleanFunction::from_truth_table(
BigUint::from_str_radix("ab", 16).unwrap(),
3,
).into();
let boolean_function2 = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
boolean_function &= boolean_function2.clone();
assert_eq!(&boolean_function, &boolean_function3);
assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
assert_eq!(boolean_function.variables_count(), 3);
assert_eq!(
boolean_function.get_boolean_function_type(),
BooleanFunctionType::Big
);
assert_eq!(
boolean_function2.get_boolean_function_type(),
BooleanFunctionType::Small
);
assert_eq!(
boolean_function3.get_boolean_function_type(),
BooleanFunctionType::Big
);
}

#[test]
fn test_walsh_fourier_values() {
let boolean_function = BooleanFunction::from_hex_string_truth_table("ff").unwrap();
Expand Down
Loading

0 comments on commit f2c8317

Please sign in to comment.