Skip to content

Commit 428d83e

Browse files
committed
added analysis helpers
1 parent 89c80f2 commit 428d83e

6 files changed

Lines changed: 109 additions & 7 deletions

File tree

docs/prompts.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ Finally, make sure to add an expected type for each argument and define the retu
2828
6. Create a time series analysis plot of the evolution of prey and predator density vs. time. Make sure enough time steps all visible to see how the system eventually stabilizes.
2929

3030
7. Create a bifuracation diagram to confirm the monotonic relationship for a varying prey death rate vs. equilibrium density.
31+
32+
###

models/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
from .mean_field import MeanFieldModel
1+
from .mean_field import MeanFieldModel
2+
from .CA import CA

models/helpers.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import numpy as np
2+
from scipy.ndimage import label
3+
4+
def find_clusters(grid: np.ndarray, state: int = 1, connectivity: int = 'moore'):
5+
"""Locate connected clusters of a given state."""
6+
if connectivity == 'moore':
7+
structure = np.ones((3, 3), dtype=int)
8+
else:
9+
structure = ([[0, 1, 0],
10+
[1, 1, 1],
11+
[0, 1, 0]])
12+
13+
binary_mask = (grid == state).astype(int)
14+
labeled_array, num_clusters = label(binary_mask, structure=structure)
15+
16+
return labeled_array, num_clusters
17+
18+
def get_cluster_sizes(grid: np.ndarray, state: int = 1):
19+
"""Returns an array containing the sizes of all detected clusters."""
20+
labeled, n = find_clusters(grid, state)
21+
22+
if n == 0:
23+
return np.array([])
24+
25+
sizes = np.bincount(labeled.ravel())[1:] # Exclude background count
26+
27+
return sizes
28+
29+
def fit_power_law_mle(sizes: np.ndarray, s_min: float = 1.0):
30+
"""
31+
Maximum Likelihood Estimator for the power-law exponent.
32+
"""
33+
# Filter sizes below the minimum threshold
34+
sizes = sizes[sizes >= s_min]
35+
36+
if len(sizes) < 10:
37+
return {'tau': np.nan, 'tau_err': np.nan, 'n_samples': len(sizes)}
38+
39+
n = len(sizes)
40+
41+
# Standard MLE formula for power-law index
42+
tau = 1 + n / np.sum(np.log(sizes / s_min))
43+
tau_err = (tau - 1) / np.sqrt(n)
44+
45+
return {
46+
'tau': tau,
47+
'tau_err': tau_err,
48+
'n_samples': n
49+
}
50+
51+
def detect_hydra_effect(d_r_vals: np.ndarray, R_vals: np.ndarray):
52+
"""Detects hydra effect by identifying increase in prey population with increased death rate."""
53+
54+
dR = np.gradient(R_vals, d_r_vals)
55+
hydra_mask = dR > 0
56+
57+
if not np.any(hydra_mask):
58+
return {
59+
'detected': False,
60+
'region': None,
61+
'max_strength': 0.0
62+
}
63+
hydra_indices = np.where(hydra_mask)[0]
64+
65+
results = {
66+
'detected': True,
67+
'd_r_start': d_r_vals[hydra_indices[0]],
68+
'd_r_end': d_r_vals[hydra_indices[-1]],
69+
'max_slope': np.max(dR),
70+
'd_r_at_max_slope': d_r_vals[np.argmax(dR)],
71+
'peak_density': np.max(R_vals[hydra_mask])
72+
}
73+
74+
return results
75+
76+
def find_spatial_correlation(d_r_vals, ca_results):
77+
"""ca_results: List of grids (np.ndarray) at equilibrium of each d_r value."""
78+
pass

notebooks/mf.ipynb

Lines changed: 4 additions & 5 deletions
Large diffs are not rendered by default.

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ matplotlib
22
numpy
33
scipy
44
pytest
5-
seaborn
5+
seaborn
6+
black

tests/test_ca.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Cellular Automaton tests."""
2+
3+
import pytest
4+
import numpy as np
5+
from models.CA import CA
6+
7+
# @pytest.fixture
8+
def ca_instance():
9+
pass
10+
11+
def test_initialization():
12+
pass
13+
14+
def test_invalid_parameters():
15+
pass
16+
17+
def test_grid_filling():
18+
pass
19+
20+
def test_neighborhood_types():
21+
pass

0 commit comments

Comments
 (0)