use rayon::prelude::*;
use crate::fvalue::FValue;
pub trait CertificateComplexity {
fn point_certificate_complexity(&self, x: usize) -> u32;
fn certificate_complexity(&self) -> u32;
fn certificate_complexity_1(&self) -> u32;
fn certificate_complexity_0(&self) -> u32;
fn mean_certificate_complexity(&self) -> f32;
}
fn greedy_upper_bound(conflicts: &[usize], n: usize) -> usize {
if conflicts.is_empty() {
return 0;
}
let mut remaining: Vec<usize> = conflicts.to_vec();
let mut count = 0;
while !remaining.is_empty() {
let best_var = (0..n)
.max_by_key(|&var| {
let mask = 1 << var;
remaining.iter().filter(|&&c| c & mask != 0).count()
})
.unwrap();
let mask = 1 << best_var;
count += 1;
remaining.retain(|&c| c & mask == 0);
}
count
}
fn minimum_certificate_size(conflicts: &[usize], n: usize) -> u32 {
if conflicts.is_empty() {
return 0;
}
let upper_bound = greedy_upper_bound(conflicts, n);
if upper_bound == 1 {
return 1;
}
for size in 1..upper_bound {
for subset_mask in SubsetMaskIterator::new(n, size) {
if conflicts.iter().all(|&diff| diff & subset_mask != 0) {
return size as u32;
}
}
}
upper_bound as u32
}
impl CertificateComplexity for FValue<bool> {
fn point_certificate_complexity(&self, x: usize) -> u32 {
let n = self.n_vars();
let f_x = *self.get(x).unwrap();
let conflicts: Vec<usize> = (0..(1 << n))
.filter(|&y| *self.get(y).unwrap() != f_x)
.map(|y| x ^ y)
.collect();
minimum_certificate_size(&conflicts, n)
}
fn certificate_complexity(&self) -> u32 {
let n = self.n_vars();
let num_inputs = 1 << n;
if n >= 4 {
(0..num_inputs)
.into_par_iter()
.map(|x| self.point_certificate_complexity(x))
.max()
.unwrap_or(0)
} else {
(0..num_inputs)
.map(|x| self.point_certificate_complexity(x))
.max()
.unwrap_or(0)
}
}
fn certificate_complexity_1(&self) -> u32 {
let n = self.n_vars();
let num_inputs = 1 << n;
if n >= 4 {
(0..num_inputs)
.into_par_iter()
.filter(|&x| *self.get(x).unwrap())
.map(|x| self.point_certificate_complexity(x))
.max()
.unwrap_or(0)
} else {
(0..num_inputs)
.filter(|&x| *self.get(x).unwrap())
.map(|x| self.point_certificate_complexity(x))
.max()
.unwrap_or(0)
}
}
fn certificate_complexity_0(&self) -> u32 {
let n = self.n_vars();
let num_inputs = 1 << n;
if n >= 4 {
(0..num_inputs)
.into_par_iter()
.filter(|&x| !*self.get(x).unwrap())
.map(|x| self.point_certificate_complexity(x))
.max()
.unwrap_or(0)
} else {
(0..num_inputs)
.filter(|&x| !*self.get(x).unwrap())
.map(|x| self.point_certificate_complexity(x))
.max()
.unwrap_or(0)
}
}
fn mean_certificate_complexity(&self) -> f32 {
let n = self.n_vars();
let num_inputs = 1 << n;
if n >= 4 {
(0..num_inputs)
.into_par_iter()
.map(|x| self.point_certificate_complexity(x))
.sum::<u32>() as f32
/ num_inputs as f32
} else {
(0..num_inputs)
.map(|x| self.point_certificate_complexity(x))
.sum::<u32>() as f32
/ num_inputs as f32
}
}
}
struct SubsetMaskIterator {
current: usize,
max: usize,
done: bool,
}
impl SubsetMaskIterator {
fn new(n: usize, k: usize) -> Self {
if k == 0 {
return Self {
current: 0,
max: (1 << n) - 1,
done: false,
};
}
if k > n {
return Self {
current: 0,
max: 0,
done: true,
};
}
let current = (1 << k) - 1;
let max = (1 << n) - 1;
Self {
current,
max,
done: false,
}
}
#[inline]
fn next_subset(v: usize) -> usize {
let c = v & v.wrapping_neg();
let r = v + c;
(((r ^ v) >> 2) / c) | r
}
}
impl Iterator for SubsetMaskIterator {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let result = self.current;
if self.current == 0 {
self.done = true;
return Some(result);
}
let next = Self::next_subset(self.current);
if next > self.max {
self.done = true;
} else {
self.current = next;
}
Some(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constant_function() {
let f_true = FValue::<bool>::constant(3, true);
assert_eq!(f_true.certificate_complexity(), 0);
let f_false = FValue::<bool>::constant(3, false);
assert_eq!(f_false.certificate_complexity(), 0);
}
#[test]
fn test_single_variable() {
let f = FValue::new(vec![false, true]);
assert_eq!(f.certificate_complexity(), 1);
}
#[test]
fn test_and_function() {
let f = FValue::new(vec![false, false, false, true]);
assert_eq!(f.point_certificate_complexity(3), 2); assert_eq!(f.point_certificate_complexity(0), 1); assert_eq!(f.certificate_complexity(), 2);
}
#[test]
fn test_or_function() {
let f = FValue::new(vec![false, true, true, true]);
assert_eq!(f.point_certificate_complexity(0), 2); assert_eq!(f.point_certificate_complexity(1), 1); assert_eq!(f.certificate_complexity(), 2);
}
#[test]
fn test_parity_function() {
let f = FValue::parity(3);
assert_eq!(f.certificate_complexity(), 3);
let f2 = FValue::parity(2);
assert_eq!(f2.certificate_complexity(), 2);
}
#[test]
fn test_majority_function() {
let f = FValue::majority(3);
assert_eq!(f.certificate_complexity(), 2);
}
#[test]
fn test_certificate_complexity_bounds() {
let f = FValue::random(4);
let cc = f.certificate_complexity();
assert!(cc <= 4);
}
#[test]
fn test_certificate_0_and_1() {
let f = FValue::new(vec![false, true, true, true]);
assert_eq!(f.certificate_complexity_0(), 2);
assert_eq!(f.certificate_complexity_1(), 1);
}
#[test]
fn test_subset_mask_iterator() {
let subsets: Vec<_> = SubsetMaskIterator::new(4, 2).collect();
assert_eq!(subsets.len(), 6);
let subsets: Vec<_> = SubsetMaskIterator::new(5, 3).collect();
assert_eq!(subsets.len(), 10);
let subsets: Vec<_> = SubsetMaskIterator::new(3, 0).collect();
assert_eq!(subsets.len(), 1); assert_eq!(subsets[0], 0);
}
#[test]
fn test_subset_mask_values() {
for n in 1..=6 {
for k in 0..=n {
for mask in SubsetMaskIterator::new(n, k) {
assert_eq!(
mask.count_ones() as usize,
k,
"Mask {} should have {} bits set",
mask,
k
);
assert!(mask < (1 << n), "Mask {} should be less than 2^{}", mask, n);
}
}
}
}
#[test]
fn test_larger_function() {
let f = FValue::majority(5);
let cc = f.certificate_complexity();
assert_eq!(cc, 3);
}
#[test]
fn test_greedy_upper_bound() {
let conflicts = vec![0b001, 0b010, 0b100];
assert_eq!(greedy_upper_bound(&conflicts, 3), 3);
let conflicts2 = vec![0b101, 0b111, 0b011];
assert_eq!(greedy_upper_bound(&conflicts2, 3), 1);
}
#[test]
fn test_performance_6_vars() {
let f = FValue::majority(6);
let cc = f.certificate_complexity();
assert_eq!(cc, 4); }
}