---
name: evo-simulator
description: >
  Simulate evolutionary game dynamics — run replicator equations, compute fixation probabilities,
  visualize phase portraits and population trajectories, and analyze evolutionary stability
  computationally. Use when the user wants to see dynamics in action, validate analytical
  predictions, or explore games too complex for closed-form analysis.
metadata:
  author: nirav
  version: "1.0"
compatibility: Designed for Claude Code
allowed-tools: Read Write bash Glob
---

# Evo-Simulator — The Laboratory

Run evolutionary dynamics computationally. Take a game specification, simulate the population over time, and produce interpretable results — trajectory plots, phase portraits, fixation probabilities, and stability assessments. Essential for games where analytical solutions are intractable or where intuition needs verification.

## How to Run

### Input

The user provides:
1. **A game** — payoff matrix, or a description to be formalized
2. **A dynamics model** — replicator, Moran, best response, logit, or other revision protocol
3. **Initial conditions** — starting population state(s)
4. **Parameters** — population size (for stochastic), selection intensity, mutation rate, time horizon

Defaults (if not specified):
- Dynamics: Replicator (continuous-time)
- Initial conditions: Multiple starting points across the simplex
- Population size: Infinite (deterministic) unless finite specified
- Time horizon: Until convergence or 1000 generations

### Steps

#### Step 1 — Formalize the Game

Convert the user's input to a payoff matrix A where Aᵢⱼ = payoff to strategy i against strategy j.

For a 2-strategy game:
```
A = [[a, b],
     [c, d]]
```

For a 3-strategy game:
```
A = [[a, b, c],
     [d, e, f],
     [g, h, i]]
```

#### Step 2 — Analytical Pre-Analysis

Before simulating, identify:
- **Fixed points**: Interior NE (solve f₁ = f₂ = ... = fₙ) and boundary NE (pure strategies)
- **ESS candidates**: Check the ESS conditions for each NE
- **Expected behavior**: Predict convergence, cycling, or chaos based on game structure

This provides a reference for validating the simulation.

#### Step 3 — Choose and Run Dynamics

**Deterministic replicator dynamics** (default for infinite population):

```python
import numpy as np
from scipy.integrate import odeint

def replicator(x, t, A):
    fitness = A @ x
    avg_fitness = x @ fitness
    return x * (fitness - avg_fitness)

# Solve ODE from initial condition x0 over time grid t
trajectory = odeint(replicator, x0, t, args=(A,))
```

**Moran process** (for finite population N):

```python
def moran_step(population, A, N):
    # Compute fitness of each strategy type
    counts = np.bincount(population, minlength=len(A))
    freqs = counts / N
    fitness = A @ freqs

    # Select reproducer proportional to fitness
    reproducer_type = np.random.choice(len(A), p=fitness*freqs/sum(fitness*freqs))

    # Select random individual to die
    death_idx = np.random.randint(N)
    population[death_idx] = reproducer_type
    return population
```

**Fixation probability** (for finite populations):
Run many independent Moran process simulations starting with a single mutant. The fraction that fixate estimates the fixation probability.

#### Step 4 — Visualize Results

**For 2-strategy games**: Plot strategy frequency x₁ over time. Multiple trajectories from different initial conditions. Mark fixed points and basins of attraction.

**For 3-strategy games**: Plot trajectories on the 2-simplex (triangle). Use barycentric coordinates. Color-code by basin of attraction. Mark fixed points.

**For finite populations**: Plot frequency over time (single runs show stochasticity). Histogram of fixation times. Fixation probability as a function of initial frequency.

#### Step 5 — Interpret and Compare

Compare simulation results to analytical predictions:
- Do trajectories converge to predicted ESS?
- Are basins of attraction as expected?
- For finite populations, how do fixation probabilities compare to the analytical formula?
- Does stochasticity qualitatively change the prediction?

Report discrepancies — they often reveal interesting phenomena (e.g., stochastic effects favoring a strategy that's not an ESS in the infinite-population limit).

#### Step 6 — Sensitivity Analysis

Vary key parameters and report how results change:
- **Selection intensity**: Weak selection (nearly neutral) vs. strong selection
- **Population size**: Small (N=20) vs. large (N=1000) — stochastic effects diminish
- **Mutation rate**: Zero mutation (absorbing states) vs. positive mutation (stationary distribution)
- **Initial conditions**: Which initial states lead to which outcomes?

### Output

A simulation report containing:

```
## Evolutionary Simulation: [Game Name]

### Game Specification
[Payoff matrix, dynamics model, parameters]

### Analytical Predictions
[Fixed points, ESS, expected basins of attraction]

### Simulation Results
[Trajectory descriptions, convergence behavior, fixation probabilities]
[Visualizations or descriptions of phase portraits]

### Sensitivity Analysis
[How results change with parameter variation]

### Interpretation
[What the dynamics tell us about the strategic situation]
```

## Error Handling

**Game matrix is not square**: A payoff matrix must have the same number of rows and columns (same number of strategies). Ask the user to verify the game specification.

**Dynamics don't converge**: This may be correct — RPS-type games cycle indefinitely. Report the cycling behavior and the nature of the orbits (closed orbits, spirals in/out, chaos).

**Stochastic simulation too slow**: For large populations or many strategies, the Moran process is slow. Suggest reducing N, using a diffusion approximation, or switching to deterministic dynamics with finite-population corrections.

**Multiple basins of attraction**: This is a feature, not a bug. Report all basins and the critical thresholds between them. Identify which initial conditions lead to which outcomes.

**Numerical instability**: Replicator dynamics can produce frequencies below 0 or above 1 due to numerical errors. Use projection onto the simplex after each integration step. If x_i < ε, set to 0 and renormalize.
