git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
232 lines
7.6 KiB
Markdown
232 lines
7.6 KiB
Markdown
# 07 - Causal Emergence
|
|
|
|
## Overview
|
|
|
|
Implementation of causal emergence theory for detecting when macro-level descriptions have more causal power than micro-level ones, using effective information metrics and coarse-graining optimization.
|
|
|
|
## Key Innovation
|
|
|
|
**Causal Emergence Detection**: Automatically find the level of description at which a system has maximum causal power, revealing emergent macro-dynamics.
|
|
|
|
```rust
|
|
pub struct CausalEmergence {
|
|
/// Transition probability matrix (micro level)
|
|
micro_tpm: TransitionMatrix,
|
|
/// Coarse-graining mappings
|
|
coarse_grainings: Vec<CoarseGraining>,
|
|
/// Effective information at each level
|
|
ei_levels: Vec<f64>,
|
|
}
|
|
```
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ Micro-Level System │
|
|
│ ┌─────────────────────────────────┐ │
|
|
│ │ States: s₁, s₂, ..., sₙ │ │
|
|
│ │ TPM: P(sⱼ|sᵢ) │ │
|
|
│ │ EI_micro = I(effect|cause) │ │
|
|
│ └─────────────────────────────────┘ │
|
|
├─────────────────────────────────────────┤
|
|
│ Coarse-Graining │
|
|
│ ┌─────────────────────────────────┐ │
|
|
│ │ Macro states: S₁, S₂, ..., Sₘ │ │
|
|
│ │ Mapping: μ: micro → macro │ │
|
|
│ │ Macro TPM: P(Sⱼ|Sᵢ) │ │
|
|
│ └─────────────────────────────────┘ │
|
|
├─────────────────────────────────────────┤
|
|
│ Emergence Detection │
|
|
│ ┌─────────────────────────────────┐ │
|
|
│ │ EI_macro > EI_micro ? │ │
|
|
│ │ Causal emergence = YES! │ │
|
|
│ └─────────────────────────────────┘ │
|
|
└─────────────────────────────────────────┘
|
|
```
|
|
|
|
## Effective Information
|
|
|
|
```rust
|
|
impl EffectiveInformation {
|
|
/// Compute EI for a transition matrix
|
|
pub fn compute(&self, tpm: &TransitionMatrix) -> f64 {
|
|
let n = tpm.size();
|
|
let mut ei = 0.0;
|
|
|
|
// EI = average mutual information between cause and effect
|
|
// under maximum entropy intervention
|
|
for i in 0..n {
|
|
for j in 0..n {
|
|
let p_joint = tpm.get(i, j) / n as f64; // Max entropy cause
|
|
let p_effect = tpm.column_sum(j) / n as f64;
|
|
let p_cause = 1.0 / n as f64;
|
|
|
|
if p_joint > 0.0 && p_effect > 0.0 {
|
|
ei += p_joint * (p_joint / (p_cause * p_effect)).log2();
|
|
}
|
|
}
|
|
}
|
|
|
|
ei
|
|
}
|
|
|
|
/// Compute causal emergence
|
|
pub fn causal_emergence(
|
|
&self,
|
|
micro_tpm: &TransitionMatrix,
|
|
macro_tpm: &TransitionMatrix,
|
|
) -> f64 {
|
|
let ei_micro = self.compute(micro_tpm);
|
|
let ei_macro = self.compute(macro_tpm);
|
|
|
|
// Normalize by log of state space size
|
|
let norm_micro = ei_micro / (micro_tpm.size() as f64).log2();
|
|
let norm_macro = ei_macro / (macro_tpm.size() as f64).log2();
|
|
|
|
norm_macro - norm_micro
|
|
}
|
|
}
|
|
```
|
|
|
|
## Coarse-Graining Optimization
|
|
|
|
```rust
|
|
impl CoarseGraining {
|
|
/// Find optimal coarse-graining that maximizes EI
|
|
pub fn optimize(&mut self, micro_tpm: &TransitionMatrix) -> CoarseGraining {
|
|
let n = micro_tpm.size();
|
|
let mut best_cg = self.clone();
|
|
let mut best_ei = 0.0;
|
|
|
|
// Try different numbers of macro states
|
|
for m in 2..n {
|
|
// Use spectral clustering to find groupings
|
|
let grouping = self.spectral_partition(micro_tpm, m);
|
|
|
|
// Compute macro TPM
|
|
let macro_tpm = self.induce_macro_tpm(micro_tpm, &grouping);
|
|
|
|
// Compute EI
|
|
let ei = EffectiveInformation::new().compute(¯o_tpm);
|
|
|
|
if ei > best_ei {
|
|
best_ei = ei;
|
|
best_cg = CoarseGraining::from_grouping(grouping);
|
|
}
|
|
}
|
|
|
|
best_cg
|
|
}
|
|
|
|
/// Spectral clustering for state grouping
|
|
fn spectral_partition(&self, tpm: &TransitionMatrix, k: usize) -> Vec<usize> {
|
|
// Compute Laplacian
|
|
let laplacian = tpm.laplacian();
|
|
|
|
// Find k smallest eigenvectors
|
|
let eigenvecs = laplacian.eigenvectors(k);
|
|
|
|
// K-means on eigenvector space
|
|
kmeans(&eigenvecs, k)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Causal Hierarchy
|
|
|
|
```rust
|
|
pub struct CausalHierarchy {
|
|
/// Levels of description
|
|
levels: Vec<HierarchyLevel>,
|
|
/// EI at each level
|
|
ei_profile: Vec<f64>,
|
|
/// Emergence peaks
|
|
peaks: Vec<usize>,
|
|
}
|
|
|
|
impl CausalHierarchy {
|
|
/// Build hierarchy and detect emergence peaks
|
|
pub fn build(&mut self, micro_tpm: &TransitionMatrix) {
|
|
let mut current_tpm = micro_tpm.clone();
|
|
|
|
for level in 0..self.max_levels {
|
|
// Compute EI at this level
|
|
let ei = EffectiveInformation::new().compute(¤t_tpm);
|
|
self.ei_profile.push(ei);
|
|
|
|
// Find optimal coarse-graining for next level
|
|
let cg = CoarseGraining::new().optimize(¤t_tpm);
|
|
current_tpm = cg.induce_macro_tpm(¤t_tpm);
|
|
|
|
self.levels.push(HierarchyLevel {
|
|
tpm: current_tpm.clone(),
|
|
coarse_graining: cg,
|
|
effective_info: ei,
|
|
});
|
|
}
|
|
|
|
// Find peaks (levels with local maximum EI)
|
|
self.peaks = self.find_peaks(&self.ei_profile);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Performance
|
|
|
|
| Micro States | Optimization Time | Peak Detection |
|
|
|--------------|-------------------|----------------|
|
|
| 16 | 10ms | 1ms |
|
|
| 64 | 200ms | 5ms |
|
|
| 256 | 5s | 50ms |
|
|
| 1024 | 2min | 500ms |
|
|
|
|
## Usage
|
|
|
|
```rust
|
|
use causal_emergence::{CausalEmergence, EffectiveInformation, CausalHierarchy};
|
|
|
|
// Define micro-level system
|
|
let micro_tpm = TransitionMatrix::from_data(&state_transitions);
|
|
|
|
// Compute effective information
|
|
let ei = EffectiveInformation::new();
|
|
let ei_micro = ei.compute(µ_tpm);
|
|
|
|
// Find optimal coarse-graining
|
|
let cg = CoarseGraining::new().optimize(µ_tpm);
|
|
let macro_tpm = cg.induce_macro_tpm(µ_tpm);
|
|
let ei_macro = ei.compute(¯o_tpm);
|
|
|
|
// Check for causal emergence
|
|
let emergence = ei_macro - ei_micro;
|
|
if emergence > 0.0 {
|
|
println!("Causal emergence detected! Δ EI = {:.3} bits", emergence);
|
|
}
|
|
|
|
// Build full hierarchy
|
|
let mut hierarchy = CausalHierarchy::new(10);
|
|
hierarchy.build(µ_tpm);
|
|
|
|
for (level, ei) in hierarchy.ei_profile.iter().enumerate() {
|
|
let marker = if hierarchy.peaks.contains(&level) { " ← PEAK" } else { "" };
|
|
println!("Level {}: EI = {:.3}{}", level, ei, marker);
|
|
}
|
|
```
|
|
|
|
## Interpretation
|
|
|
|
| Emergence Value | Interpretation |
|
|
|-----------------|----------------|
|
|
| < 0 | Micro level is more causal |
|
|
| = 0 | No emergence |
|
|
| 0 to 0.5 | Weak emergence |
|
|
| 0.5 to 1.0 | Moderate emergence |
|
|
| > 1.0 | Strong causal emergence |
|
|
|
|
## References
|
|
|
|
- Hoel, E.P. et al. (2013). "Quantifying causal emergence shows that macro can beat micro"
|
|
- Tononi, G. & Sporns, O. (2003). "Measuring information integration"
|
|
- Klein, B. & Hoel, E.P. (2020). "The Emergence of Informative Higher Scales"
|