Metadata-Version: 2.4
Name: graphsimulacrum
Version: 0.1.0
Summary: Mechanistic synthetic data generation framework for MMM validation
Author: Laercio Pires
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: networkx>=3.2
Requires-Dist: numba>=0.59
Requires-Dist: numpy>=1.26
Requires-Dist: polars>=1.0
Requires-Dist: pyarrow>=16.0
Requires-Dist: pydantic>=2.7
Requires-Dist: pyyaml>=6.0
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: hypothesis>=6.100; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pandas>=2.2; extra == 'dev'
Requires-Dist: pytest-benchmark>=4.0; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocs>=1.6; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
Requires-Dist: pymdown-extensions>=10.0; extra == 'docs'
Provides-Extra: jax
Requires-Dist: jax>=0.4.30; extra == 'jax'
Description-Content-Type: text/markdown

# graphsimulacrum

**Mechanistic synthetic data generation for Marketing Mix Modeling (MMM) validation.**

MMMs are usually benchmarked against synthetic data built from the same functional
forms (Adstock, Hill curves) the models assume — which guarantees flattering but
meaningless parameter recovery. `graphsimulacrum` breaks that circularity: you declare a
causal DAG of agent-level behavioral rules (exposure, memory decay, purchase choice),
and macro phenomena like carryover and saturation *emerge* from millions of simulated
individual decisions instead of being written into equations.

Every run produces three things a real dataset never can:

1. **An observable dataset** — a clean panel (spend, exposure, conversions, revenue)
   in schemas ready for Robyn, Meridian, or any custom MMM.
2. **A ground-truth ledger** — the *true* per-channel, per-period causal increments,
   computed via paired counterfactual runs under Common Random Numbers (CRN). This is
   what your MMM estimates get scored against.
3. **A provenance manifest** — full spec, seeds, and content hashes, so any run is
   exactly reproducible.

The framework can run fully synthetic, or in **hybrid mode**, binding real
macroeconomic indicators or historical spend plans to the simulation — including
ground-truth incrementality for a *real* media plan.

## Quickstart

Requires Python 3.11+. Install into any environment — a plain `venv`, conda,
uv, or poetry all work. Using the standard library `venv`:

```bash
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install graphsimulacrum        # or: pip install -e '.[dev]' from a clone

graphsimulacrum run docs/reference_scenarios/clean_world.yaml -o out/clean --backend numba
```

That writes a full run bundle to `out/clean/`: the observed panel, the ground-truth
ledger, MMM-ready exports (Robyn/Meridian/tidy), and a provenance manifest.

> Prefer [uv](https://docs.astral.sh/uv/)? It's a supported optional accelerator —
> `uv sync` then `uv run graphsimulacrum ...` — but nothing here requires it.
>
> On some filesystems (e.g. exFAT/FAT32 external drives) a virtual environment
> can't be created in-tree; put it on a native-filesystem path instead. See
> `docs/faq.md`.

## The two reference scenarios

- **`clean_world.yaml`** — media spend is orthogonal to demand; everything the DAG
  uses is observed. No excuses for a badly specified MMM.
- **`confounded_world.yaml`** — TV spend is planned against the same seasonal cycle
  that drives demand, and the observed panel hides that seasonality column entirely.
  A naive attribution will credit TV with demand it never caused — the ledger is the
  only way to see it.

See `docs/reference_scenarios/README.md` for the DAG and the numbers.

## Documentation

The full documentation is a MkDocs site under `docs/`. Build and preview it
locally with one command each:

```bash
pip install -e '.[docs]'
mkdocs serve            # live preview at http://127.0.0.1:8000
mkdocs build --strict   # production build; fails on broken links
```

| Doc | What's in it |
|---|---|
| `docs/index.md` | Site home / overview |
| `docs/quickstart.md` | Install → run → inspect → score a naive MMM, start to finish |
| `docs/concepts.md` | Core concepts: DGP/model decoupling, CRN, the ledger, the dirty lens |
| `docs/ARCHITECTURE.md` | Full design spec: layers, data contracts, RNG/CRN discipline |
| `docs/tutorial.md` | Spec → panel → ledger → export → score, worked end to end |
| `docs/tutorials/` | Market-calibrated worlds scored against three real MMM libraries |
| `docs/hybrid_mode.md` | Binding real time series (spend plans, macro indices) |
| `docs/extend.md` | Authoring mechanisms, distributions, corruption steps, adapters |
| `docs/export_adapters.md` | Robyn / Meridian / tidy exports |
| `docs/experiments.md` | Scenarios and parameter sweeps |
| `docs/api.md` / `docs/reference.md` | API cheatsheet + autogenerated reference |
| `docs/releasing.md` | Maintainer release ritual (tag-driven publishing) |
| `docs/faq.md` | Common gotchas |
| `.claude/CLAUDE.md` | Development workflow, environment setup, build order |

## Status

v1 feature-complete (M0–M3): spec + compiler, NumPy/Numba kernels, counterfactual
engine + ground-truth ledger, hybrid-mode series binding, observation model, Robyn/
Meridian/tidy export adapters, experiment manager (scenarios & sweeps), and the two
reference scenarios above. See `.claude/CLAUDE.md` for the detailed status and
`docs/ARCHITECTURE.md` §12 for the roadmap of what's intentionally out of scope for v1
(agent-to-agent interaction, distributed backends, differentiable simulation).

## Development

From a clone, install the package with its dev dependencies (editable), then run
the checks. One command sets everything up:

```bash
pip install -e '.[dev]'
```

```bash
pytest                                              # full test suite
ruff check src/ tests/                              # lint
ruff format --check src/ tests/                     # format check
mypy src/graphsimulacrum/spec src/graphsimulacrum/compile --strict
```

(Prefix any command with `uv run` if you use uv; it is optional.)

See `.claude/CLAUDE.md` for the full contributor workflow.
