use crate::types::tensor_network::{MinimalCut, TensorNetworkState};
use crate::TribeResult;
pub fn entropy_from_cut(cut: &MinimalCut) -> TribeResult<u64> {
if cut.edges.is_empty() {
return Ok(0);
}
let cut_size = cut.cut_size as f64;
let avg_bond_dim = if cut.edges.is_empty() {
2.0
} else {
(cut.total_bond_dimension as f64) / (cut.edges.len() as f64)
};
let bond_dim_safe = avg_bond_dim.max(2.0);
let entropy_f64 = cut_size * bond_dim_safe.ln();
let entropy_fixed = (entropy_f64 * 1_000_000.0) as u64;
Ok(entropy_fixed)
}
pub fn mutual_information(entropy_a: u64, entropy_b: u64, entropy_union: u64) -> TribeResult<u64> {
let s_a = entropy_a as f64 / 1_000_000.0;
let s_b = entropy_b as f64 / 1_000_000.0;
let s_union = entropy_union as f64 / 1_000_000.0;
let mutual_info = (s_a + s_b - s_union).max(0.0);
Ok((mutual_info * 1_000_000.0) as u64)
}
pub fn effective_distance(mutual_info: u64, max_entropy: u64) -> TribeResult<u64> {
if max_entropy == 0 {
return Ok(1_000_000); }
let mutual_f64 = mutual_info as f64 / 1_000_000.0;
let max_f64 = max_entropy as f64 / 1_000_000.0;
let distance = (1.0 - (mutual_f64 / max_f64)).clamp(0.0, 1.0);
Ok((distance * 1_000_000.0) as u64)
}
pub fn total_network_entropy(network_state: &TensorNetworkState) -> u64 {
network_state
.edges
.iter()
.map(|edge| {
let bond_dim = edge.bond_dimension.max(2) as f64;
(bond_dim.ln() * 1_000_000.0) as u64
})
.fold(0u64, |acc, val| acc.saturating_add(val))
}
pub fn approximate_minimal_cut(network_state: &TensorNetworkState) -> MinimalCut {
MinimalCut::new(network_state.edges.clone())
}
pub fn coherence_probability(local_entropy: f64, max_entropy: f64) -> f64 {
if max_entropy <= 0.0 {
return 0.0;
}
let normalized = local_entropy / max_entropy;
normalized.tanh()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_entropy_from_empty_cut() {
let cut = MinimalCut::new(vec![]);
let entropy = entropy_from_cut(&cut).unwrap();
assert_eq!(entropy, 0);
}
#[test]
fn test_entropy_from_single_edge() {
let edge = EntanglementEdge::new(0, b"src".to_vec(), b"dst".to_vec(), 2, 500_000, 1000);
let cut = MinimalCut::new(vec![edge]);
let entropy = entropy_from_cut(&cut).unwrap();
assert!(entropy > 600_000 && entropy < 800_000);
}
#[test]
fn test_mutual_information() {
let s_a = 1_000_000; let s_b = 1_000_000; let s_union = 1_500_000;
let mi = mutual_information(s_a, s_b, s_union).unwrap();
assert_eq!(mi, 500_000);
}
#[test]
fn test_effective_distance() {
let mi = 500_000; let max = 1_000_000;
let d = effective_distance(mi, max).unwrap();
assert_eq!(d, 500_000);
}
#[test]
fn test_coherence_probability() {
let local = 0.5;
let max = 1.0;
let p = coherence_probability(local, max);
assert!(p > 0.45 && p < 0.47);
}
#[test]
fn test_total_network_entropy() {
let mut state = TensorNetworkState::new();
let edge1 = EntanglementEdge::new(0, b"a".to_vec(), b"b".to_vec(), 2, 500_000, 1000);
let edge2 = EntanglementEdge::new(1, b"b".to_vec(), b"c".to_vec(), 2, 500_000, 1000);
state.edges.push(edge1);
state.edges.push(edge2);
let total = total_network_entropy(&state);
assert!(total > 1_300_000 && total < 1_500_000);
}
}