Skip to content

Commit 1e1561f

Browse files
committed
Merge branch 'main' into kimon
2 parents 7a0e2e7 + f2075e8 commit 1e1561f

7 files changed

Lines changed: 1485 additions & 7 deletions

File tree

SOC_ANALYSIS_README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Self-Organized Criticality (SOC) Analysis - Summary
2+
3+
## File Created
4+
**Location:** `scripts/soc_analysis.py`
5+
6+
## Overview
7+
This comprehensive Python analysis script tests whether your prey-predator cellular automaton exhibits **self-organized criticality** (SOC), with focus on perturbations from initial configurations and diverse parameter sampling.
8+
9+
## Key Features
10+
11+
### 1. **Four SOC Properties Analyzed**
12+
- **Slow Drive:** Gradual parameter drift without immediate release
13+
- **Stress Build-up:** Interface-based metric tracking potential energy accumulation
14+
- **Intermittent Release:** Detection of avalanche cascades in population dynamics
15+
- **Self-Organization:** Robustness across diverse parameter combinations
16+
17+
### 2. **Parameter Variations** (Beyond just death/birth rates)
18+
- Grid sizes: 16×16 to 64×64
19+
- Initial densities: prey (0.1–0.4), predator (0.02–0.15)
20+
- Neighborhood types: Neumann & Moore
21+
- Update modes: Synchronous & Asynchronous
22+
- Rate parameters: randomly varied across valid ranges
23+
24+
### 3. **Metrics Computed**
25+
- **Stress Metric:** Normalized count of (predator/prey)↔empty adjacent pairs
26+
- Represents friction and interface gradient (potential energy)
27+
- **Avalanche Detection:** Population change magnitude thresholds
28+
- **Population Variance:** Rolling window variance of prey/predator counts
29+
- **Robustness Metrics:**
30+
- Avalanche count mean/std across configurations
31+
- Magnitude consistency
32+
- Coefficient of variation (measures criticality robustness)
33+
34+
### 4. **Perturbation Experiment Design**
35+
Each experiment runs 230 total steps:
36+
- **Equilibration phase (0–80 steps):** System reaches quasi-steady state
37+
- Stress accumulates during slow drive
38+
- No parameter perturbation
39+
- **Observation phase (80–230 steps):** Gradual parameter drift
40+
- Predator death rate increases by +0.05 (slow drive)
41+
- System responds with cascading events if critical
42+
- Stress release and avalanche events detected
43+
44+
## Visualization Output
45+
46+
The script generates `soc_analysis_results.png` with a **2×2 grid displaying the 4 core SOC properties**:
47+
48+
1. **Panel 1 (Top-Left) - Slow Drive:** Gradual parameter drift over time with equilibration and perturbation phases marked
49+
2. **Panel 2 (Top-Right) - Build-up of Stress:** Stress accumulation with avalanche event thresholds marked as orange stars
50+
3. **Panel 3 (Bottom-Left) - Intermittent Release:** Prey and predator population dynamics showing cascade events during perturbation
51+
4. **Panel 4 (Bottom-Right) - Self-Organization:** Stress-density relation across diverse configurations, colored by avalanche activity
52+
53+
## Usage
54+
55+
```bash
56+
python scripts/soc_analysis.py
57+
```
58+
59+
Output:
60+
- Console report with findings
61+
- PNG visualization saved to workspace root: `soc_analysis_results.png`
62+
63+
## Key Observations from Test Run
64+
65+
- **8 diverse configurations** sampled with varied grid sizes, densities, neighborhoods
66+
- **Avalanche detection:** 1/8 experiments showed clear cascade events
67+
- **Stress persistence:** Mean stress ~0.1529 across all configurations
68+
- **Robustness metric:** Coefficient of Variation = 2.646 (indicates some parameter-dependence; lower values → more robust SOC)
69+
- **Population variance:** Consistent across runs (signature of intermittent release mechanism)
70+
71+
## Code Structure
72+
73+
### Main Functions
74+
- `compute_grid_stress()` – Interface-based stress metric
75+
- `compute_population_variance()` – Rolling window variance calculation
76+
- `detect_avalanche_events()` – Identify cascading population changes
77+
- `sample_parameter_configurations()` – Generate diverse parameter sets
78+
- `run_soc_perturbation_experiment()` – Single experiment with slow drive
79+
- `analyze_soc_robustness()` – Cross-configuration robustness metrics
80+
- `visualize_soc_properties()` – Comprehensive 8-panel figure
81+
- `main()` – Orchestrates full analysis pipeline
82+
83+
### Configuration Space
84+
- **Grid size:** Affects stability and relaxation dynamics
85+
- **Densities:** Controls predator-prey interaction frequency
86+
- **Neighborhood:** Changes spatial coupling strength
87+
- **Rates:** Direct influence on birth/death thresholds
88+
89+
## Scientific Interpretation
90+
91+
The analysis tests the hypothesis:
92+
> *"Does the prey-predator CA exhibit self-organized criticality independent of specific parameter choices?"*
93+
94+
If coefficient of variation is **low** (< 1.0) → SOC is **robust** (self-organized)
95+
If coefficient of variation is **high** (> 1.0) → Behavior is **parameter-dependent** (requires tuning)
96+
97+
---
98+
99+
**Created:** January 2026
100+
**Framework:** NumPy, Matplotlib, custom CA simulation

docs/sary_prompts.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# CA Stochastic Bifurcation Diagram:
2+
Mutations (evolutions) parameter OFF
3+
Control parameter: prey death rate
4+
5+
Possible statistical observables:
6+
- Fraction of prey cells at equilibrium
7+
- Measure of entropy of the generated pattern.
8+
- Prey population count
9+
- Predator population count
10+
11+
Run simulation:
12+
- Let the system run until a steady state is observed
13+
- For each death rate value, let the CA run for a specified number of iterations after warmp up, show distribution (scatters) for each sim run at a given prey death rate, and the average line
14+
15+
16+
# Phase 1: finding the critical point
17+
- Create bifurcation diagram of mean population count, varying prey death rate
18+
- Look for critical transition
19+
- Create log-log plot of cluster size distribution, varying prey death rate
20+
- Look for power-law
21+
22+
# Experiment Phase: CA Stochastic Bifurcation Diagram:
23+
24+
1) Write a Config Object specific to that experiment
25+
2) Make sure the experiment running on the cluster is running 15 reps of each runs at all sweeped values.
26+
3) Make sure the outputs of the experiment are a 1D and 2D array (explained below)
27+
28+
# Bifurcation Diagram Prompts:
29+
1) Help me write a function for creating a stochastic bifurcation diagram, of the population count at equilibrium, varying the prey death rate (as the control variable).
30+
2) At each sweeped value of the prey death control variable, we should be measuring the population count at equilibrium for at least 15 simulation runs.
31+
3) Which means that the two inputs for my function should be a 1D Array for the sweep parameter, and a 2D array for the experiment results at each sweep for the rows, and the results for each iteration for the columns.
32+
4) When running my function, using the argparse module, my command-line arguments specifies which analysis to do, in this case the analysis is the bifurcation diagram.
33+
34+
35+
# Output:
36+
def load_bifurcation_results(results_dir: Path) -> Tuple[np.ndarray, np.ndarray]:
37+
"""
38+
Load bifurcation analysis results.
39+
40+
Returns
41+
-------
42+
sweep_params : np.ndarray
43+
1D array of control parameter values (prey death rates).
44+
results : np.ndarray
45+
2D array of shape (n_sweep, n_replicates) with population counts
46+
at equilibrium.
47+
"""
48+
npz_file = results_dir / "bifurcation_results.npz"
49+
json_file = results_dir / "bifurcation_results.json"
50+
51+
if npz_file.exists():
52+
logging.info(f"Loading bifurcation results from {npz_file}")
53+
data = np.load(npz_file)
54+
return data['sweep_params'], data['results']
55+
elif json_file.exists():
56+
logging.info(f"Loading bifurcation results from {json_file}")
57+
with open(json_file, 'r') as f:
58+
data = json.load(f)
59+
return np.array(data['sweep_params']), np.array(data['results'])
60+
else:
61+
raise FileNotFoundError(f"Bifurcation results not found in {results_dir}")
62+
63+
64+
def plot_bifurcation_diagram(sweep_params: np.ndarray, results: np.ndarray,
65+
output_dir: Path, dpi: int = 150,
66+
control_label: str = "Prey Death Rate",
67+
population_label: str = "Population at Equilibrium"):
68+
"""
69+
Generate a stochastic bifurcation diagram.
70+
71+
Shows the distribution of equilibrium population counts as a function of
72+
a control parameter (e.g., prey death rate), with scatter points for each
73+
replicate run overlaid on summary statistics.
74+
75+
Parameters
76+
----------
77+
sweep_params : np.ndarray
78+
1D array of control parameter values (e.g., prey death rates).
79+
Shape: (n_sweep,)
80+
results : np.ndarray
81+
2D array of population counts at equilibrium.
82+
Shape: (n_sweep, n_replicates) where rows correspond to sweep_params
83+
and columns are replicate simulation runs.
84+
output_dir : Path
85+
Directory to save the output figure.
86+
dpi : int
87+
Output resolution (default: 150).
88+
control_label : str
89+
Label for x-axis (control parameter).
90+
population_label : str
91+
Label for y-axis (population count).
92+
"""
93+
n_sweep, n_replicates = results.shape
94+
95+
fig, ax = plt.subplots(figsize=(12, 7))
96+
97+
# Scatter all individual replicates with transparency
98+
for i, param in enumerate(sweep_params):
99+
ax.scatter(
100+
np.full(n_replicates, param),
101+
results[i, :],
102+
alpha=0.3, s=15, c='steelblue', edgecolors='none'
103+
)
104+
105+
# Compute summary statistics
106+
means = np.mean(results, axis=1)
107+
medians = np.median(results, axis=1)
108+
q25 = np.percentile(results, 25, axis=1)
109+
q75 = np.percentile(results, 75, axis=1)
110+
111+
# Plot median line and IQR envelope
112+
ax.fill_between(sweep_params, q25, q75, alpha=0.25, color='coral',
113+
label='IQR (25th-75th percentile)')
114+
ax.plot(sweep_params, medians, 'o-', color='darkred', linewidth=2,
115+
markersize=5, label='Median')
116+
ax.plot(sweep_params, means, 's--', color='black', linewidth=1.5,
117+
markersize=4, alpha=0.7, label='Mean')
118+
119+
ax.set_xlabel(control_label)
120+
ax.set_ylabel(population_label)
121+
ax.set_title(f"Stochastic Bifurcation Diagram\n({n_replicates} replicates per parameter value)")
122+
ax.legend(loc='best')
123+
ax.grid(True, alpha=0.3)
124+
125+
# Add rug plot at bottom showing parameter sampling density
126+
ax.plot(sweep_params, np.zeros_like(sweep_params), '|', color='gray',
127+
markersize=10, alpha=0.5)
128+
129+
plt.tight_layout()
130+
output_file = output_dir / "bifurcation_diagram.png"
131+
plt.savefig(output_file, dpi=dpi)
132+
plt.close()
133+
logging.info(f"Saved {output_file}")
134+
135+
return output_file

models/CA.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@
88

99
import numpy as np
1010
import logging
11+
import sys
12+
from pathlib import Path
13+
14+
# Add parent directory to path for imports
15+
sys.path.insert(0, str(Path(__file__).parent.parent))
16+
1117
from models.numba_optimized import PPKernel, set_numba_seed
18+
from models.cluster_analysis import ClusterAnalyzer
1219

1320
# Module logger
1421
logger = logging.getLogger(__name__)

0 commit comments

Comments
 (0)