Spaces:
Sleeping
Sleeping
Vikram Vasudevan commited on
Commit ·
696dddf
1
Parent(s): 9239f05
compararive insights
Browse files- README.md +24 -248
- SKILLS.md +21 -56
- src/god_sim/app/streamlit_app.py +24 -0
- src/god_sim/insights/llm.py +58 -0
README.md
CHANGED
|
@@ -19,260 +19,36 @@ The goal is not to “simulate everything”, but to build a configurable sandbo
|
|
| 19 |
- **Bias experiments**: What happens to world stability when the population is biased toward “good nature” vs “bad nature”?
|
| 20 |
- **Scarcity vs abundance**: How do shared natural resources shape inequality, wellbeing, cooperation/conflict, and longevity?
|
| 21 |
- **Identity dynamics**: How do race/faith/beauty norms influence social networks and opportunity, and how do they compound over rebirth cycles?
|
| 22 |
-
- **
|
| 23 |
-
- **Philosophical lenses**: If we encode different schools of thought (e.g., Advaita, Vishishtadvaita, Buddhist frameworks) as rule sets, how do they change emergent behavior and “liberation” outcomes?
|
| 24 |
|
| 25 |
-
###
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
| 27 |
|
|
|
|
| 28 |
- **Soul**: immutable id; persists across lifetimes; carries karma forward.
|
| 29 |
-
- **Person
|
| 30 |
-
- **Karma**:
|
| 31 |
-
- **
|
| 32 |
-
- **
|
| 33 |
-
- **Society**: group labels (race/faith) and norms (beauty) influencing trust, mate choice, cooperation, and conflict.
|
| 34 |
-
- **Events**: stochastic shocks (disease, drought, opportunity, tragedy) parameterized and observable in logs.
|
| 35 |
-
- **Philosophical school / worldview**: a configurable “lens” that changes how agents interpret self/other, attachment, ethics, and the karma→rebirth→liberation mechanics (implemented as a pluggable ruleset, not hard-coded into the engine).
|
| 36 |
|
| 37 |
-
###
|
| 38 |
-
|
| 39 |
-
- **Advaita (Adhvaitha)**: non-dual framing; emphasis on ignorance/knowledge; reduced self/other separation.
|
| 40 |
-
- **Vishishtadvaita (Vishistadvaitha)**: qualified non-dual framing; enduring individuality in relation to the whole.
|
| 41 |
-
- **Buddhist lenses**: no fixed self, dependent origination; attachment/craving as drivers of suffering; liberation as reduction of craving/ignorance.
|
| 42 |
-
|
| 43 |
-
Implementation-wise, these won’t be treated as “religion labels” like `faith`. Instead, they act as **simulation rule modules** that can change:
|
| 44 |
-
- **Decision policy**: cooperation vs hoarding vs harm vs help; attachment, compassion, renunciation as parameters.
|
| 45 |
-
- **Suffering/wellbeing model**: how craving/aversion affects wellbeing beyond material resources.
|
| 46 |
-
- **Karma semantics**: how actions update karma and which actions matter.
|
| 47 |
-
- **Rebirth mapping**: how karma affects next-life traits and circumstances.
|
| 48 |
-
- **Liberation / exit conditions** (optional): when a soul stops rebirthing (e.g., thresholds, convergent criteria, or explicit “moksha/nirvana” state in the model).
|
| 49 |
-
|
| 50 |
-
The key constraint: we’ll keep the **core engine neutral** and make worldviews pluggable so we can run the same initial world under different lenses and compare outcomes.
|
| 51 |
-
|
| 52 |
-
### Why a phased approach
|
| 53 |
-
This idea contains many interacting systems. If we build UI/visuals first, we’ll optimize for looks before we know the world model creates interesting behavior.
|
| 54 |
-
|
| 55 |
-
So we build **engine-first**, prove the simulation produces meaningful metrics and repeatable experiments, then layer visualization and richer social dynamics.
|
| 56 |
-
|
| 57 |
-
## Phased roadmap
|
| 58 |
-
Each phase should end with something runnable and measurable.
|
| 59 |
-
|
| 60 |
-
### Phase 0 — Foundations (scaffolding + repeatability)
|
| 61 |
-
- Basic repo structure and packaging
|
| 62 |
-
- Single config object (or YAML/JSON) that fully defines a run
|
| 63 |
-
- Deterministic seeding for reproducible scenarios
|
| 64 |
-
- Logging/tracing of key events
|
| 65 |
-
|
| 66 |
-
### Phase 1 — Core life-cycle engine (V1 target)
|
| 67 |
-
- A world with a **fixed soul pool**
|
| 68 |
-
- Birth/life/death loop with a tick-based simulation (e.g., one tick = one year)
|
| 69 |
-
- Shared resource pool with scarcity/abundance knobs
|
| 70 |
-
- Karma accumulation and rebirth mapping
|
| 71 |
-
- Metrics + simple charts
|
| 72 |
-
|
| 73 |
-
### Phase 2 — Social interactions
|
| 74 |
-
- Friendship/partnering rules
|
| 75 |
-
- Cooperation/conflict mechanics
|
| 76 |
-
- Network effects (who influences whom)
|
| 77 |
-
- New metrics: cohesion, inequality, conflict rate, cluster formation
|
| 78 |
-
|
| 79 |
-
### Phase 3 — Identity + norms
|
| 80 |
-
- Race/faith labels and trust matrices
|
| 81 |
-
- “Beauty” norms as socially defined advantage/disadvantage
|
| 82 |
-
- Bias and discrimination parameters
|
| 83 |
-
|
| 84 |
-
### Phase 4 — Rich events + scenario comparison UX
|
| 85 |
-
- Expanded event catalogue and world shocks
|
| 86 |
-
- Side-by-side scenario runner (good-biased vs bad-biased, scarcity vs abundance)
|
| 87 |
-
- Saved runs, replay, and comparative dashboards
|
| 88 |
-
|
| 89 |
-
### Phase 5 — Philosophical schools as pluggable worldviews
|
| 90 |
-
- Define a `Worldview` interface (policy + karma + rebirth + liberation hooks)
|
| 91 |
-
- Implement first set of worldview modules (Advaita, Vishishtadvaita, Buddhist lens)
|
| 92 |
-
- Add scenario comparison: same seed/config, different worldview → compare metrics and liberation rates
|
| 93 |
-
- Add new metrics relevant to worldviews (e.g., attachment/craving proxy, compassion proxy, “liberation” events)
|
| 94 |
-
|
| 95 |
-
## V1 technical plan (build the minimum interesting world)
|
| 96 |
-
V1 is the smallest version that can answer: **does “good vs bad bias” + “scarcity vs abundance” meaningfully change world-level outcomes over generations?**
|
| 97 |
-
|
| 98 |
-
### Deliverable (what “done” looks like for V1)
|
| 99 |
-
- A single command starts an interactive app where you can:
|
| 100 |
-
- set parameters (seed, population size, resource abundance, bias toward good/bad nature)
|
| 101 |
-
- run for `N` ticks / generations
|
| 102 |
-
- view metrics and charts
|
| 103 |
-
- Runs are reproducible via seed + config snapshot.
|
| 104 |
-
|
| 105 |
-
### Running (Windows / PowerShell)
|
| 106 |
-
From `c:\Workspace\agentic-ai\projects\god`:
|
| 107 |
-
|
| 108 |
-
- Run the CLI (prints JSON):
|
| 109 |
-
|
| 110 |
-
```bash
|
| 111 |
-
uv sync
|
| 112 |
-
uv run god-sim --ticks 200 --num-souls 300
|
| 113 |
-
```
|
| 114 |
-
|
| 115 |
-
- Run the UI (Streamlit):
|
| 116 |
-
|
| 117 |
-
```bash
|
| 118 |
-
uv sync
|
| 119 |
-
uv run streamlit run .\src\god_sim\app\streamlit_app.py
|
| 120 |
-
```
|
| 121 |
-
|
| 122 |
-
### Run history persistence
|
| 123 |
-
- Every simulation run is automatically saved to `data/run_history.json`.
|
| 124 |
-
- Each record contains:
|
| 125 |
-
- `run_id`, `created_at_utc`
|
| 126 |
-
- `config`
|
| 127 |
-
- `final` metrics snapshot
|
| 128 |
-
- full `series` time-series data
|
| 129 |
-
- The dashboard includes a **Run History** section to compare recent runs.
|
| 130 |
-
|
| 131 |
-
### Local LLM insights (Gemma via Ollama)
|
| 132 |
-
The UI can optionally ask a **local** model to summarize and interpret a run (no cloud required).
|
| 133 |
-
|
| 134 |
-
1) Install and start Ollama, then pull a small Gemma model (example):
|
| 135 |
|
| 136 |
```bash
|
| 137 |
-
|
| 138 |
-
|
| 139 |
```
|
| 140 |
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
- `GOD_LLM_PROVIDER`: `ollama` (default) or `openai_compatible`
|
| 145 |
-
- `OLLAMA_BASE_URL`: default `http://localhost:11434`
|
| 146 |
-
- `OLLAMA_MODEL`: default `gemma2:2b`
|
| 147 |
-
- `OPENAI_BASE_URL`: default `http://localhost:1234/v1` (for local OpenAI-compatible servers)
|
| 148 |
-
- `OPENAI_MODEL`: default `gemma`
|
| 149 |
-
- `OPENAI_API_KEY`: only if your local server requires it
|
| 150 |
-
|
| 151 |
-
### Fully offline LLM insights (no server) using your HF `.bin`
|
| 152 |
-
Your Hugging Face repo contains a local file `gemma-2b-it-cpu-int4.bin` (uploaded here: [`vikramvasudevan/gemma-for-panchangam`](https://huggingface.co/vikramvasudevan/gemma-for-panchangam)).
|
| 153 |
-
|
| 154 |
-
Important format note:
|
| 155 |
-
- `llama-cpp-python` expects **GGUF** files for `provider=llama_cpp`.
|
| 156 |
-
- A `.bin` file may download successfully but still fail to load in `llama_cpp`.
|
| 157 |
-
- If you want to use your current `.bin`, use `provider=ollama` (server mode), or obtain/convert a GGUF model for fully offline `llama_cpp`.
|
| 158 |
-
|
| 159 |
-
1) Download the model file into `.\models\`:
|
| 160 |
-
|
| 161 |
-
```bash
|
| 162 |
-
uv sync
|
| 163 |
-
uv run god-sim-download-model --repo vikramvasudevan/gemma-for-panchangam --file gemma-2b-it-cpu-int4.bin --out models
|
| 164 |
-
```
|
| 165 |
-
|
| 166 |
-
2) Run the UI and choose provider `llama_cpp` in the Insights section, or set env vars:
|
| 167 |
-
- `GOD_LLM_PROVIDER=llama_cpp`
|
| 168 |
-
- `GOD_LLM_MODEL_PATH=models/<your-model>.gguf`
|
| 169 |
-
- (optional) `GOD_LLM_N_CTX=4096`, `GOD_LLM_N_THREADS=0`
|
| 170 |
-
|
| 171 |
-
If the model path is missing, the app now tries to **auto-download** from Hugging Face by default.
|
| 172 |
-
|
| 173 |
-
Optional controls:
|
| 174 |
-
- `GOD_LLM_AUTO_DOWNLOAD=1` (default) or `0`
|
| 175 |
-
- `GOD_LLM_HF_REPO=vikramvasudevan/gemma-for-panchangam`
|
| 176 |
-
- `GOD_LLM_HF_FILE=gemma-2b-it-cpu-int4.bin`
|
| 177 |
-
|
| 178 |
-
### Recommended stack
|
| 179 |
-
- **Python**: `dataclasses` + type hints
|
| 180 |
-
- **Numerics**: `numpy` (optionally `pandas` if it helps)
|
| 181 |
-
- **Visualization/UI**: **Streamlit** (fastest to iterate on “play God” sliders + charts)
|
| 182 |
-
- **Plots**: `plotly` (or `matplotlib`)
|
| 183 |
-
|
| 184 |
-
### Suggested code organization
|
| 185 |
-
```
|
| 186 |
-
god/
|
| 187 |
-
README.md
|
| 188 |
-
pyproject.toml
|
| 189 |
-
main.py # CLI or entrypoint (later can launch Streamlit)
|
| 190 |
-
src/god_sim/
|
| 191 |
-
__init__.py
|
| 192 |
-
config.py # WorldConfig, scenario presets
|
| 193 |
-
domain/
|
| 194 |
-
soul.py # Soul (id, karma)
|
| 195 |
-
person.py # Person (traits, identity, wellbeing, relationships)
|
| 196 |
-
world.py # World state (population, resources, time)
|
| 197 |
-
resources.py # ResourcePool (replenish, consume)
|
| 198 |
-
events.py # Event types and effects
|
| 199 |
-
engine/
|
| 200 |
-
sim.py # run_simulation(), step_world()
|
| 201 |
-
rebirth.py # Rebirth rules (karma → next-life initialization)
|
| 202 |
-
karma.py # Karma updates from actions/outcomes
|
| 203 |
-
rules/
|
| 204 |
-
decisions.py # cooperate/hoard/help/harm policy driven by moral_bias
|
| 205 |
-
social.py # (minimal in V1) optional basic interaction
|
| 206 |
-
analytics/
|
| 207 |
-
metrics.py # collectors + aggregations
|
| 208 |
-
report.py # plot helpers
|
| 209 |
-
app/
|
| 210 |
-
streamlit_app.py # sliders → run → charts
|
| 211 |
-
```
|
| 212 |
-
|
| 213 |
-
### Core data model (V1)
|
| 214 |
-
Start numeric and simple; keep everything observable.
|
| 215 |
-
|
| 216 |
-
- `Soul`
|
| 217 |
-
- `soul_id: int`
|
| 218 |
-
- `karma: float`
|
| 219 |
-
|
| 220 |
-
- `Person`
|
| 221 |
-
- `soul_id: int`
|
| 222 |
-
- `age: int`
|
| 223 |
-
- `max_age: int` (sampled)
|
| 224 |
-
- `health: float`
|
| 225 |
-
- `wellbeing: float`
|
| 226 |
-
- `moral_bias: float` (good↔bad)
|
| 227 |
-
- `consumption_need: float`
|
| 228 |
-
- (optional in V1) `race`, `faith`, `beauty_score` (can exist but not heavily used yet)
|
| 229 |
-
|
| 230 |
-
- `World`
|
| 231 |
-
- `time: int`
|
| 232 |
-
- `resource_pool: ResourcePool`
|
| 233 |
-
- `people: list[Person]`
|
| 234 |
-
- `souls: dict[int, Soul]`
|
| 235 |
-
|
| 236 |
-
### Simulation loop (tick-based)
|
| 237 |
-
For each tick:
|
| 238 |
-
- Replenish global resources
|
| 239 |
-
- For each person:
|
| 240 |
-
- consume resources (if insufficient, wellbeing/health drop)
|
| 241 |
-
- decide actions influenced by `moral_bias` (e.g., share vs hoard)
|
| 242 |
-
- sample an event (configurable probabilities)
|
| 243 |
-
- update wellbeing/health/karma
|
| 244 |
-
- Age everyone, apply deaths
|
| 245 |
-
- For each death:
|
| 246 |
-
- update soul karma summary if needed
|
| 247 |
-
- rebirth: create a new `Person` for the same `Soul`, with traits drawn from distributions shifted by karma
|
| 248 |
-
- Collect metrics for this tick
|
| 249 |
-
|
| 250 |
-
### Metrics to track in V1 (minimum set)
|
| 251 |
-
- Population alive over time (should remain stable-ish given constant soul pool, but death/birth timing matters)
|
| 252 |
-
- Mean/median karma and distribution (histogram)
|
| 253 |
-
- Mean/median wellbeing and distribution
|
| 254 |
-
- Resource pool level over time
|
| 255 |
-
- Inequality proxy (simple: Gini of wellbeing or resources consumed; can be added later)
|
| 256 |
-
- Event counts by type
|
| 257 |
-
|
| 258 |
-
### Scenario knobs (V1 controls)
|
| 259 |
-
- `seed`
|
| 260 |
-
- `num_souls`
|
| 261 |
-
- `ticks`
|
| 262 |
-
- `resource_replenish_rate`
|
| 263 |
-
- `resource_capacity`
|
| 264 |
-
- `baseline_consumption_need`
|
| 265 |
-
- `event_rate` and event mix
|
| 266 |
-
- `initial_moral_bias_mean` and `initial_moral_bias_std`
|
| 267 |
-
- `rebirth_influence_strength` (how strongly karma affects next-life traits)
|
| 268 |
-
|
| 269 |
-
### Testing/validation (pragmatic)
|
| 270 |
-
- Same config + seed produces the same metrics time series
|
| 271 |
-
- Extreme scenarios behave sensibly:
|
| 272 |
-
- very low replenish rate → widespread suffering / collapse-like signals
|
| 273 |
-
- high replenish rate + good bias → higher wellbeing and lower conflict proxies (even if conflict is minimal in V1)
|
| 274 |
-
|
| 275 |
-
---
|
| 276 |
|
| 277 |
-
###
|
| 278 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
- **Bias experiments**: What happens to world stability when the population is biased toward “good nature” vs “bad nature”?
|
| 20 |
- **Scarcity vs abundance**: How do shared natural resources shape inequality, wellbeing, cooperation/conflict, and longevity?
|
| 21 |
- **Identity dynamics**: How do race/faith/beauty norms influence social networks and opportunity, and how do they compound over rebirth cycles?
|
| 22 |
+
- **Sustainability Equilibrium**: What is the ideal balance of population, resources, and moral bias to ensure world longevity?
|
|
|
|
| 23 |
|
| 24 |
+
### Core Features
|
| 25 |
+
- **Deterministic Simulation**: Tick-based engine where every run is reproducible via seed.
|
| 26 |
+
- **Sustainable Equilibrium Optimizer**: An auto-tuning tool that hunts for parameters that maximize world longevity (surviving collapse).
|
| 27 |
+
- **Run History & AI Comparison**: Automatically saves all runs and allows AI to generate comparative insights between two different worlds.
|
| 28 |
+
- **Local AI Insights**: Uses Gemma 2 2b (via `llama_cpp` or `Ollama`) to quantitatively interpret simulation results and causal links.
|
| 29 |
|
| 30 |
+
### High-level model
|
| 31 |
- **Soul**: immutable id; persists across lifetimes; carries karma forward.
|
| 32 |
+
- **Person**: a transient body with traits (moral bias, health, wellbeing).
|
| 33 |
+
- **Karma**: numeric score updated by actions; influences next-life initialization.
|
| 34 |
+
- **Resources**: global pool with replenishment; consumption influenced by moral bias (sharing vs hoarding).
|
| 35 |
+
- **World Collapse**: Simulation ends if resources hit 0, everyone dies, or karma reaches 0.
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
+
### Running the App
|
| 38 |
+
The app is optimized for Hugging Face Spaces using Docker, but can be run locally:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
```bash
|
| 41 |
+
# Run the UI (Streamlit)
|
| 42 |
+
uv run streamlit run src/god_sim/app/streamlit_app.py
|
| 43 |
```
|
| 44 |
|
| 45 |
+
### Local LLM insights
|
| 46 |
+
1) Install Ollama and pull Gemma: `ollama pull gemma2:2b`
|
| 47 |
+
2) Run the app and click **Generate insights**.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
+
### Hugging Face Deployment
|
| 50 |
+
The app uses `llama_cpp` with GGUF for fast, serverless insights:
|
| 51 |
+
- **Provider**: `llama_cpp`
|
| 52 |
+
- **Model Repo**: `bartowski/gemma-2-2b-it-GGUF`
|
| 53 |
+
- **Model File**: `gemma-2-2b-it-Q4_K_M.gguf`
|
| 54 |
+
- **Context Window**: 8192 tokens.
|
SKILLS.md
CHANGED
|
@@ -1,68 +1,33 @@
|
|
| 1 |
# GOD Simulation Skills & Knowledge
|
| 2 |
|
| 3 |
-
This document serves as a guide for working on the GOD reincarnation-based social simulation.
|
| 4 |
|
| 5 |
## 核心理念 (Core Philosophy)
|
| 6 |
The project is a "world engine" simulating a fixed pool of souls cycling through birth, life, death, and rebirth.
|
| 7 |
- **Fixed Soul Pool:** Souls are persistent; only their physical manifestations (Persons) cycle.
|
| 8 |
-
- **
|
| 9 |
-
- **
|
| 10 |
-
- **Extensible Worldviews:** (Planned) Pluggable rulesets for different philosophical lenses (Advaita, Buddhist, etc.).
|
| 11 |
|
| 12 |
-
##
|
| 13 |
-
- **`Soul`**: Immutable ID + persistent `karma`. Carries history across lifetimes.
|
| 14 |
-
- **`Person`**: The transient physical entity. Has `age`, `health`, `wellbeing`, `moral_bias`, and `consumption_need`.
|
| 15 |
-
- **`World`**: Container for the `ResourcePool`, `Person` list, and `Soul` dictionary.
|
| 16 |
-
- **`ResourcePool`**: Manages finite resources with a replenishment rate.
|
| 17 |
|
| 18 |
-
##
|
| 19 |
-
- **
|
| 20 |
-
- **
|
| 21 |
-
1. **Replenish Resources:** Global pool grows by `replenish_rate`.
|
| 22 |
-
2. **Consumption & Interaction:**
|
| 23 |
-
- High `moral_bias` (good) -> Sharing part of resources.
|
| 24 |
-
- Low `moral_bias` (bad) -> Hoarding (requesting more than need).
|
| 25 |
-
- Shortfalls hurt health/wellbeing; surplus helps.
|
| 26 |
-
3. **Karma Updates:** Updated based on `moral_bias` and life events.
|
| 27 |
-
4. **Events:** Stochastic shocks (positive/negative) impacting health/wellbeing.
|
| 28 |
-
5. **Aging & Death:** Health drops with age; death triggers rebirth.
|
| 29 |
-
6. **Rebirth:** A new `Person` is created for the `Soul`. Karma influences the new `moral_bias`.
|
| 30 |
|
| 31 |
-
##
|
| 32 |
-
-
|
| 33 |
-
- **
|
| 34 |
|
| 35 |
-
## AI Insights (`src/god_sim/insights/`)
|
| 36 |
-
The system uses LLMs to interpret
|
| 37 |
-
- **
|
| 38 |
-
- **
|
| 39 |
-
- **
|
| 40 |
-
- `GOD_LLM_PROVIDER`: `llama_cpp`
|
| 41 |
-
- `GOD_LLM_HF_REPO`: `bartowski/gemma-2-2b-it-GGUF`
|
| 42 |
-
- `GOD_LLM_HF_FILE`: `gemma-2-2b-it-Q4_K_M.gguf`
|
| 43 |
-
- **Workflow:**
|
| 44 |
-
1. `build_run_summary` extracts deltas and trends from the simulation output.
|
| 45 |
-
2. LLM analyzes JSON summary to provide bulleted insights and suggested experiments.
|
| 46 |
|
| 47 |
-
##
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
```bash
|
| 51 |
-
uv run god-sim --ticks 200 --num-souls 300
|
| 52 |
-
```
|
| 53 |
-
|
| 54 |
-
### Running the Dashboard
|
| 55 |
-
```bash
|
| 56 |
-
uv run streamlit run src/god_sim/app/streamlit_app.py
|
| 57 |
-
```
|
| 58 |
|
| 59 |
-
##
|
| 60 |
-
|
| 61 |
-
-
|
| 62 |
-
- `resource_replenish_rate`: Controls scarcity.
|
| 63 |
-
- `rebirth_influence_strength`: Controls how much karma matters for the next life.
|
| 64 |
-
|
| 65 |
-
## Adding New Features
|
| 66 |
-
- **New Metrics:** Update `step_world` return dict and `analytics/metrics.py`.
|
| 67 |
-
- **New Rules:** Add logic to `step_world` or create a new module in `rules/`.
|
| 68 |
-
- **New Worldviews:** Implement hooks in `engine/sim.py` that change `moral_bias` interpretation or karma calculation.
|
|
|
|
| 1 |
# GOD Simulation Skills & Knowledge
|
| 2 |
|
| 3 |
+
This document serves as a guide for working on the GOD reincarnation-based social simulation.
|
| 4 |
|
| 5 |
## 核心理念 (Core Philosophy)
|
| 6 |
The project is a "world engine" simulating a fixed pool of souls cycling through birth, life, death, and rebirth.
|
| 7 |
- **Fixed Soul Pool:** Souls are persistent; only their physical manifestations (Persons) cycle.
|
| 8 |
+
- **Sustainability Equilibrium:** The goal is to find parameters where the world does not collapse.
|
| 9 |
+
- **Collapse Conditions:** Resources = 0, Population = 0, or Karma = 0.
|
|
|
|
| 10 |
|
| 11 |
+
## Simulation Engine (`src/god_sim/engine/`)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
+
### Core Simulator (`sim.py`)
|
| 14 |
+
- **Step Logic:** Replenish -> Consume/Interact -> Update Karma -> Events -> Age/Death -> Rebirth.
|
| 15 |
+
- **Collapsed Flag:** Every tick checks if the world has met any exit conditions.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
+
### Sustainable Equilibrium Optimizer (`optimizer.py`)
|
| 18 |
+
- **Evaluation**: Uses a fitness function based on "Longevity" (ticks survived).
|
| 19 |
+
- **Random Search**: Iterates through parameter combinations to find the highest fitness world configuration for a fixed resource capacity.
|
| 20 |
|
| 21 |
+
## AI Insights & Comparisons (`src/god_sim/insights/`)
|
| 22 |
+
The system uses LLMs (Gemma 2 2b) to interpret results.
|
| 23 |
+
- **Single Run (`generate_insights`)**: Quantitative analysis of deltas and trends.
|
| 24 |
+
- **Comparative (`generate_comparative_insights`)**: Analyzing two runs to find causal links between parameter changes and outcomes.
|
| 25 |
+
- **Local Deployment**: Uses `llama_cpp` with GGUF files and an 8192 context window.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
+
## Analytics & Persistence (`src/god_sim/analytics/`)
|
| 28 |
+
- **JSON Serialization**: Uses a custom `SimulationEncoder` in `history.py` to handle `numpy` types and booleans.
|
| 29 |
+
- **Run History**: Saved to `data/run_history.json`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
+
## Development Workflows
|
| 32 |
+
- **Hugging Face**: Deployed via Docker. Environment variables `GOD_LLM_PROVIDER`, `GOD_LLM_HF_REPO`, and `GOD_LLM_HF_FILE` control the AI engine.
|
| 33 |
+
- **Streamlit**: Main entry point is `src/god_sim/app/streamlit_app.py`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/god_sim/app/streamlit_app.py
CHANGED
|
@@ -218,6 +218,30 @@ if history:
|
|
| 218 |
}
|
| 219 |
)
|
| 220 |
st.dataframe(pd.DataFrame(rows), width="stretch")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
else:
|
| 222 |
st.caption("No runs stored yet. Run a simulation to create history.")
|
| 223 |
|
|
|
|
| 218 |
}
|
| 219 |
)
|
| 220 |
st.dataframe(pd.DataFrame(rows), width="stretch")
|
| 221 |
+
|
| 222 |
+
st.subheader("⚖️ AI Comparison")
|
| 223 |
+
st.caption("Select two runs from history to compare them using AI.")
|
| 224 |
+
compare_runs = st.multiselect(
|
| 225 |
+
"Select exactly 2 runs",
|
| 226 |
+
options=list(run_options.keys()),
|
| 227 |
+
max_selections=2,
|
| 228 |
+
help="Select two runs to see how their parameters influenced the emergent world outcomes."
|
| 229 |
+
)
|
| 230 |
+
|
| 231 |
+
if len(compare_runs) == 2:
|
| 232 |
+
if st.button("Generate Comparative Insights"):
|
| 233 |
+
from god_sim.insights.llm import generate_comparative_insights
|
| 234 |
+
run_a = run_options[compare_runs[0]]
|
| 235 |
+
run_b = run_options[compare_runs[1]]
|
| 236 |
+
|
| 237 |
+
cfg_ins = insight_config_from_env()
|
| 238 |
+
# (Assuming standard provider/model selection from below or env)
|
| 239 |
+
try:
|
| 240 |
+
with st.spinner("Analyzing differences..."):
|
| 241 |
+
comparison_text = generate_comparative_insights(run_a, run_b, cfg=cfg_ins)
|
| 242 |
+
st.markdown(comparison_text)
|
| 243 |
+
except Exception as e:
|
| 244 |
+
st.error(f"Comparison failed: {e}")
|
| 245 |
else:
|
| 246 |
st.caption("No runs stored yet. Run a simulation to create history.")
|
| 247 |
|
src/god_sim/insights/llm.py
CHANGED
|
@@ -236,3 +236,61 @@ def generate_insights(sim_output: dict[str, Any], cfg: InsightConfig | None = No
|
|
| 236 |
data = r.json()
|
| 237 |
return str(data["choices"][0]["message"]["content"]).strip()
|
| 238 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
data = r.json()
|
| 237 |
return str(data["choices"][0]["message"]["content"]).strip()
|
| 238 |
|
| 239 |
+
def generate_comparative_insights(out_a: dict[str, Any], out_b: dict[str, Any], cfg: InsightConfig | None = None, timeout_s: int = 120) -> str:
|
| 240 |
+
cfg = cfg or insight_config_from_env()
|
| 241 |
+
summary_a = build_run_summary(out_a, df_tail_rows=10)
|
| 242 |
+
summary_b = build_run_summary(out_b, df_tail_rows=10)
|
| 243 |
+
|
| 244 |
+
user_prompt = (
|
| 245 |
+
"Compare these TWO simulation runs (A and B).\n\n"
|
| 246 |
+
f"RUN_A_SUMMARY:\n{json.dumps(summary_a, indent=2)}\n\n"
|
| 247 |
+
f"RUN_B_SUMMARY:\n{json.dumps(summary_b, indent=2)}\n\n"
|
| 248 |
+
"Analyze the impact of the parameter differences on the outcomes.\n"
|
| 249 |
+
"Return:\n"
|
| 250 |
+
"1) Key differences in longevity and stability\n"
|
| 251 |
+
"2) Causal link: which parameter change likely caused the most significant divergence?\n"
|
| 252 |
+
"3) Which world was 'healthier' and why?\n"
|
| 253 |
+
)
|
| 254 |
+
|
| 255 |
+
if cfg.provider == "ollama":
|
| 256 |
+
url = cfg.ollama_base_url.rstrip("/") + "/api/generate"
|
| 257 |
+
payload = {
|
| 258 |
+
"model": cfg.ollama_model,
|
| 259 |
+
"prompt": user_prompt,
|
| 260 |
+
"system": "You are a comparative analyst for world simulations. Focus on causal differences.",
|
| 261 |
+
"stream": False,
|
| 262 |
+
"options": {"temperature": cfg.temperature},
|
| 263 |
+
}
|
| 264 |
+
r = requests.post(url, json=payload, timeout=timeout_s)
|
| 265 |
+
r.raise_for_status()
|
| 266 |
+
return str(r.json().get("response", "")).strip()
|
| 267 |
+
|
| 268 |
+
if cfg.provider == "llama_cpp":
|
| 269 |
+
try:
|
| 270 |
+
from llama_cpp import Llama
|
| 271 |
+
except ImportError:
|
| 272 |
+
raise RuntimeError("llama-cpp-python not available.")
|
| 273 |
+
|
| 274 |
+
model_path = Path(cfg.model_path)
|
| 275 |
+
llm = Llama(model_path=str(model_path), n_ctx=cfg.n_ctx, n_threads=None if cfg.n_threads <= 0 else cfg.n_threads, verbose=False)
|
| 276 |
+
prompt = f"System: You are a comparative analyst.\nUser: {user_prompt}"
|
| 277 |
+
out = llm(prompt, max_tokens=cfg.max_tokens, temperature=cfg.temperature, stop=["</s>"])
|
| 278 |
+
return str(out["choices"][0]["text"]).strip()
|
| 279 |
+
|
| 280 |
+
# OpenAI-compatible
|
| 281 |
+
url = cfg.openai_base_url.rstrip("/") + "/chat/completions"
|
| 282 |
+
headers = {"Content-Type": "application/json"}
|
| 283 |
+
if cfg.openai_api_key:
|
| 284 |
+
headers["Authorization"] = f"Bearer {cfg.openai_api_key}"
|
| 285 |
+
payload = {
|
| 286 |
+
"model": cfg.openai_model,
|
| 287 |
+
"temperature": cfg.temperature,
|
| 288 |
+
"max_tokens": cfg.max_tokens,
|
| 289 |
+
"messages": [
|
| 290 |
+
{"role": "system", "content": "You are a comparative analyst."},
|
| 291 |
+
{"role": "user", "content": user_prompt},
|
| 292 |
+
],
|
| 293 |
+
}
|
| 294 |
+
r = requests.post(url, headers=headers, json=payload, timeout=timeout_s)
|
| 295 |
+
r.raise_for_status()
|
| 296 |
+
return str(r.json()["choices"][0]["message"]["content"]).strip()
|