Thermodynamic agent-based simulation for complex systems
Project description
phinx — φ-ensemble
Thermodynamic agent-based simulation for complex systems
phinx unifies cellular automata, Bayesian inference, game theory, fractal geometry, and thermodynamic ensembles into a single real-time simulation pipeline — without a global temperature parameter.
Why phinx?
Existing packages handle each domain separately:
| Domain | Existing tools |
|---|---|
| Agent-based models | Mesa |
| Cellular automata | cellpylib |
| Bayesian inference | PyMC, pomegranate |
| Game theory | nashpy, axelrod |
| Thermodynamics | domain-specific only |
phinx integrates all of them into one pipeline with a unified survival function Φ, computable in real time on local hardware — CPU or GPU.
Key idea: local randomness instead of global temperature
Instead of a single global temperature parameter (as in transformers):
# Transformer approach — global T
P(output) = softmax(logits / T)
phinx assigns each agent its own local noise ε, updated through raindrop-collision-style interactions:
εᵢ ~ f(contextᵢ, priorᵢ, neighborsᵢ)
output_i = act(stateᵢ) + εᵢ
The collective effect of local ε distributions produces an emergent effective temperature T*, structurally equivalent to natural uncertainty — without any global parameter.
This is not a metaphor. The raindrop collision probability p = exp(−d/r₀) is mathematically
identical to an attention score softmax(QKᵀ/√d). phinx implements agent interaction as a
masked local attention kernel, accelerated by Triton on GPU.
Mathematical Foundation
The unified survival function
Φ = sigmoid(α·S + β·D − γ·T*) · ⟨cooperation⟩_M
| Symbol | Meaning | Source theory |
|---|---|---|
| S | Shannon entropy of prior distribution | Thermodynamics |
| D | Fractal dimension (box-counting) | Fractal theory |
| T* | Effective temperature = Var(εᵢ)/k | Local randomness |
| ⟨coop⟩_M | Monte Carlo cooperation estimate | Bayesian + Game theory |
| α, β, γ | Aesthetic tuning parameters | — |
Φ → 1: stable system (ESS maintained, fractal healthy, free energy minimum)
Φ → 0: collapse (phase transition reached, D drops, defection ESS)
Three-layer architecture
Micro (Agent ψᵢ) → s, π, P(H), ε, E
↓ raindrop collision + Bayesian update
Ensemble (Z, T*, S, F) → thermodynamic interface
↓ partition function + phase detection
Macro (Ψ, D, ⟨O⟩) → emergent patterns
↑ (feedback: macro state → micro prior)
Thermodynamic ensemble — bridging micro and macro
The ensemble layer computes global system state from local agent distributions, without iterating every agent pair:
Z = Σᵢ exp(−Eᵢ / kT*) partition function
T* = Var(εᵢ) / k emergent temperature (no global T needed)
S = −k Σ Pᵢ ln Pᵢ entropy (diversity → stability)
F = E − T*·S free energy (minimum = stable ESS)
Tc = ∂²F/∂T*² = 0 phase transition point
High entropy S (diverse agent population) → low free energy F → stable system.
Homogenization reduces S → F rises → system approaches collapse threshold Tc.
Raindrop sequence — collision probability
n agents moving on independent paths collide with probability:
P(at least one collision) = 1 − (1−p)^C(n,2)
Each collision is an evidence exchange event that triggers Bayesian belief revision (τ = 3 iterations by default, convergence guaranteed by KL-divergence bound):
P(H|E) ∝ P(E|H) · P(H) ← posterior of agent i after meeting agent j
The local ε of both agents co-evolves after each collision:
εᵢ_new = 0.8·εᵢ + 0.2·εⱼ ← ε co-evolution (local temperature mixing)
This replaces global attention with context-dependent, path-history-aware belief revision — structurally analogous to quantum wavefunction collapse at measurement.
Installation
pip install phinx
With optional dependencies:
pip install phinx[fast] # numba JIT acceleration (CPU)
pip install phinx[gpu] # Triton GPU kernel (RTX 20xx+)
pip install phinx[output] # OSC + WebSocket real-time output
pip install phinx[viz] # matplotlib visualization
pip install phinx[all] # everything
GPU setup (RTX 20xx / 30xx / 40xx)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
pip install triton
pip install phinx[gpu]
Triton kernels activate automatically when a compatible GPU is detected (CC ≥ 7.5). No code changes required — the same API runs identically on CPU and GPU.
Quick Start
import numpy as np
import phinx
# 1. Create grid
grid = phinx.EnsembleGrid(N=16, r=1)
# 2. Randomize initial priors (diversity matters)
for i in range(grid.N):
for j in range(grid.N):
grid.agents[i][j].prior = float(np.random.rand())
# 3. Thermodynamic ensemble
ensemble = phinx.ThermoEnsemble(grid, M=64)
# 4. Run simulation
loop = phinx.PhiLoop(grid, ensemble, fps=60, alpha=0.3, beta=0.4, gamma=0.3)
def on_frame(result):
print(f"frame={result['frame']:04d} "
f"Φ={result['phi']:.3f} "
f"signal={result['signal']}")
results = loop.run(n_frames=100, callback=on_frame)
# 5. Summary
summary = loop.summary()
print(f"Φ mean={summary['phi_mean']:.3f} "
f"avg={summary['avg_total_ms']:.1f}ms/frame")
GPU pipeline (PhinxPipeline)
For real-time installations requiring maximum throughput:
from phinx.core.gpu_pipeline import PhinxPipeline, PhinxConfig
cfg = PhinxConfig(N=32, M=64)
cfg.auto_tune() # reads GPU model + VRAM, sets N/M/D automatically
pipeline = PhinxPipeline(cfg)
for frame in pipeline.run():
print(f"Φ={frame['phi']:.3f} {frame['ms']:.1f}ms")
# frame keys: phi, S, D, T_star, coop, F, is_critical, frame, ms
auto_tune() adapts to the detected hardware:
| Hardware | CC | Auto M | Per-frame target |
|---|---|---|---|
| CPU only | — | 32 | ~40–80ms |
| RTX 2060/70 | 7.5 | 64 | ~12ms ✓ |
| RTX 2080 Ti | 7.5 | 128 | ~8ms ✓ |
| RTX 3060 | 8.6 | 128 | ~6ms ✓ |
| RTX 3080+ | 8.6 | 512 | ~3ms ✓ |
Core Components
Agent — state vector ψᵢ
from phinx import Agent
a = Agent(
prior=0.6, # Bayesian prior P(H) — cooperation belief
epsilon_var=0.1, # local noise variance (replaces global T)
energy=0.4, # internal energy Eᵢ (mind-body state)
)
b = Agent(prior=0.3)
# Raindrop collision → Bayesian update + strategy update + ε co-evolution
a.meet(b, distance=0.5)
print(a.act()) # local ε-sampled action
print(a.to_dict()) # serialize
EnsembleGrid — N×N cellular automata
from phinx import EnsembleGrid
grid = EnsembleGrid(
N=32, # grid size (N² agents)
r=1, # neighbor radius (r=1 → 8 directions)
wrap=True, # toroidal boundary
)
ms = grid.step() # one frame update
print(grid.stats()) # aggregate statistics
print(grid.fractal_dim()) # fractal dimension D ∈ [1.0, 2.0]
GPU Attention Kernel
Agent interactions are implemented as masked local attention — mathematically equivalent to raindrop collision probability — compiled to Triton for GPU execution:
from phinx.core.attention_kernel import agent_attention, masked_agent_attention
# Auto-dispatches: Triton (CC ≥ 7.5) or PyTorch fallback (CPU / older GPU)
out = agent_attention(Q, K, V)
# With neighbor radius mask — only agents within r interact
out = masked_agent_attention(Q, K, V, positions=pos, r=1.5)
Kernel dispatch is fully automatic:
CUDA available
+ Compute Capability ≥ 7.5 (RTX 20xx, 30xx, 40xx)
+ triton installed
──────────────────────────► Triton kernel (fp16, Tensor Core)
otherwise
──────────────────────────► PyTorch fallback (CPU or CUDA, fp32)
Game Theory — payoff matrices + ESS
from phinx import (
PRISONERS_DILEMMA, STAG_HUNT, HARMONY,
is_ess, population_dynamics, pareto_efficiency
)
print(is_ess(1.0, HARMONY)) # True
print(is_ess(1.0, PRISONERS_DILEMMA)) # False
result = population_dynamics(PRISONERS_DILEMMA, initial_coop=0.5, steps=200)
print(f"Converged to cooperation rate: {result['converged_to']:.3f}")
eff = pareto_efficiency(PRISONERS_DILEMMA, coop_rate=0.6)
print(f"Efficiency: {eff['efficiency']:.3f}")
Thermodynamic Ensemble
from phinx import ThermoEnsemble, compute_phi
ensemble = ThermoEnsemble(grid, M=64)
result = compute_phi(grid, ensemble, alpha=0.3, beta=0.4, gamma=0.3)
print(f"Φ={result['phi']:.3f} S={result['S']:.3f} "
f"D={result['D']:.3f} T*={result['T_star']:.4f}")
print(f"signal: {result['signal']}") # stable | warning | critical
Real-time Output
from phinx.output.realtime import RealtimeOutput, ConsoleOutput
# Console (development)
console = ConsoleOutput(every_n=10)
# OSC → Max/MSP, TouchDesigner, SuperCollider
from phinx.output.realtime import OSCOutput
osc = OSCOutput(host="127.0.0.1", port=9000)
# OSC + WebSocket simultaneously
rt = RealtimeOutput(
osc_target=("127.0.0.1", 9000),
ws_port=8765, # WebSocket → browser GLSL / p5.js
)
loop.run(n_frames=1000, callback=rt.send)
OSC message schema
| Address | Type | Range | Description |
|---|---|---|---|
/phinx/phi |
f | [0, 1] | survival index |
/phinx/entropy |
f | [0, ∞) | diversity |
/phinx/fractal |
f | [1, 2] | pattern complexity |
/phinx/temp |
f | [0, ∞) | effective temperature |
/phinx/coop |
f | [0, 1] | cooperation rate |
/phinx/signal |
s | — | "stable"|"warning"|"critical" |
/phinx/frame |
i | — | frame number |
/phinx/critical |
i | [0, 1] | phase transition flag |
Fractal Analysis
from phinx.grid.fractal import fractal_dim_multiscale, fractal_dim_history
state = grid.state_matrix()
analysis = fractal_dim_multiscale(state)
print(f"D(3-scale)={analysis['D_3scale']:.3f} "
f"healthy={analysis['is_healthy']}")
D_history = [grid.fractal_dim() for _ in range(30)]
alert = fractal_dim_history(D_history, window=10)
print(f"alert={alert['alert']} drop={alert['drop']:.3f}")
Interactive Art Applications
phinx was developed in part for the NEMAF 2025 interactive installation artwork.
The survival function Φ maps directly to sensory output:
| Φ component | Visual | Audio |
|---|---|---|
| S (entropy) | color diversity | harmonic richness |
| D (fractal dim) | pattern complexity | rhythmic complexity |
| T* (temperature) | particle turbulence | timbre roughness |
| Φ (combined) | overall density | consonance/dissonance |
| signal=critical | monochrome collapse | noise flood |
# Minimal installation loop — GPU accelerated, OSC output
from phinx.core.gpu_pipeline import PhinxPipeline, PhinxConfig
from pythonosc import udp_client
cfg = PhinxConfig(N=32, M=64)
cfg.auto_tune()
pipeline = PhinxPipeline(cfg)
osc = udp_client.SimpleUDPClient("127.0.0.1", 9000)
for frame in pipeline.run():
osc.send_message("/phinx/phi", frame['phi'])
osc.send_message("/phinx/entropy", frame['S'])
osc.send_message("/phinx/fractal", frame['D'])
osc.send_message("/phinx/temp", frame['T_star'])
osc.send_message("/phinx/critical", int(frame['is_critical']))
Performance
CPU (pure Python, no numba)
| Grid size | step() | compute_phi() | Total/frame |
|---|---|---|---|
| N=8 | ~1ms | ~2ms | ~3ms ✓ |
| N=16 | ~5ms | ~3ms | ~8ms ✓ |
| N=32 | ~20ms | ~4ms | ~24ms ✓ |
Install phinx[fast] for numba JIT acceleration (10–50× speedup on the grid loop).
GPU (Triton kernel — phinx[gpu])
| GPU | CC | N=32 M=64 | N=32 M=128 | 60fps budget |
|---|---|---|---|---|
| RTX 2060/70 | 7.5 | ~12ms | ~16ms | ✓ |
| RTX 2080 Ti | 7.5 | ~8ms | ~10ms | ✓ |
| RTX 3060 | 8.6 | ~6ms | ~8ms | ✓ |
| RTX 3080+ | 8.6 | ~3ms | ~4ms | ✓ |
On CPU-only machines, phinx[gpu] is not required.
PyTorch fallback activates automatically — same API, same results.
Theoretical Background
phinx integrates the following theoretical frameworks:
- Behavioral Psychology — reinforcement, imitation, social learning → agent state
s - Conway's Game of Life — local rules → global emergence → cellular automata grid
- Prisoner's Dilemma / Game Theory — cooperation/defection, ESS, replicator dynamics
- Personality Theory (Big Five, MBTI) — individual parameter variation → diversity
- Fractal Theory — self-similarity across scales → D as complexity measure
- Mind-Body Monism (Spinoza) — physical space ↔ collective psychology → energy
E - Frege's Logic — Sinn/Bedeutung: different theories, same referent (Φ)
- Bayesian Inference — prior → evidence → posterior → raindrop collision update
- Thermodynamics — partition function Z, entropy S, free energy F, phase transition Tc
- Quantum analogy — superposition (local ε before collision) → collapse (Bayesian update)
All unified under the survival function Φ.
Citation
If you use phinx in research or artwork, please cite:
@software{phinx2025,
author = {Lee, Chae-moon},
title = {phinx: Thermodynamic agent-based simulation for complex systems},
year = {2025},
url = {https://github.com/yourusername/phinx},
version = {0.1.0}
}
License
MIT License — see LICENSE for details.
Author
lajjadred
GitHub: @yourusername
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file phinx-0.1.1.tar.gz.
File metadata
- Download URL: phinx-0.1.1.tar.gz
- Upload date:
- Size: 47.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e27c5add716189cb30c03368dc27d187e0a6f89b5565eb7c1884bffec914513
|
|
| MD5 |
3ed50ba3635df6c71f09cb9086e9c150
|
|
| BLAKE2b-256 |
cde6d8e174ab2e9f165dc3afc42bf43c58d9b052290a813598f9eba180a9cca3
|
File details
Details for the file phinx-0.1.1-py3-none-any.whl.
File metadata
- Download URL: phinx-0.1.1-py3-none-any.whl
- Upload date:
- Size: 40.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
011473ebd057d8ba7ebed727afbdfcaf8e58423d339f505dcd65f65bb956ef24
|
|
| MD5 |
5312614bd7a21a60c95ff870d0d25c9d
|
|
| BLAKE2b-256 |
b74b08672744f895373d5de854455f079e2a96c532cddcb1f87776b669d3687d
|