"""Generalized entropy calculations for patterns (MERCURIAL A.8)."""
import numpy as np
from mercurial.core.patterns import Pattern
[docs]
def shannon_entropy(probabilities: np.ndarray, base: float = 2.0) -> float:
"""
Shannon entropy H = -Σ p_i log(p_i).
Parameters
----------
probabilities : array
Probability distribution (must sum to 1).
base : float
Logarithm base (2 for bits, e for nats).
Returns
-------
float
Entropy in chosen units.
"""
probs = probabilities[probabilities > 0]
if base == 2:
return -np.sum(probs * np.log2(probs))
elif base == np.e:
return -np.sum(probs * np.log(probs))
else:
return -np.sum(probs * np.log(probs) / np.log(base))
[docs]
def thermodynamic_entropy(energy_distribution: np.ndarray, temperature: float) -> float:
"""
Thermodynamic entropy S_therm = (U - F)/T.
Here we approximate from energy distribution variance.
"""
np.mean(energy_distribution)
variance = np.var(energy_distribution)
# Simple approximation: S ~ k_B * log(σ²) for a Gaussian distribution
return 1.380649e-23 * 0.5 * np.log(max(variance, 1e-30))
[docs]
def phenomenological_disorder(pattern_coherence: float) -> float:
"""
Phenomenological disorder measure (0 = fully ordered, 1 = fully disordered).
pattern_coherence ∈ [0,1] (1 = maximal coherence).
"""
return 1.0 - pattern_coherence
[docs]
class GeneralizedEntropy:
"""Implements S_gen from Definition 1.6."""
def __init__(self, beta_info: float = 1.0, beta_therm: float = 1.0, beta_ph: float = 1.0):
self.beta_info = beta_info
self.beta_therm = beta_therm
self.beta_ph = beta_ph
[docs]
def compute(self, info_entropy: float, therm_entropy: float, ph_disorder: float) -> float:
"""S_gen = β_info * I + β_therm * S_therm + β_ph * S_ph."""
return (
self.beta_info * info_entropy
+ self.beta_therm * therm_entropy
+ self.beta_ph * ph_disorder
)
[docs]
def from_pattern(self, pattern: "Pattern") -> float:
"""Compute S_gen directly from a Pattern object."""
info = pattern.information_content()
# Simplified: use pattern's free energy as proxy for therm entropy
therm = pattern.free_energy() / 1e-20 # scaling
ph = phenomenological_disorder(pattern.coherence())
return self.compute(info, therm, ph)