From aa3f263f334ac96ed133ef4937d42b0b9816e4ce Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:14:59 +0330 Subject: [PATCH] Import documentation: Shayan1/Prod/docs/DOCS.md Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- Shayan1/Prod/docs/DOCS.md | 62 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Shayan1/Prod/docs/DOCS.md diff --git a/Shayan1/Prod/docs/DOCS.md b/Shayan1/Prod/docs/DOCS.md new file mode 100644 index 0000000..f01510d --- /dev/null +++ b/Shayan1/Prod/docs/DOCS.md @@ -0,0 +1,62 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +Dependencies are installed in a local virtualenv (`.venv/`) because the system Python is externally managed: + +``` +python3 -m venv .venv +.venv/bin/pip install -r requirements.txt +``` + +Run the tool against a game file: + +``` +.venv/bin/python main.py --game games/pricing.json --rounds 30 --memory on --seed 1 +``` + +- `--game ` or `--describe ""` — exactly one is required (mutually exclusive). `--describe` uses the optional AI translation layer and needs `anthropic` installed plus `ANTHROPIC_API_KEY` set. +- `--memory on|off` — toggles fictitious play vs. last-round-only best response (default `on`). +- `--seed ` — seeds the RNG for reproducible runs (useful when debugging). +- `--out ` — where the strategy-usage chart PNG is saved (default `strategy_usage.png`). +- `--inspect` — prints game details, payoff matrix, and dominant strategies, then exits. +- `--reduce` — iteratively eliminates strictly dominated strategies (IESDS matrix reduction) before simulation or inspection. +- `--verbose` — prints per-round debug data (e.g. agent reasoning) during simulation. +- `--player ` — decision model for simulation (default `best_response`). +- `--sim-type ` — type of simulation: `agents` (multi-agent) or `evolutionary` (replicator dynamics) (default `agents`). + +Run tests: + +``` +.venv/bin/python -m pytest tests/ +``` + +There's no build/lint step — this is a small, dependency-light script project. + +## Architecture + +**Games are data, not code.** Every game (player names, strategies, payoffs) lives in a JSON file under `games/`; nothing about a specific scenario is hardcoded in `nash/`. `nash/game.py`'s `Game` class loads this JSON and represents payoffs as one N-dimensional numpy tensor per player (`payoffs[i]` has shape `(num_strategies_p0, num_strategies_p1, ...)`), indexed by a full strategy profile tuple. This tensor representation is what lets the pure-equilibrium finder and the simulation work for any number of players, not just 2 — adding a 3+ player game requires no code changes, just a JSON file with matching-shaped payoff tensors. + +**Solver has game reduction and multiple solving algorithms** (`nash/solver.py`): +- `find_pure_nash_equilibria` — brute-force over all strategy profiles, works for any N players. +- `find_mixed_nash_equilibria` — support enumeration, **2-player only by design**. It assumes non-degenerate games (only tries equal-size supports for both players); N-player mixed equilibria aren't computed because no Lemke-Howson-style algorithm generalizes past 2 players. Calling it on a game with `num_players != 2` raises `NotImplementedError` deliberately. +- `find_dominant_strategies` — finds strictly dominant strategies for each player. +- `reduce_game` — performs Iterated Elimination of Strictly Dominated Strategies (IESDS) to reduce the matrix size before solving or simulating. + +**Simulation supports multiple player decision models and evolutionary dynamics** (`nash/simulation.py`, `nash/players.py`): +- **Agent Simulation (`--sim-type agents`)**: runs agent-based rounds using decision models like `BestResponsePlayer`, `SoftmaxBestResponsePlayer`, `RegretMatchingPlayer`, `QLearningPlayer`, and `LLMPlayer`. +- **LLM Player**: `LLMPlayer` queries the Anthropic Claude API using the `anthropic` SDK to decide its next strategy. It is supplied with the payoff matrix and game history, then returns a JSON object containing its reasoning and its selected strategy index. +- **Evolutionary Simulation (`--sim-type evolutionary`)**: runs `EvolutionarySimulation` using Replicator Dynamics. Instead of discrete agent actions, it updates a continuous population strategy distribution for each player over time based on expected payoffs against other populations. +**Best-response dynamics has a memory switch** (`nash/players.py`, `BestResponsePlayer`): `memory=False` computes the best response to only the immediately preceding round (can cycle indefinitely in games like Rock-Paper-Scissors or Matching Pennies); `memory=True` is fictitious play — best response to the empirical distribution of the *entire* history so far. Ties in expected payoff are broken via a caller-supplied `random.Random` instance (passed down from `main.py`'s `--seed`), not `random` global state, so runs are reproducible end to end. + +**Convergence detection is a heuristic, and `main.py` compensates for its blind spot.** `Simulation.converged_round()` (`nash/simulation.py`) just checks for N (default 5) consecutive identical profiles — it can't distinguish "the game actually settled" from "fictitious play happens to be mid-streak in a game with no pure equilibrium" (e.g. Matching Pennies, Rock-Paper-Scissors under `memory=on` will show long streaks that eventually flip as the historical average slowly shifts). `main.py.print_comparison` handles this by cross-checking the "converged" profile against `solver.find_pure_nash_equilibria`'s actual output before claiming a real equilibrium was reached; if it doesn't match, it explicitly explains why and falls back to reporting long-run strategy frequencies instead (which is the number that's actually meaningful for games whose only equilibrium is mixed). + +**The AI layer (`nash/translate.py`) is intentionally decoupled from everything else.** `describe_to_json` is the only function in the codebase that makes a network/API call (via the `anthropic` SDK), and it's only reachable through `main.py`'s `--describe` flag. It never touches `solver.py` or `simulation.py` directly — it just produces the same JSON shape a hand-written game file would have, prints/saves it, and hands it to the exact same `Game` constructor and pipeline used for `--game`. This means a bad translation surfaces as visibly wrong JSON before any simulation runs, not as a silently wrong answer. + +## Sample games (`games/`) + +- `pricing.json` — 2-player Prisoner's-Dilemma-shaped game (High/Low pricing), unique pure NE at `(Low, Low)`. +- `matching_pennies.json` — 2-player zero-sum game with no pure NE, mixed NE at 50/50. +- `rock_paper_scissors.json` — 2-player, 3-strategy zero-sum game, mixed NE at 1/3-1/3-1/3; used to confirm the tool isn't hardcoded to 2-strategy games.