#[cfg(feature = "fmatrix")]
use crate::fmulti::FMulti;
use crate::{auxiliar::SubsetIterator, fvalue::FValue};
use rayon::prelude::*;
use std::hash::Hash;
const PARALLEL_THRESHOLD: usize = 10;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct EntanglementSet {
pub entanglement: usize,
pub set1: Vec<usize>,
pub set2: Vec<usize>,
}
impl Default for EntanglementSet {
fn default() -> Self {
EntanglementSet {
entanglement: usize::MAX,
set1: vec![],
set2: vec![],
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct EntropySet {
pub entropy: f32,
pub set1: Vec<usize>,
pub set2: Vec<usize>,
}
impl Default for EntropySet {
fn default() -> Self {
EntropySet {
entropy: f32::MAX,
set1: vec![],
set2: vec![],
}
}
}
pub trait NVars {
fn num_vars(&self) -> usize;
}
pub trait WithInformation {
fn get_information(&self, vars: &[usize]) -> usize;
}
pub trait WithMultipleInformation {
fn get_multiple_information(&self, vars: &[usize]) -> Vec<usize>;
}
pub trait WithEntropy {
fn get_entropy(&self, vars: &[usize]) -> f32;
}
pub trait Entanglement {
fn entanglement(&self) -> usize;
fn entanglement_sets(&self) -> Vec<EntanglementSet>;
fn minmax_entanglement(&self) -> usize;
fn minmax_entanglement_sets(&self) -> Vec<EntanglementSet>;
}
pub trait SubInfos {
fn sub_infos(&self) -> Vec<usize>;
}
pub trait Entropy {
fn entropy(&self) -> f32;
fn entropy_sets(&self) -> Vec<EntropySet>;
}
impl<T: WithInformation + NVars + Sync> Entanglement for T {
fn entanglement(&self) -> usize {
let n = self.num_vars();
if n >= PARALLEL_THRESHOLD {
SubsetIterator::new(n)
.into_par_iter()
.map(|(set1, set2)| {
let s1 = self.get_information(&set1);
let s2 = self.get_information(&set2);
s1 + s2
})
.min()
.unwrap_or(usize::MAX)
} else {
SubsetIterator::new(n)
.map(|(set1, set2)| {
let s1 = self.get_information(&set1);
let s2 = self.get_information(&set2);
s1 + s2
})
.min()
.unwrap_or(usize::MAX)
}
}
fn entanglement_sets(&self) -> Vec<EntanglementSet> {
let n = self.num_vars();
if n >= PARALLEL_THRESHOLD {
SubsetIterator::new(n)
.into_par_iter()
.map(|(set1, set2)| {
let s1 = self.get_information(&set1);
let s2 = self.get_information(&set2);
EntanglementSet {
entanglement: s1 + s2,
set1,
set2,
}
})
.collect()
} else {
SubsetIterator::new(n)
.map(|(set1, set2)| {
let s1 = self.get_information(&set1);
let s2 = self.get_information(&set2);
EntanglementSet {
entanglement: s1 + s2,
set1,
set2,
}
})
.collect()
}
}
fn minmax_entanglement(&self) -> usize {
let n = self.num_vars();
if n >= PARALLEL_THRESHOLD {
SubsetIterator::new(n)
.into_par_iter()
.map(|(set1, set2)| {
let s1 = self.get_information(&set1);
let s2 = self.get_information(&set2);
s1.max(s2)
})
.min()
.unwrap_or(usize::MAX)
} else {
SubsetIterator::new(n)
.map(|(set1, set2)| {
let s1 = self.get_information(&set1);
let s2 = self.get_information(&set2);
s1.max(s2)
})
.min()
.unwrap_or(usize::MAX)
}
}
fn minmax_entanglement_sets(&self) -> Vec<EntanglementSet> {
let n = self.num_vars();
if n >= PARALLEL_THRESHOLD {
SubsetIterator::new(n)
.into_par_iter()
.map(|(set1, set2)| {
let s1 = self.get_information(&set1);
let s2 = self.get_information(&set2);
EntanglementSet {
entanglement: s1.max(s2),
set1,
set2,
}
})
.collect()
} else {
SubsetIterator::new(n)
.map(|(set1, set2)| {
let s1 = self.get_information(&set1);
let s2 = self.get_information(&set2);
EntanglementSet {
entanglement: s1.max(s2),
set1,
set2,
}
})
.collect()
}
}
}
impl<T: WithEntropy + NVars + Sync> Entropy for T {
fn entropy(&self) -> f32 {
let n = self.num_vars();
if n >= PARALLEL_THRESHOLD {
SubsetIterator::new(n)
.into_par_iter()
.map(|(set1, set2)| {
let s1 = self.get_entropy(&set1);
let s2 = self.get_entropy(&set2);
s1 + s2
})
.min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
.unwrap_or(f32::MAX)
} else {
SubsetIterator::new(n)
.map(|(set1, set2)| {
let s1 = self.get_entropy(&set1);
let s2 = self.get_entropy(&set2);
s1 + s2
})
.min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
.unwrap_or(f32::MAX)
}
}
fn entropy_sets(&self) -> Vec<EntropySet> {
let n = self.num_vars();
if n >= PARALLEL_THRESHOLD {
SubsetIterator::new(n)
.into_par_iter()
.map(|(set1, set2)| {
let s1 = self.get_entropy(&set1);
let s2 = self.get_entropy(&set2);
EntropySet {
entropy: s1 + s2,
set1,
set2,
}
})
.collect()
} else {
SubsetIterator::new(n)
.map(|(set1, set2)| {
let s1 = self.get_entropy(&set1);
let s2 = self.get_entropy(&set2);
EntropySet {
entropy: s1 + s2,
set1,
set2,
}
})
.collect()
}
}
}
impl<T: WithInformation + NVars + Sync> SubInfos for T {
fn sub_infos(&self) -> Vec<usize> {
let n = self.num_vars();
if n >= PARALLEL_THRESHOLD {
(0..n)
.into_par_iter()
.map(|i| self.get_information(&[i]))
.collect()
} else {
(0..n).map(|i| self.get_information(&[i])).collect()
}
}
}
#[cfg(feature = "fmatrix")]
impl<T: crate::fmulti::GenericValue + Send + Sync> NVars for FMulti<T> {
fn num_vars(&self) -> usize {
self.repr().len().ilog2() as usize
}
}
#[cfg(feature = "fmatrix")]
impl<T: crate::fmulti::GenericValue + Send + Hash + Sync> WithInformation for FMulti<T> {
fn get_information(&self, vars: &[usize]) -> usize {
self.count_forms_by_multiple_fixed(vars)
}
}
impl<T: crate::fvalue::GenericValue + Send + Sync> NVars for FValue<T> {
fn num_vars(&self) -> usize {
self.repr().len().ilog2() as usize
}
}
impl<T: crate::fvalue::GenericValue + Send + Hash + Sync> WithInformation for FValue<T> {
fn get_information(&self, vars: &[usize]) -> usize {
self.count_forms_by_multiple_fixed(vars)
}
}
impl<T: crate::fvalue::GenericValue + Send + Hash + Sync> WithEntropy for FValue<T> {
fn get_entropy(&self, vars: &[usize]) -> f32 {
self.set_entropy(vars)
}
}
pub trait EquanimityImportance {
fn equanimity_importance(&self) -> f32;
}
impl<T: crate::fvalue::GenericValue> EquanimityImportance for FValue<T> {
fn equanimity_importance(&self) -> f32 {
fn pow2(n: usize) -> usize {
1 << n
}
let mut importance_sum = 0;
let num_input_bits = self.repr().len().ilog2() as usize;
for i in 1..=num_input_bits {
for j in (0..pow2(num_input_bits)).step_by(pow2(i)) {
for k in 0..pow2(i - 1) {
if self.repr()[j + k] != self.repr()[j + k + pow2(i - 1)] {
importance_sum += 1;
}
}
}
}
importance_sum as f32 / (num_input_bits * pow2(num_input_bits - 1)) as f32
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::fvalue::FValue;
#[test]
fn test_entanglement_set_default() {
let es = EntanglementSet::default();
assert_eq!(es.entanglement, usize::MAX);
assert_eq!(es.set1.len(), 0);
assert_eq!(es.set2.len(), 0);
}
#[test]
fn test_entropy_set_default() {
let es = EntropySet::default();
assert_eq!(es.entropy, f32::MAX);
assert_eq!(es.set1.len(), 0);
assert_eq!(es.set2.len(), 0);
}
#[test]
fn test_nvars_fvalue() {
let f = FValue::parity(3);
assert_eq!(f.num_vars(), 3);
let f4 = FValue::majority(4);
assert_eq!(f4.num_vars(), 4);
}
#[test]
fn test_with_information() {
let f = FValue::parity(3);
let info_empty = f.get_information(&[]);
assert!(info_empty > 0);
let info_single = f.get_information(&[0]);
assert!(info_single > 0);
let info_all = f.get_information(&[0, 1, 2]);
assert!(info_all > 0);
}
#[test]
fn test_entanglement_computation() {
let f = FValue::parity(3);
let ent = f.entanglement();
assert!(ent < usize::MAX);
assert!(ent > 0);
}
#[test]
fn test_entanglement_sets() {
let f = FValue::parity(2);
let ent_sets = f.entanglement_sets();
assert!(!ent_sets.is_empty());
for es in &ent_sets {
assert!(es.entanglement < usize::MAX);
assert!(es.set1.len() + es.set2.len() <= f.num_vars());
}
}
#[test]
fn test_minmax_entanglement() {
let f = FValue::majority(3);
let minmax = f.minmax_entanglement();
assert!(minmax < usize::MAX);
assert!(minmax > 0);
}
#[test]
fn test_minmax_entanglement_sets() {
let f = FValue::majority(3);
let minmax_sets = f.minmax_entanglement_sets();
assert!(!minmax_sets.is_empty());
for es in &minmax_sets {
assert!(es.entanglement < usize::MAX);
}
}
#[test]
fn test_entropy_computation() {
let f = FValue::parity(3);
let ent = f.entropy();
assert!(ent < f32::MAX);
assert!(ent > 0.0);
}
#[test]
fn test_entropy_sets() {
let f = FValue::parity(3);
let ent_sets = f.entropy_sets();
assert!(!ent_sets.is_empty());
for es in &ent_sets {
assert!(es.entropy < f32::MAX);
assert!(es.entropy >= 0.0);
}
}
#[test]
fn test_sub_infos() {
let f = FValue::parity(3);
let sub_infos = f.sub_infos();
assert_eq!(sub_infos.len(), 3);
for info in sub_infos {
assert!(info > 0);
}
}
#[test]
fn test_equanimity_importance() {
let f = FValue::majority(3);
let eq_imp = f.equanimity_importance();
assert!(eq_imp >= 0.0);
assert!(eq_imp <= 1.0);
}
#[test]
fn test_entanglement_parity_vs_majority() {
let parity_f = FValue::parity(3);
let majority_f = FValue::majority(3);
let parity_ent = parity_f.entanglement();
let majority_ent = majority_f.entanglement();
assert!(parity_ent < usize::MAX);
assert!(majority_ent < usize::MAX);
assert!(parity_ent > 0);
assert!(majority_ent > 0);
}
#[test]
fn test_with_entropy() {
let f = FValue::parity(3);
let entropy_empty = f.get_entropy(&[]);
let entropy_single = f.get_entropy(&[0]);
let entropy_all = f.get_entropy(&[0, 1, 2]);
assert!((0.0..f32::MAX).contains(&entropy_empty));
assert!((0.0..f32::MAX).contains(&entropy_single));
assert!((0.0..f32::MAX).contains(&entropy_all));
}
}