Compile PLN inference rules to thermodynamic factor graphs and run them via Gibbs sampling — bridging Hyperon/PLN and Extropic/thrml.
- Overview
- Why this matters
- Installation
- Quick start
- How it works
- API reference
- Results
- Hyperon integration outlook
- Project structure
- Contributing
- Acknowledgements
PLN-THRML compiles probabilistic logic inference rules into factor graphs that run on thermodynamic hardware. Each inference splits into two independent paths: strength (s) via Ising Gibbs sampling on TSU, confidence (c) via closed-form algebra on CPU. 5 PLN rules (MP, Deduction, Abduction, Inversion, Revision) are implemented and verified end-to-end with 88 tests.
New to PLN? (30-second primer)
PLN represents uncertain knowledge with two numbers:
| Component | Meaning | Analogy |
|---|---|---|
| strength s | How likely something is true | A poll result: "80% of respondents said yes" |
| confidence c | How much evidence supports the estimate | The poll's sample size: 1,000 people vs 10 people |
(stv 0.8 0.9) means "80% likely true, based on strong evidence."
(stv 0.8 0.01) means "80% likely true, but we barely know — almost a guess."
Where do s and c come from? Given n observations, n⁺ of which are positive, and a prior weight k (default 1):
s = n⁺ / n c = n / (n + k)
More observations push c → 1; fewer keep it near 0. The strength s is just the observed frequency. This dual-value semantics is what makes PLN more expressive than plain probabilities, and what this project must preserve when compiling to hardware.
New to thrml / factor graphs? (30-second primer)
A factor graph is a bipartite graph of variable nodes and factor nodes. Each variable holds a discrete distribution; each factor encodes how likely certain state combinations are via a weight table.
In thrml, two primitives cover everything PLN-THRML needs:
| thrml construct | What it does |
|---|---|
SpinNode |
Binary (±1) variable — 1 pbit per proposition |
SpinEBMFactor |
Ising bias (h) + coupling (J) between spins |
Every proposition is one SpinNode — 1 pbit, exact 2×2 encoding, zero
discretisation error for strength. Rules differ only in how the spins
connect: a chain of SpinEBMFactors for deduction, a joint 2-node graph
for inversion, a hidden-unit topology for abduction's explaining-away.
Gibbs sampling iteratively resamples each variable conditioned on its
neighbors until the joint distribution converges. The Boltzmann connection
P(x) ∝ e^{−ℰ(x)} means lower energy = higher probability — so
log-probabilities become energy weights directly.
Technical summary: PLN's 2×2 conditional probability table encodes exactly as Ising parameters (bias h, coupling J) — 1 pbit per proposition, zero discretisation error for strength. Confidence propagates via closed-form PLN/QLN algebra on CPU, running in parallel with the TSU sampler. 5 rules × multiple parameter sets × 88 tests constitute the evidence. Rule selection and structure discovery remain on CPU/GPU.
The core task is propagating PLN truth values across a knowledge graph — given known premises, infer the strength and confidence of every reachable conclusion. Each architecture parallelizes this differently and hits different bottlenecks:
| CPU | GPU (estimated) | TSU | |
|---|---|---|---|
| Parallelism | Sequential per-rule | Batched tensor contraction | All nodes sample simultaneously |
| Bottleneck | Inference chain length | Communication + memory bandwidth | Mixing time (energy barrier height) |
| Best fit | Small graphs, exact reasoning | Large sparse graphs | Graph topology fits on-chip¹ |
On CPU, PLN runs rule-based chaining — each step applies one rule's formula in dependency order. On GPU, Goertzel's RAPTL-ShardZipper framework encodes logical relations as sparse tensors for batch contraction. On a TSU, the knowledge graph compiles into a factor graph where all sampling cells update in parallel via block Gibbs sampling — wall-clock per iteration is independent of node count for bipartite graphs that fit on-chip, but total time depends on mixing time, graph depth, and lattice size.
¹ Graphs exceeding a single TSU chip require multi-chip partitioning with communication overhead. Mixing time depends on graph structure and can grow sharply for landscapes with tall energy barriers.
The TSU architecture paper (arXiv:2510.23972) reports ~10,000× lower energy per sample vs GPU baselines on DTM sampling of binarized Fashion-MNIST (E_cell ≈ 2 femtojoules). PLN factor graph inference is expected to benefit similarly but has not been independently benchmarked.
git clone --recurse-submodules https://github.com/xiaohanma-oss/PLN-THRML.git
cd PLN-THRML
pip install -e . # core only (thrml + jax)
pip install -e ".[dev]" # + pytest for running testsThe trueagi-io/PLN submodule provides test baselines. If you cloned without
--recurse-submodules, rungit submodule update --init.
from pln_thrml import unified_modus_ponens
# Modus ponens: P(A)=(0.8, 0.9), s(A→B)=0.9, c(A→B)=0.85
s, c, meta = unified_modus_ponens(s_A=0.8, c_A=0.9, s_AB=0.9, c_AB=0.85)
print(f"P(B) = (stv {s:.3f} {c:.3f})") # ≈ (stv 0.777 0.765)
# s from Ising Gibbs sampling, c from PLN closed-form formulafrom pln_thrml.hybrid import hybrid_modus_ponens
# Same inference — binary Ising s + PLN formula c
s, c = hybrid_modus_ponens(s_A=0.8, c_A=0.9, s_AB=0.9, c_AB=0.85)
print(f"P(B) = (stv {s:.3f} {c:.3f})") # ≈ (stv 0.777 0.765)# Run per-file to avoid OOM (JAX compilation cache grows large)
python -m pytest tests/test_unified.py -v
python -m pytest tests/test_hybrid.py -v- Compile s — PLN's 2×2 conditional table
[1−ε, ε; 1−s_AB, s_AB](rows = parent F/T, cols = child F/T, ε = background rate ≈ 0.02 = P(child=T | parent=F)) maps exactly to Ising parameters: bias h encodes the prior, coupling J encodes the implication strength. 1SpinNodeper proposition. - Sample s (TSU) — Block Gibbs sampling over Ising spins. Binary encoding means zero discretisation error for strength.
- Compute c (CPU) — PLN closed-form: e.g.
c_B = c_A × c_ABfor modus ponens. No sampling needed — deterministic algebra. - Return —
(strength, confidence)per rule.
| PLN concept | Hardware path | Device |
|---|---|---|
| Proposition | SpinNode (binary ±1) |
pbit |
| Prior P(A) | Ising bias h | Bias field |
| Implication A→B | Ising coupling J | Coupling |
| Confidence c | PLN/QLN formula on CPU | CPU |
| Deduction chain | Chain of Ising spins | Spin pipeline |
| Abduction (inverted-V) | Hidden-unit topology | Explaining-away |
| Inversion (Bayes) | 2-node all-free joint graph | pbit pair |
| Revision | PLN book formula: n_rev = n₁ + n₂ (raw) | CPU only |
| Function | Rule |
|---|---|
unified_modus_ponens(s_A, c_A, s_AB, c_AB) |
A, A→B ⊢ B |
unified_deduction(s_A, c_A, s_B, c_B, s_C, c_C, s_AB, c_AB, s_BC, c_BC) |
A→B, B→C ⊢ A→C |
unified_abduction(s_A, c_A, s_B, c_B, s_AC, c_AC, s_BC, c_BC) |
A→C, B→C ⊢ A→B |
unified_inversion(s_A, c_A, s_B, c_B, s_AB, c_AB) |
A→B ⊢ B→A |
unified_revision(s1, c1, s2, c2) |
merge two evidence streams |
TSU rules (MP, Deduction, Abduction) return (strength, confidence, metadata) and iterate 2–3 rounds. CPU-only rules (Inversion, Revision) return (strength, confidence) immediately.
| Function | Rule |
|---|---|
hybrid_modus_ponens(s_A, c_A, s_AB, c_AB) |
A, A→B ⊢ B |
hybrid_deduction(s_A, c_A, ..., s_AB, c_AB, s_BC, c_BC) |
A→B, B→C ⊢ A→C |
hybrid_abduction(s_A, c_A, ..., s_AC, c_AC, s_BC, c_BC) |
A→C, B→C ⊢ A→B |
hybrid_inversion(s_A, c_A, s_B, c_B, s_AB, c_AB) |
A→B ⊢ B→A |
All return (strength, confidence).
| Function | Purpose |
|---|---|
c_modus_ponens(c_A, c_AB) |
c_B = c_A × c_AB |
c_deduction(s_AB, c_AB, s_BC, c_BC) |
c_AC from chain |
c_abduction(s_AC, c_AC, s_BC, c_BC) |
c_AB from shared consequent |
inversion_bayes(s_A, c_A, s_B, c_B, s_AB, c_AB) |
Exact Bayesian P(B→A) |
inversion_pln(s_A, c_A, s_B, c_B, s_AB, c_AB) |
PLN heuristic |
revision(s1, c1, s2, c2) |
Evidence merge: n_rev = n₁ + n₂ |
5 PLN rules verified across three architecture levels (88 tests total). Representative strength errors (Δ vs DTV continuous baseline):
| Rule | Unified (Ising+QLN) | Hybrid (Binary+PLN) |
|---|---|---|
| Modus Ponens | 0.053 | 0.018 |
| Deduction | 0.050 | 0.019 (3-spin joint chain) |
| Abduction | 0.116 | 0.002 (Ded∘Inv reduction, Bayes-correct bg) |
| Inversion | 0.021 (Bayes exact) | Bayes exact |
| Revision | 0.001 (PLN book) | — |
All rules use the binary Ising path (1 pbit per proposition, zero discretisation error for strength). Inversion and Revision are CPU-only (Bayes formula and PLN book n_rev = n₁ + n₂ raw counts).
RAPTL (Resource-Aware Probabilistic Tensor Logic) bundles inference into a triple product quantale Q = Q_logic × Q_uncertainty × Q_resource. These three components travel together through every operation — RAPTL's joint optimization depends on co-locating all three so that, e.g., uncertainty tolerance can inform sparse-to-dense approximation decisions alongside resource constraints.
This project takes a different approach: extract Q_tv and compile it to TSU hardware by splitting strength (TSU Ising sampling) from confidence (CPU closed-form), keeping Q_logic on CPU/GPU. This trades RAPTL's joint optimization for hardware-native sampling — 5 PLN rules validate that Q_tv executes faithfully this way.
A possible heterogeneous pipeline extending this idea:
| Tier | Hardware | Role |
|---|---|---|
| Control | CPU | Variable binding, rule scheduling |
| Compile | CPU+GPU | Sparse tensor contraction, graph sharding (ShardZipper) |
| Sample | TSU | Boltzmann sampling over compiled factor graphs |
The Sample tier is more general than PLN alone — any algorithm reducible to sampling from P(x) ∝ e^{−ℰ(x)} is a candidate (see Sister Projects).
The three-tier pipeline is our projection, not described in the references. Whether the gain from hardware-native sampling outweighs the loss of RAPTL's joint optimization is an open question.
pln_thrml/ Main package
__init__.py Public API re-exports (pln_utils + unified + qln_cpu)
pln_utils.py PLN conversion utilities (c2w, w2c, stv_to_beta_params — no thrml dependency)
hybrid.py Binary Ising s + PLN formula c (MP / 3-spin-chain Deduction / Ded∘Inv Abduction / 2-node Inversion)
compiler_binary.py Binary Ising compiler (1 pbit/proposition, exact 2×2 encoding, joint 2-node graph)
unified.py Unified LBM(s) on TSU + QLN(n) on CPU: per-rule g(n) calibration
qln_cpu.py QLN n-layer: closed-form confidence propagation (Inversion, Revision)
compiler_unified.py Confidence-modulated Ising compiler (g(n) precision scaling)
dtv_baseline.py DTV continuous Monte Carlo baseline (zero discretization error)
vendor/PLN/ trueagi-io/PLN (git submodule) — test baselines
tests/
conftest.py Shared strength tolerance (±0.05); confidence is closed-form (≤1e-3)
test_unified.py Unified architecture validation (DTV / PLN / Unified / Inversion / Revision)
test_hybrid.py Binary-Ising-s + PLN-formula-c validation (DTV / PLN / Binary / Hybrid)
See CONTRIBUTING.md for development setup, testing, code conventions, and pull request guidelines.
Five projects compiling Hyperon's cognitive architecture to thermodynamic hardware:
| Project | What it compiles |
|---|---|
| PLN-THRML | Probabilistic inference → Boltzmann energy tables |
| ECAN-THRML | Attention diffusion → Lattice Boltzmann simulation |
| MOSES-THRML | Program evolution → Boltzmann sampling |
| QuantiMORK-THRML | Predictive coding → wavelet-sparse factor graphs |
| Geodesic-THRML | Unified geodesic scheduler for all above |
- Hyperon/PLN — TrueAGI
- thrml — Extropic AI factor graph library
MIT — Copyright (c) 2026 Xiaohan Ma