Skip to content

Commit 93df0cb

Browse files
committed
Add support for XOR operation between ANF polynomial
1 parent f2c8317 commit 93df0cb

File tree

1 file changed

+103
-2
lines changed

1 file changed

+103
-2
lines changed

src/anf_polynom.rs

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
//! Algebraic Normal Form (ANF) representation of Boolean functions.
22
33
#[cfg(not(feature = "unsafe_disable_safety_checks"))]
4-
use crate::boolean_function_error::POLYNOMIAL_ANF_TOO_BIG_VAR_COUNT_PANIC_MSG;
4+
use crate::boolean_function_error::{POLYNOMIAL_ANF_TOO_BIG_VAR_COUNT_PANIC_MSG, XOR_DIFFERENT_VAR_COUNT_PANIC_MSG};
55
use itertools::Itertools;
66
use num_bigint::BigUint;
7-
use num_traits::{One, Zero};
7+
use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
88
use std::fmt::Display;
9+
use std::ops::{BitXor, BitXorAssign};
910
use fast_boolean_anf_transform::fast_bool_anf_transform_unsigned;
1011
use crate::{BigBooleanFunction, BooleanFunction, BooleanFunctionError, SmallBooleanFunction};
1112
use crate::utils::fast_anf_transform_biguint;
@@ -149,7 +150,14 @@ impl AnfPolynomial {
149150
num_variables,
150151
};
151152

153+
if anf_polynomial.is_empty() {
154+
return Ok(anf_polynomial_obj);
155+
}
156+
152157
for monomial_string in anf_polynomial_filtered.split('+') {
158+
if monomial_string == "0" {
159+
continue;
160+
}
153161
if monomial_string == "1" {
154162
anf_polynomial_obj.flip_bit_pos(0)?;
155163
continue;
@@ -253,6 +261,52 @@ impl Into<BooleanFunction> for AnfPolynomial {
253261
}
254262
}
255263

264+
impl Into<String> for AnfPolynomial {
265+
fn into(self) -> String {
266+
self.to_string()
267+
}
268+
}
269+
270+
/// In-place XOR operator for Boolean functions ANF polynomial
271+
///
272+
/// # Panics
273+
/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
274+
impl BitXorAssign for AnfPolynomial {
275+
fn bitxor_assign(&mut self, rhs: Self) {
276+
#[cfg(not(feature = "unsafe_disable_safety_checks"))]
277+
if self.num_variables != rhs.num_variables {
278+
panic!("{}", XOR_DIFFERENT_VAR_COUNT_PANIC_MSG);
279+
}
280+
match (&mut self.polynomial, rhs.polynomial) {
281+
(PolynomialFormat::Small(self_poly), PolynomialFormat::Small(rhs_poly)) => {
282+
*self_poly ^= rhs_poly;
283+
},
284+
(PolynomialFormat::Big(self_poly), PolynomialFormat::Small(rhs_poly)) => {
285+
*self_poly ^= BigUint::from_u64(rhs_poly).unwrap();
286+
},
287+
(PolynomialFormat::Small(self_poly), PolynomialFormat::Big(rhs_poly)) => {
288+
*self_poly ^= rhs_poly.to_u64().unwrap();
289+
},
290+
(PolynomialFormat::Big(self_poly), PolynomialFormat::Big(rhs_poly)) => {
291+
*self_poly ^= rhs_poly;
292+
},
293+
}
294+
}
295+
}
296+
297+
/// XOR operator for Boolean functions ANF polynomial
298+
///
299+
/// # Panics
300+
/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
301+
impl BitXor for AnfPolynomial {
302+
type Output = AnfPolynomial;
303+
304+
fn bitxor(mut self, rhs: Self) -> Self::Output {
305+
self ^= rhs;
306+
self
307+
}
308+
}
309+
256310
#[cfg(test)]
257311
mod tests {
258312
use crate::anf_polynom::AnfPolynomial;
@@ -360,6 +414,11 @@ mod tests {
360414
assert_eq!(anf_polynomial.to_string(), "x0*x1 + x0 + x2");
361415
assert_eq!(anf_polynomial.get_boolean_function_type(), crate::BooleanFunctionType::Small);
362416

417+
let anf_str = "x2 + x0*x1 + x0 + 0 + 0";
418+
let anf_polynomial = AnfPolynomial::from_str(anf_str, 3).unwrap();
419+
assert_eq!(anf_polynomial.to_string(), "x0*x1 + x0 + x2");
420+
assert_eq!(anf_polynomial.get_boolean_function_type(), crate::BooleanFunctionType::Small);
421+
363422
let anf_str = "x0*x1 + x2 + x0 + 1";
364423
let anf_polynomial = AnfPolynomial::from_str(anf_str, 2);
365424
assert!(anf_polynomial.is_err());
@@ -389,6 +448,31 @@ mod tests {
389448
let anf_polynomial = AnfPolynomial::from_str(anf_str, 8);
390449
assert!(anf_polynomial.is_err());
391450
assert_eq!(anf_polynomial.unwrap_err(), BooleanFunctionError::ErrorParsingAnfString);
451+
452+
let anf_str = "";
453+
let polynomial = AnfPolynomial::from_str(anf_str, 3).unwrap();
454+
let boolean_function = polynomial.to_boolean_function();
455+
assert_eq!(boolean_function.printable_hex_truth_table(), "00");
456+
457+
let anf_str = "0";
458+
let polynomial = AnfPolynomial::from_str(anf_str, 3).unwrap();
459+
let boolean_function = polynomial.to_boolean_function();
460+
assert_eq!(boolean_function.printable_hex_truth_table(), "00");
461+
462+
let anf_str = "";
463+
let polynomial = AnfPolynomial::from_str(anf_str, 7).unwrap();
464+
let boolean_function = polynomial.to_boolean_function();
465+
assert_eq!(boolean_function.printable_hex_truth_table(), "00000000000000000000000000000000");
466+
467+
let anf_str = "0";
468+
let polynomial = AnfPolynomial::from_str(anf_str, 7).unwrap();
469+
let boolean_function = polynomial.to_boolean_function();
470+
assert_eq!(boolean_function.printable_hex_truth_table(), "00000000000000000000000000000000");
471+
472+
let anf_str = "x0*x0";
473+
let anf_polynomial = AnfPolynomial::from_str(anf_str, 3).unwrap();
474+
assert_eq!(anf_polynomial.to_string(), "x0");
475+
assert_eq!(anf_polynomial.get_boolean_function_type(), crate::BooleanFunctionType::Small);
392476
}
393477

394478
#[test]
@@ -408,4 +492,21 @@ mod tests {
408492
let boolean_function = anf_polynomial.to_boolean_function();
409493
assert_eq!(boolean_function.printable_hex_truth_table(), "7fffffffffffffffffffffffffffffff80000000000000000000000000000000");
410494
}
495+
496+
#[test]
497+
fn test_xor() {
498+
let anf_1 = AnfPolynomial::from_str("x0*x1*x4*x7 + x2*x3 + x1 + 0", 8).unwrap();
499+
let mut anf_2 = AnfPolynomial::from_str("x0*x1*x2*x4*x7 + x2*x3 + x3 + 1", 8).unwrap();
500+
let anf_3 = anf_1.clone() ^ anf_2.clone();
501+
assert_eq!(anf_3.to_string(), "x0*x1*x2*x4*x7 + x0*x1*x4*x7 + x1 + x3 + 1");
502+
anf_2 ^= anf_1;
503+
assert_eq!(anf_2.to_string(), "x0*x1*x2*x4*x7 + x0*x1*x4*x7 + x1 + x3 + 1");
504+
505+
let anf_1 = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 8).unwrap();
506+
let mut anf_2 = AnfPolynomial::from_str("x0*x1*x2 + x0*x2 + x1*x0 + x1 + 1", 8).unwrap();
507+
let anf_3 = anf_1.clone() ^ anf_2.clone();
508+
assert_eq!(anf_3.to_string(), "x0*x1*x2 + x0*x2 + x0 + x2 + 1");
509+
anf_2 ^= anf_1;
510+
assert_eq!(anf_2.to_string(), "x0*x1*x2 + x0*x2 + x0 + x2 + 1");
511+
}
411512
}

0 commit comments

Comments
 (0)