Skip to content

Commit 2e0aa72

Browse files
committed
Add support for AND operation between ANF polynomial
1 parent 93df0cb commit 2e0aa72

File tree

1 file changed

+184
-6
lines changed

1 file changed

+184
-6
lines changed

src/anf_polynom.rs

Lines changed: 184 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +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, XOR_DIFFERENT_VAR_COUNT_PANIC_MSG};
4+
use crate::boolean_function_error::{POLYNOMIAL_ANF_TOO_BIG_VAR_COUNT_PANIC_MSG, XOR_DIFFERENT_VAR_COUNT_PANIC_MSG, AND_DIFFERENT_VAR_COUNT_PANIC_MSG};
55
use itertools::Itertools;
66
use num_bigint::BigUint;
77
use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
88
use std::fmt::Display;
9-
use std::ops::{BitXor, BitXorAssign};
9+
use std::ops::{BitAnd, BitAndAssign, BitXor, BitXorAssign};
1010
use fast_boolean_anf_transform::fast_bool_anf_transform_unsigned;
1111
use crate::{BigBooleanFunction, BooleanFunction, BooleanFunctionError, SmallBooleanFunction};
1212
use crate::utils::fast_anf_transform_biguint;
@@ -277,12 +277,12 @@ impl BitXorAssign for AnfPolynomial {
277277
if self.num_variables != rhs.num_variables {
278278
panic!("{}", XOR_DIFFERENT_VAR_COUNT_PANIC_MSG);
279279
}
280-
match (&mut self.polynomial, rhs.polynomial) {
280+
match (&mut self.polynomial, &rhs.polynomial) {
281281
(PolynomialFormat::Small(self_poly), PolynomialFormat::Small(rhs_poly)) => {
282282
*self_poly ^= rhs_poly;
283283
},
284284
(PolynomialFormat::Big(self_poly), PolynomialFormat::Small(rhs_poly)) => {
285-
*self_poly ^= BigUint::from_u64(rhs_poly).unwrap();
285+
*self_poly ^= BigUint::from_u64(*rhs_poly).unwrap();
286286
},
287287
(PolynomialFormat::Small(self_poly), PolynomialFormat::Big(rhs_poly)) => {
288288
*self_poly ^= rhs_poly.to_u64().unwrap();
@@ -307,6 +307,90 @@ impl BitXor for AnfPolynomial {
307307
}
308308
}
309309

310+
/// In-place AND operator for Boolean functions ANF polynomial
311+
///
312+
/// # Panics
313+
/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
314+
impl BitAndAssign for AnfPolynomial {
315+
fn bitand_assign(&mut self, rhs: Self) {
316+
*self = self.clone() & rhs;
317+
}
318+
}
319+
320+
/// AND operator for Boolean functions ANF polynomial
321+
///
322+
/// # Panics
323+
/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
324+
impl BitAnd for AnfPolynomial {
325+
type Output = AnfPolynomial;
326+
327+
fn bitand(self, rhs: Self) -> Self::Output {
328+
#[cfg(not(feature = "unsafe_disable_safety_checks"))]
329+
if self.num_variables != rhs.num_variables {
330+
panic!("{}", AND_DIFFERENT_VAR_COUNT_PANIC_MSG);
331+
}
332+
333+
fn small_anf_polynomial_multiply(left_poly: u64, right_poly: u64, num_variables: usize) -> u64 {
334+
let mut res = 0u64;
335+
for left_bit_pos in 0u64..(1 << num_variables) {
336+
if (left_poly >> left_bit_pos) & 1 == 0 {
337+
continue;
338+
}
339+
for right_bit_pos in 0u64..(1 << num_variables) {
340+
if (right_poly >> right_bit_pos) & 1 == 0 {
341+
continue;
342+
}
343+
res ^= 1 << (left_bit_pos | right_bit_pos);
344+
}
345+
}
346+
res
347+
}
348+
349+
fn big_anf_polynomial_multiply(left_poly: &BigUint, right_poly: &BigUint, num_variables: usize) -> BigUint {
350+
let mut res = BigUint::zero();
351+
for left_bit_pos in 0u64..(1 << num_variables) {
352+
if !left_poly.bit(left_bit_pos) {
353+
continue;
354+
}
355+
for right_bit_pos in 0u64..(1 << num_variables) {
356+
if !right_poly.bit(right_bit_pos) {
357+
continue;
358+
}
359+
let pos_to_flip = left_bit_pos | right_bit_pos;
360+
res.set_bit(pos_to_flip, !res.bit(pos_to_flip));
361+
}
362+
}
363+
res
364+
}
365+
366+
let new_polynomial = match (self.polynomial, rhs.polynomial) {
367+
(PolynomialFormat::Small(self_poly), PolynomialFormat::Small(rhs_poly)) => {
368+
PolynomialFormat::Small(small_anf_polynomial_multiply(self_poly, rhs_poly, self.num_variables))
369+
},
370+
(PolynomialFormat::Big(self_poly), PolynomialFormat::Small(rhs_poly)) => {
371+
PolynomialFormat::Big(
372+
BigUint::from_u64(
373+
small_anf_polynomial_multiply(self_poly.to_u64().unwrap(), rhs_poly, self.num_variables)
374+
).unwrap()
375+
)
376+
},
377+
(PolynomialFormat::Small(self_poly), PolynomialFormat::Big(rhs_poly)) => {
378+
PolynomialFormat::Small(
379+
small_anf_polynomial_multiply(self_poly, rhs_poly.to_u64().unwrap(), self.num_variables)
380+
)
381+
},
382+
(PolynomialFormat::Big(self_poly), PolynomialFormat::Big(rhs_poly)) => {
383+
PolynomialFormat::Big(big_anf_polynomial_multiply(&self_poly, &rhs_poly, self.num_variables))
384+
}
385+
};
386+
387+
AnfPolynomial {
388+
polynomial: new_polynomial,
389+
num_variables: self.num_variables
390+
}
391+
}
392+
}
393+
310394
#[cfg(test)]
311395
mod tests {
312396
use crate::anf_polynom::AnfPolynomial;
@@ -502,11 +586,105 @@ mod tests {
502586
anf_2 ^= anf_1;
503587
assert_eq!(anf_2.to_string(), "x0*x1*x2*x4*x7 + x0*x1*x4*x7 + x1 + x3 + 1");
504588

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();
589+
let anf_1 = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
590+
let mut anf_2 = AnfPolynomial::from_str("x0*x1*x2 + x0*x2 + x1*x0 + x1 + 1", 3).unwrap();
507591
let anf_3 = anf_1.clone() ^ anf_2.clone();
508592
assert_eq!(anf_3.to_string(), "x0*x1*x2 + x0*x2 + x0 + x2 + 1");
509593
anf_2 ^= anf_1;
510594
assert_eq!(anf_2.to_string(), "x0*x1*x2 + x0*x2 + x0 + x2 + 1");
511595
}
596+
597+
#[test]
598+
fn test_and() {
599+
let anf_1 = AnfPolynomial::from_str("x0*x1", 3).unwrap();
600+
let mut anf_2 = AnfPolynomial::from_str("x0*x2", 3).unwrap();
601+
let anf_3 = anf_1.clone() & anf_2.clone();
602+
assert_eq!(anf_3.to_string(), "x0*x1*x2");
603+
anf_2 &= anf_1;
604+
assert_eq!(anf_2.to_string(), "x0*x1*x2");
605+
606+
let anf_1 = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
607+
let mut anf_2 = AnfPolynomial::from_str("x0*x1 + x0*x1*x2 + x1 + 1", 3).unwrap();
608+
let anf_3 = anf_1.clone() & anf_2.clone();
609+
assert_eq!(anf_3.to_string(), "x0*x1*x2 + x1*x2 + x0 + x2");
610+
anf_2 &= anf_1;
611+
assert_eq!(anf_2.to_string(), "x0*x1*x2 + x1*x2 + x0 + x2");
612+
613+
let anf_1 = AnfPolynomial::from_str("x0*x1 + x0*x1*x2 + x1 + 1", 3).unwrap();
614+
let mut anf_2 = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
615+
let anf_3 = anf_1.clone() & anf_2.clone();
616+
assert_eq!(anf_3.to_string(), "x0*x1*x2 + x1*x2 + x0 + x2");
617+
anf_2 &= anf_1;
618+
assert_eq!(anf_2.to_string(), "x0*x1*x2 + x1*x2 + x0 + x2");
619+
620+
let anf_1 = AnfPolynomial::from_str("x3*x2*x1 + x0*x1 + x0*x1*x2 + x1 + 1", 4).unwrap();
621+
let mut anf_2 = AnfPolynomial::from_str("x0*x2*x3 + x0*x1 + x0 + x1 + x2", 4).unwrap();
622+
let anf_3 = anf_1.clone() & anf_2.clone();
623+
assert_eq!(anf_3.to_string(), "x0*x1*x2 + x0*x2*x3 + x1*x2 + x0 + x2");
624+
anf_2 &= anf_1;
625+
assert_eq!(anf_2.to_string(), "x0*x1*x2 + x0*x2*x3 + x1*x2 + x0 + x2");
626+
627+
let anf_1 = AnfPolynomial::from_str("x3*x2*x1 + x0*x1 + x0*x1*x2 + x1 + 1", 8).unwrap();
628+
let mut anf_2 = AnfPolynomial::from_str("x0*x2*x3 + x0*x1 + x0 + x1 + x2", 8).unwrap();
629+
let anf_3 = anf_1.clone() & anf_2.clone();
630+
assert_eq!(anf_3.to_string(), "x0*x1*x2 + x0*x2*x3 + x1*x2 + x0 + x2");
631+
anf_2 &= anf_1;
632+
assert_eq!(anf_2.to_string(), "x0*x1*x2 + x0*x2*x3 + x1*x2 + x0 + x2");
633+
634+
let anf_1 = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
635+
let mut anf_2 = AnfPolynomial::from_str("0", 3).unwrap();
636+
let anf_3 = anf_1.clone() & anf_2.clone();
637+
assert_eq!(anf_3.to_string(), "0");
638+
anf_2 &= anf_1;
639+
assert_eq!(anf_2.to_string(), "0");
640+
641+
let anf_1 = AnfPolynomial::from_str("0", 3).unwrap();
642+
let mut anf_2 = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
643+
let anf_3 = anf_1.clone() & anf_2.clone();
644+
assert_eq!(anf_3.to_string(), "0");
645+
anf_2 &= anf_1;
646+
assert_eq!(anf_2.to_string(), "0");
647+
648+
let anf_1 = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
649+
let mut anf_2 = AnfPolynomial::from_str("1", 3).unwrap();
650+
let anf_3 = anf_1.clone() & anf_2.clone();
651+
assert_eq!(anf_3.to_string(), "x0*x1 + x0 + x1 + x2");
652+
anf_2 &= anf_1;
653+
assert_eq!(anf_2.to_string(), "x0*x1 + x0 + x1 + x2");
654+
655+
let anf_1 = AnfPolynomial::from_str("1", 3).unwrap();
656+
let mut anf_2 = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
657+
let anf_3 = anf_1.clone() & anf_2.clone();
658+
assert_eq!(anf_3.to_string(), "x0*x1 + x0 + x1 + x2");
659+
anf_2 &= anf_1;
660+
assert_eq!(anf_2.to_string(), "x0*x1 + x0 + x1 + x2");
661+
662+
let anf_1 = AnfPolynomial::from_str("x3*x7 + x3 + x4*x5 + x4*x6 + x5*x6*x7 + x6 + x7 + 1", 8).unwrap();
663+
let mut anf_2 = AnfPolynomial::from_str("x3*x5*x6*x7 + x3*x6*x7 + x3*x6 + x3*x7 + x3 + x4*x5*x6 + x4*x5*x7 + x4*x7 + x4 + x6*x7 + x6 + x7 + 1", 8).unwrap();
664+
let anf_3 = anf_1.clone() & anf_2.clone();
665+
assert_eq!(anf_3.to_string(), "x3*x4*x5*x7 + x3*x4*x5 + x4*x5*x6 + x3*x4*x7 + x4*x5*x7 + x3*x6*x7 + x3*x4 + x3*x6 + x3*x7 + x4*x7 + x6*x7 + x3 + x4 + x6 + x7 + 1");
666+
anf_2 &= anf_1;
667+
assert_eq!(anf_2.to_string(), "x3*x4*x5*x7 + x3*x4*x5 + x4*x5*x6 + x3*x4*x7 + x4*x5*x7 + x3*x6*x7 + x3*x4 + x3*x6 + x3*x7 + x4*x7 + x6*x7 + x3 + x4 + x6 + x7 + 1");
668+
669+
let anf_1 = AnfPolynomial::from_str("x3*x5*x6*x7 + x3*x6*x7 + x3*x6 + x3*x7 + x3 + x4*x5*x6 + x4*x5*x7 + x4*x7 + x4 + x6*x7 + x6 + x7 + 1", 8).unwrap();
670+
let mut anf_2 = AnfPolynomial::from_str("x3*x7 + x3 + x4*x5 + x4*x6 + x5*x6*x7 + x6 + x7 + 1", 8).unwrap();
671+
let anf_3 = anf_1.clone() & anf_2.clone();
672+
assert_eq!(anf_3.to_string(), "x3*x4*x5*x7 + x3*x4*x5 + x4*x5*x6 + x3*x4*x7 + x4*x5*x7 + x3*x6*x7 + x3*x4 + x3*x6 + x3*x7 + x4*x7 + x6*x7 + x3 + x4 + x6 + x7 + 1");
673+
anf_2 &= anf_1;
674+
assert_eq!(anf_2.to_string(), "x3*x4*x5*x7 + x3*x4*x5 + x4*x5*x6 + x3*x4*x7 + x4*x5*x7 + x3*x6*x7 + x3*x4 + x3*x6 + x3*x7 + x4*x7 + x6*x7 + x3 + x4 + x6 + x7 + 1");
675+
676+
let anf_1 = AnfPolynomial::from_str("0", 8).unwrap();
677+
let mut anf_2 = AnfPolynomial::from_str("x3*x7 + x3 + x4*x5 + x4*x6 + x5*x6*x7 + x6 + x7 + 1", 8).unwrap();
678+
let anf_3 = anf_1.clone() & anf_2.clone();
679+
assert_eq!(anf_3.to_string(), "0");
680+
anf_2 &= anf_1;
681+
assert_eq!(anf_2.to_string(), "0");
682+
683+
let anf_1 = AnfPolynomial::from_str("1", 8).unwrap();
684+
let mut anf_2 = AnfPolynomial::from_str("x3*x7 + x3 + x4*x5 + x4*x6 + x5*x6*x7 + x6 + x7 + 1", 8).unwrap();
685+
let anf_3 = anf_1.clone() & anf_2.clone();
686+
assert_eq!(anf_3.to_string(), "x5*x6*x7 + x4*x5 + x4*x6 + x3*x7 + x3 + x6 + x7 + 1");
687+
anf_2 &= anf_1;
688+
assert_eq!(anf_2.to_string(), "x5*x6*x7 + x4*x5 + x4*x6 + x3*x7 + x3 + x6 + x7 + 1");
689+
}
512690
}

0 commit comments

Comments
 (0)