Skip to main content

phinx — φ-ensemble

Thermodynamic agent-based simulation for complex systems

PyPI version Python License: MIT Tests GPU

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

Release files for phinx 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for phinx 0.1.1
File Size Uploaded
phinx-0.1.1.tar.gz 47.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for phinx 0.1.1
File Interpreter ABI Platform
phinx-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 87.8 kB

Release files / phinx-0.1.1.tar.gz

Download URL phinx-0.1.1.tar.gz
Size 47.6 kB
Tags Source
SHA-256 checksum
How to use checksums
1e27c5add716189cb30c03368dc27d187e0a6f89b5565eb7c1884bffec914513
BLAKE2b-256 checksum
How to use checksums
cde6d8e174ab2e9f165dc3afc42bf43c58d9b052290a813598f9eba180a9cca3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Release files / phinx-0.1.1-py3-none-any.whl

Download URL phinx-0.1.1-py3-none-any.whl
Size 40.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
011473ebd057d8ba7ebed727afbdfcaf8e58423d339f505dcd65f65bb956ef24
BLAKE2b-256 checksum
How to use checksums
b74b08672744f895373d5de854455f079e2a96c532cddcb1f87776b669d3687d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page