thermoc-erasure 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- thermoc_erasure-0.2.0/LICENSE +10 -0
- thermoc_erasure-0.2.0/MANIFEST.in +7 -0
- thermoc_erasure-0.2.0/MANUAL.md +546 -0
- thermoc_erasure-0.2.0/PKG-INFO +125 -0
- thermoc_erasure-0.2.0/README.md +92 -0
- thermoc_erasure-0.2.0/examples/item2_adapter.py +82 -0
- thermoc_erasure-0.2.0/examples/profile_gpt2_block.py +20 -0
- thermoc_erasure-0.2.0/examples/profile_item2_chain.py +22 -0
- thermoc_erasure-0.2.0/examples/profile_resnet50.py +21 -0
- thermoc_erasure-0.2.0/integration/ENERGYIR_INTEGRATION.md +81 -0
- thermoc_erasure-0.2.0/pyproject.toml +44 -0
- thermoc_erasure-0.2.0/pytest.ini +3 -0
- thermoc_erasure-0.2.0/setup.cfg +4 -0
- thermoc_erasure-0.2.0/src/thermoc/__init__.py +3 -0
- thermoc_erasure-0.2.0/src/thermoc/__main__.py +4 -0
- thermoc_erasure-0.2.0/src/thermoc/_vendor/__init__.py +1 -0
- thermoc_erasure-0.2.0/src/thermoc/_vendor/thermoir/__init__.py +15 -0
- thermoc_erasure-0.2.0/src/thermoc/_vendor/thermoir/backend.py +76 -0
- thermoc_erasure-0.2.0/src/thermoc/_vendor/thermoir/ir.py +71 -0
- thermoc_erasure-0.2.0/src/thermoc/_vendor/thermoir/passes.py +108 -0
- thermoc_erasure-0.2.0/src/thermoc/allocate_time.py +193 -0
- thermoc_erasure-0.2.0/src/thermoc/cli.py +65 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/__init__.py +19 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/attribution.py +114 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/backends/capability.py +67 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/backends/simulated_adiabatic.py +60 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/benchmarks.py +119 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/budget.py +100 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/certify.py +135 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/cli_impl.py +150 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/constants.py +27 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/demos.py +75 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/estimators/base.py +38 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/estimators/empirical.py +231 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/estimators/glauber.py +203 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/estimators/worstcase.py +187 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/frontends/__init__.py +29 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/frontends/stablehlo.py +23 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/frontends/thermoir_frontend.py +60 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/frontends/torch_fx.py +211 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/html.py +163 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/ir.py +134 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/ir_protocols.py +33 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/licensing.py +162 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/measurement.py +46 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/pebble.py +214 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/plan_format.py +66 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/planner.py +129 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/profile_api.py +85 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/report.py +89 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/rewrite/__init__.py +61 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/rewrite/framework.py +131 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/rewrite/substitutions.py +146 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/rewrite/uncompute.py +187 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/taxonomy/__init__.py +35 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/taxonomy/registry.py +101 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/taxonomy/seed_irrev.py +332 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/taxonomy/seed_rev.py +204 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/taxonomy/seed_stoch.py +97 -0
- thermoc_erasure-0.2.0/src/thermoc/erasure/trace.py +124 -0
- thermoc_erasure-0.2.0/src/thermoc_erasure.egg-info/PKG-INFO +125 -0
- thermoc_erasure-0.2.0/src/thermoc_erasure.egg-info/SOURCES.txt +83 -0
- thermoc_erasure-0.2.0/src/thermoc_erasure.egg-info/dependency_links.txt +1 -0
- thermoc_erasure-0.2.0/src/thermoc_erasure.egg-info/entry_points.txt +2 -0
- thermoc_erasure-0.2.0/src/thermoc_erasure.egg-info/requires.txt +14 -0
- thermoc_erasure-0.2.0/src/thermoc_erasure.egg-info/top_level.txt +1 -0
- thermoc_erasure-0.2.0/tests/conftest.py +82 -0
- thermoc_erasure-0.2.0/tests/erasure_testlib.py +100 -0
- thermoc_erasure-0.2.0/tests/test_acceptance_fr1.py +59 -0
- thermoc_erasure-0.2.0/tests/test_allocate_time.py +101 -0
- thermoc_erasure-0.2.0/tests/test_budget.py +45 -0
- thermoc_erasure-0.2.0/tests/test_constants.py +33 -0
- thermoc_erasure-0.2.0/tests/test_empirical.py +130 -0
- thermoc_erasure-0.2.0/tests/test_glauber_sigma.py +100 -0
- thermoc_erasure-0.2.0/tests/test_ir_frontends.py +162 -0
- thermoc_erasure-0.2.0/tests/test_licensing.py +142 -0
- thermoc_erasure-0.2.0/tests/test_m3_end_to_end.py +87 -0
- thermoc_erasure-0.2.0/tests/test_pebble.py +133 -0
- thermoc_erasure-0.2.0/tests/test_planner.py +101 -0
- thermoc_erasure-0.2.0/tests/test_report_certify.py +119 -0
- thermoc_erasure-0.2.0/tests/test_substitutions.py +93 -0
- thermoc_erasure-0.2.0/tests/test_taxonomy.py +117 -0
- thermoc_erasure-0.2.0/tests/test_uncompute.py +76 -0
- thermoc_erasure-0.2.0/tests/test_vendor.py +65 -0
- thermoc_erasure-0.2.0/tests/test_worstcase.py +168 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Copyright (c) 2026 David Johnson / EnergyIR. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and its accompanying documentation are proprietary.
|
|
4
|
+
No permission is granted to use, copy, modify, distribute, or create
|
|
5
|
+
derivative works of this software, in whole or in part, without prior
|
|
6
|
+
written agreement from the copyright holder.
|
|
7
|
+
|
|
8
|
+
The vendored ThermoIR snapshot under src/thermoc/_vendor/thermoir/ is a
|
|
9
|
+
frozen copy of the author's own EnergyIR research-stack prototype and is
|
|
10
|
+
covered by the same terms.
|
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
# ThermoC `erasure` — User Manual
|
|
2
|
+
|
|
3
|
+
**Version 0.1.0 · July 2026 · EnergyIR**
|
|
4
|
+
Reversibility analysis, Landauer erased-bit accounting, erasure-minimizing
|
|
5
|
+
graph rewrites, and adiabatic execution planning for computation graphs.
|
|
6
|
+
|
|
7
|
+
This manual covers the complete end-to-end workflow: profile a model →
|
|
8
|
+
read the report → certify the floor → rewrite the graph → emit and
|
|
9
|
+
simulate an adiabatic execution plan.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. What this compiler does, in one page
|
|
14
|
+
|
|
15
|
+
Every logically **irreversible** operation — every bit overwritten, rounded
|
|
16
|
+
away, or discarded — has a hard physical minimum energy cost:
|
|
17
|
+
|
|
18
|
+
> **Landauer bound.** Erasing ΔS bits into a bath at temperature T
|
|
19
|
+
> dissipates heat Q ≥ k_B·T·ln2·ΔS.
|
|
20
|
+
> At 300 K that is **2.87098 × 10⁻²¹ joules per bit** — a law of physics,
|
|
21
|
+
> not an engineering estimate.
|
|
22
|
+
|
|
23
|
+
Every logically **reversible** operation has no such floor: on
|
|
24
|
+
adiabatic-capable hardware its dissipation can be driven toward zero by
|
|
25
|
+
running it more slowly (E ≈ a/τ).
|
|
26
|
+
|
|
27
|
+
`thermoc.erasure` is the compiler subsystem that exploits this:
|
|
28
|
+
|
|
29
|
+
| Phase | What it does | Command |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| **A — Measure** | Counts the erased bits of every op in your graph, attributes a certified joule floor per op, ranks hotspots | `erasure profile` |
|
|
32
|
+
| **A — Certify** | Emits a signed physics certificate of the floor | `erasure certify` |
|
|
33
|
+
| **B — Restructure** | Removes erasures via substitutions, uncomputation, and Bennett pebble scheduling, under your memory/latency budgets | `rewrite()` |
|
|
34
|
+
| **B — Plan** | Emits an adiabatic execution plan with provably optimal per-op time allocation; refuses non-adiabatic backends | `erasure plan` |
|
|
35
|
+
|
|
36
|
+
**The honest line (PRD P4/N1), stated up front:** floors and headroom are
|
|
37
|
+
physics *reference lines*. Actual joule savings are realized **only** on
|
|
38
|
+
adiabatic-capable hardware via Phase B plans. The tool never claims energy
|
|
39
|
+
savings on GPUs or conventional CMOS — it refuses, with an explanation.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. Installation & environment
|
|
44
|
+
|
|
45
|
+
The project is self-contained at:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
/Users/davidjohnson/Desktop/Spectral/EnergyIR/thermoc_erasure/
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
It lives inside the production EnergyIR repository **without touching it**
|
|
52
|
+
(vendored ThermoIR snapshot, read-only borrows only).
|
|
53
|
+
|
|
54
|
+
**Requirements:** Python ≥ 3.11 with numpy. Optional: `torch` +
|
|
55
|
+
`transformers` (for the PyTorch frontend and neural-net demos),
|
|
56
|
+
`hypothesis` + `scipy` (dev/tests). On this machine everything is already
|
|
57
|
+
present in `/opt/anaconda3/bin/python`.
|
|
58
|
+
|
|
59
|
+
**No install needed** — run from the project folder:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
cd "/Users/davidjohnson/Desktop/Spectral/EnergyIR/thermoc_erasure"
|
|
63
|
+
|
|
64
|
+
# full test suite (150 tests, ~75 s; the physics gates live here)
|
|
65
|
+
/opt/anaconda3/bin/python -m pytest
|
|
66
|
+
|
|
67
|
+
# CLI without installing
|
|
68
|
+
PYTHONPATH=src /opt/anaconda3/bin/python -m thermoc --help
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Optionally, in your own venv: `pip install -e .` gives you the `thermoc`
|
|
72
|
+
console command directly.
|
|
73
|
+
|
|
74
|
+
Throughout this manual, `thermoc` means
|
|
75
|
+
`PYTHONPATH=src /opt/anaconda3/bin/python -m thermoc` run from the project
|
|
76
|
+
folder.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 3. Quickstart: profile a model in 60 seconds
|
|
81
|
+
|
|
82
|
+
### 3.1 Builtin demo targets
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
thermoc erasure profile resnet50 --mode empirical --out out_resnet
|
|
86
|
+
thermoc erasure profile gpt2-block --mode worstcase --out out_gpt2
|
|
87
|
+
thermoc erasure profile item2-chain --out out_item2
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Example output (GPT-2 block, worstcase):
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
graph: GPT2Block ops: 27 mode: worstcase
|
|
94
|
+
Landauer floor: 8.1470e-14 J erased bits: 2.8377e+07 sigma_env: 0 nats
|
|
95
|
+
top hotspots:
|
|
96
|
+
3.613e-14 J 44.3% gelu torch_fx:0025:act
|
|
97
|
+
2.709e-14 J 33.3% linear torch_fx:0026:mlp_proj
|
|
98
|
+
1.411e-16 J 0.2% softmax torch_fx:0016:softmax
|
|
99
|
+
...
|
|
100
|
+
wrote json: out_gpt2/erasure_report.json
|
|
101
|
+
wrote html: out_gpt2/erasure_report.html
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Open `erasure_report.html` in any browser — it is fully self-contained
|
|
105
|
+
(no CDNs): headline cards, hotspot chart, sortable per-op table,
|
|
106
|
+
warnings, unclassified-op panel.
|
|
107
|
+
|
|
108
|
+
### 3.2 Your own PyTorch model
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
thermoc erasure profile path/to/my_model.py --mode empirical --out out/
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`my_model.py` must expose:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
def get_model(): # returns an nn.Module (eval mode recommended)
|
|
118
|
+
...
|
|
119
|
+
def get_example_inputs(): # returns a tensor / tuple of tensors
|
|
120
|
+
...
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
or pass inputs from a file: `--inputs batch.npz` (first array is used).
|
|
124
|
+
|
|
125
|
+
### 3.3 Modes: `worstcase` vs `empirical`
|
|
126
|
+
|
|
127
|
+
- **`worstcase`** — no execution. Distribution-free preimage arithmetic:
|
|
128
|
+
an *upper* attribution per op ("at most this many bits"), plus the
|
|
129
|
+
uniform-ensemble column used for certificates. This is the only mode
|
|
130
|
+
whose certificate is a valid bound.
|
|
131
|
+
- **`empirical`** — runs your model on the example inputs, streams
|
|
132
|
+
activation histograms (never stores raw activations), and estimates the
|
|
133
|
+
bits actually erased *on your workload*, with bootstrap confidence
|
|
134
|
+
intervals. Deterministic for a fixed `--seed` (bin edges are frozen on
|
|
135
|
+
the first batch). Never certifiable; always ≤ the worstcase column.
|
|
136
|
+
|
|
137
|
+
Useful flags:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
--temperature 300 bath temperature in K (floor scales linearly)
|
|
141
|
+
--seed 0 --bins 64 empirical estimator settings
|
|
142
|
+
--top-k 10 hotspot count
|
|
143
|
+
--measured-json m.json attach measured energy => headroom column
|
|
144
|
+
--no-html JSON only
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`m.json` schema: `{"total_J": 12.3, "per_op": {...}?, "source": "nvml"}` —
|
|
148
|
+
any measurement source works; v1 deliberately does not bind NVML/RAPL.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 4. Reading the report
|
|
153
|
+
|
|
154
|
+
Every op row carries **three erased-bit columns** — they answer different
|
|
155
|
+
questions and are deliberately kept separate:
|
|
156
|
+
|
|
157
|
+
| Column | Meaning | Use |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `delta_S_worstcase_bits` | max over inputs of log₂\|preimage\| — an upper bound for **every** input distribution. **= 0 ⇔ op is logically reversible.** | reversibility certification, rewrite targeting |
|
|
160
|
+
| `delta_S_uniform_bits` | erased bits under a uniform ensemble over the dtype domain | the certified floor (Form B) |
|
|
161
|
+
| `delta_S_empirical_bits` | erased bits measured on your traced workload (± CI) | profiling truth |
|
|
162
|
+
|
|
163
|
+
Ordering is always `empirical ≤ uniform ≤ worstcase` (tested).
|
|
164
|
+
|
|
165
|
+
**Classes:**
|
|
166
|
+
- `REV` — reversible (ΔS_wc = 0). Examples: transpose/reshape, XOR,
|
|
167
|
+
integer add, LeakyReLU(α≠0), coupling layers, RevNet blocks, RoPE, FFT,
|
|
168
|
+
*numerically full-rank square* linear (checked at runtime via SVD — a
|
|
169
|
+
singular or ill-conditioned weight is demoted with its σ-spectrum
|
|
170
|
+
recorded; condition number literally becomes a bit count).
|
|
171
|
+
- `IRREV` — information-destroying, with a derived formula. E.g. ReLU
|
|
172
|
+
erases exactly p(x≤0)·H(x|x≤0); softmax erases exactly one scalar (the
|
|
173
|
+
mean logit) per row; quantization erases bits_in − bits_out per element.
|
|
174
|
+
- `STOCH` — sampling ops. Accounted by **entropy production σ** (nats),
|
|
175
|
+
not deterministic erasure: heat ≥ k_B·T·σ. For Gibbs/Glauber sweeps σ is
|
|
176
|
+
computed exactly from the trajectory ledger.
|
|
177
|
+
- `UNKNOWN` — unclassified kind. **Soundness rule:** treated as full-input
|
|
178
|
+
erasure (worstcase), logged, and listed in the report's
|
|
179
|
+
`unclassified ops` panel. If you see UNKNOWN inflating your floor, add a
|
|
180
|
+
spec (§9).
|
|
181
|
+
|
|
182
|
+
**Headroom** = measured_J / floor_J. Expect 10⁵–10⁶× on today's hardware —
|
|
183
|
+
that gap is the industry's total remaining prize, not a promise this tool
|
|
184
|
+
saves it on your GPU.
|
|
185
|
+
|
|
186
|
+
**Sanity anchors** (what a healthy report looks like): ResNet-50 —
|
|
187
|
+
conv/relu/pool dominate; GPT-2 block — GELU and the non-square MLP
|
|
188
|
+
projection dominate, softmax is tiny (exactly b bits per attention row);
|
|
189
|
+
item-2 chain — the first stage dissipates (+σ), later noising stages
|
|
190
|
+
absorb heat (−σ, zero floor).
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 5. Certification
|
|
195
|
+
|
|
196
|
+
```sh
|
|
197
|
+
thermoc erasure certify out_gpt2/erasure_report.json --out cert.json
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The certificate contains **two claim forms** (this is a deliberate,
|
|
201
|
+
documented soundness correction to the PRD's original FR6 wording — flag
|
|
202
|
+
for legal review):
|
|
203
|
+
|
|
204
|
+
- **Form A — reversibility (distribution-free, fully sound).** Lists the
|
|
205
|
+
ops with ΔS_wc = 0: *"these contribute no Landauer floor under any input
|
|
206
|
+
distribution."* Valid because worstcase preimage counting upper-bounds
|
|
207
|
+
the erased entropy for every distribution.
|
|
208
|
+
- **Form B — floor (ensemble-bound).** *"Under the declared input ensemble
|
|
209
|
+
(default: uniform over the dtype domain), the **average** dissipation of
|
|
210
|
+
any physical device executing this exact graph at T is ≥ X J."*
|
|
211
|
+
A distribution-free nonzero floor does not exist (a point-mass input
|
|
212
|
+
erases nothing), so the ensemble must be declared — and is.
|
|
213
|
+
|
|
214
|
+
Guard rails baked into the artifact:
|
|
215
|
+
- empirical-mode reports always produce `claim_valid: false` and a
|
|
216
|
+
`[NOT A BOUND — empirical mode]` prefix;
|
|
217
|
+
- the claim binds to *this graph's semantics* — a different algorithm for
|
|
218
|
+
the same task may have a lower floor;
|
|
219
|
+
- Landauer is an ensemble-average bound (single-shot fluctuations can
|
|
220
|
+
undershoot it — Jarzynski); the wording says "average".
|
|
221
|
+
|
|
222
|
+
**Signing:** set `THERMOC_SIGNING_KEY` (and optionally
|
|
223
|
+
`THERMOC_SIGNING_KEY_ID`) in the environment → HMAC-SHA256 over canonical
|
|
224
|
+
JSON. Unset → `alg: none` with an explicit warning. Verify in Python:
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
import json
|
|
228
|
+
from thermoc.erasure.certify import verify
|
|
229
|
+
assert verify(json.load(open("cert.json")))
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 6. Python API (end-to-end)
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
import sys
|
|
238
|
+
sys.path.insert(0, "/Users/davidjohnson/Desktop/Spectral/EnergyIR/thermoc_erasure/src")
|
|
239
|
+
|
|
240
|
+
from thermoc.erasure import profile, rewrite, plan, Budget
|
|
241
|
+
|
|
242
|
+
# ---- Phase A: profile -------------------------------------------------
|
|
243
|
+
import torch
|
|
244
|
+
model = MyModel().eval()
|
|
245
|
+
x = torch.randn(8, 128)
|
|
246
|
+
|
|
247
|
+
rep = profile(model, x, mode="empirical", temperature_K=300.0, seed=0)
|
|
248
|
+
print(rep.total_floor_J) # graph Landauer floor, joules
|
|
249
|
+
print(rep.hotspots[:5]) # ranked irreversibility hotspots
|
|
250
|
+
rep.save("out/") # erasure_report.json + .html
|
|
251
|
+
|
|
252
|
+
# ---- Phase B: rewrite under budgets ------------------------------------
|
|
253
|
+
g = rep.graph # the live erasure-IR graph
|
|
254
|
+
g2, rw = rewrite(g, Budget(mem="4x", latency="2x"))
|
|
255
|
+
print(rw.erased_bits_before, "->", rw.erased_bits_after)
|
|
256
|
+
for cert in rw.certificates: # every rewrite carries a certificate
|
|
257
|
+
print(cert.rule, cert.delta_bits, cert.equivalence)
|
|
258
|
+
|
|
259
|
+
# ---- Phase B: plan + simulate ------------------------------------------
|
|
260
|
+
xp = plan(g2, "phal:pb64", latency_budget_s=1.0)
|
|
261
|
+
xp.save("execution_plan.json")
|
|
262
|
+
|
|
263
|
+
from thermoc.erasure.backends.simulated_adiabatic import SimulatedAdiabaticBackend
|
|
264
|
+
sim = SimulatedAdiabaticBackend("phal:pb64").run(xp)
|
|
265
|
+
print(xp.E_total_pred_J, sim.E_total_J) # agree within 2% (M3 gate)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`profile()` accepts an `nn.Module` (+ example inputs), an
|
|
269
|
+
`fx.GraphModule`, a ThermoIR `Program`, or an `EGraph`.
|
|
270
|
+
|
|
271
|
+
### 6.1 ThermoIR / p-bit programs and σ accounting
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from thermoc.erasure.demos import item2_chain
|
|
275
|
+
prog, _ = item2_chain(T=6, L=16) # item-2 DTM forward chain
|
|
276
|
+
rep = profile(prog, mode="empirical", seed=0)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Empirical mode executes the chain with the **σ ledger**: per Glauber
|
|
280
|
+
update, the exact pathwise entropy flow Δs_env = β·f_i·(Δs_i) = β·Q. Per
|
|
281
|
+
stage you get `sigma_env_nats` and a stage floor
|
|
282
|
+
kT·max(σ,0). The cheap production estimator
|
|
283
|
+
(σ̂ = β·Σ f·(tanh(βf) − s), the Rao-Blackwellized conditional expectation)
|
|
284
|
+
is validated ≤ 5% against the exact ledger, and the whole machinery passes
|
|
285
|
+
an integral-fluctuation-theorem test (⟨e^(−Δs_tot)⟩ = 1) against an
|
|
286
|
+
exactly-enumerated 4×4 ensemble.
|
|
287
|
+
|
|
288
|
+
To instrument your own program:
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
from thermoc.erasure.trace import run_program_logged
|
|
292
|
+
import numpy as np
|
|
293
|
+
s, ledger = run_program_logged(prog, np.random.default_rng(0))
|
|
294
|
+
print(ledger.sigma_env, ledger.sigma_rb) # nats; per-op in ledger.per_op
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Trajectories are bit-identical to the vendored ThermoIR backend at equal
|
|
298
|
+
seeds — logging adds zero RNG draws.
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## 7. The rewrite engine (Phase B, part 1)
|
|
303
|
+
|
|
304
|
+
`rewrite(graph, budget, opt_in=None)` runs three passes in order — R1
|
|
305
|
+
creates the reversible regions that R2/R3 then exploit:
|
|
306
|
+
|
|
307
|
+
**R1 — substitutions**
|
|
308
|
+
- `relu → leaky_relu` fold-back. *Exact* when every consumer is another
|
|
309
|
+
relu-family op (relu∘leaky = relu); otherwise requires
|
|
310
|
+
`opt_in={"relu_leaky": {"alpha": 0.01}}` and the certificate is marked
|
|
311
|
+
`approx`.
|
|
312
|
+
- `quantize-later`: sinks a quantize past exactly-commuting relabelings
|
|
313
|
+
(transpose/reshape/flip/roll), growing the upstream REV region.
|
|
314
|
+
- `inplace → out-of-place`: overwrites stop erasing H(old|new), charged
|
|
315
|
+
against the memory budget by erased-bits-per-byte density.
|
|
316
|
+
|
|
317
|
+
**R2 — uncomputation.** Explicit `erase` nodes whose value was produced by
|
|
318
|
+
an invertible cone are replaced by the cone's **inverse chain** (generated
|
|
319
|
+
from the taxonomy's registered inverses, the way autodiff generates
|
|
320
|
+
gradients from a tape). Cost: ~2× that region's time + pinned anchor
|
|
321
|
+
memory. A copy of a still-live source (e.g. a graph input) is cancelled
|
|
322
|
+
reversibly (retained-operand convention). Selection is greedy by erased
|
|
323
|
+
bits per extra time, until your latency budget is spent.
|
|
324
|
+
|
|
325
|
+
**R3 — Bennett pebble scheduling.** For long reversible chains where
|
|
326
|
+
memory can't hold every checkpoint: the exact checkpoint/uncompute
|
|
327
|
+
recursion with branching factor k. Erasure drops **N·b → b** (only the
|
|
328
|
+
forced final erasure survives) at time × (2−1/k)ⁿ = N^ε and
|
|
329
|
+
n(k−1)+1 checkpoints. The scheduler generates and *simulates* the exact
|
|
330
|
+
move list (game invariant asserted); k is chosen under your budgets, and
|
|
331
|
+
infeasible budgets raise `BudgetInfeasible` carrying the exact
|
|
332
|
+
(k, time×, space, erasure) Pareto frontier so you can pick a point.
|
|
333
|
+
|
|
334
|
+
**Budgets.** `Budget(mem="2x", latency="1.5x")` — multipliers over the
|
|
335
|
+
baseline graph's peak liveness / total time, or absolute values
|
|
336
|
+
(bytes / time units). Rough guide: `mem="8x", latency="3x"` lets the full
|
|
337
|
+
pipeline strip a reversible-heavy graph to its forced erasures.
|
|
338
|
+
|
|
339
|
+
**Certificates.** Every application emits
|
|
340
|
+
`{rule, nodes, delta_bits, equivalence: tested|by-construction|approx}`.
|
|
341
|
+
Semantic equivalence is checked by executing before/after graphs on
|
|
342
|
+
identical inputs (bit-equal for integers).
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## 8. The adiabatic planner (Phase B, part 2)
|
|
347
|
+
|
|
348
|
+
```sh
|
|
349
|
+
thermoc erasure plan coupling_mlp --latency 10 --mem 8x --out plan.json
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
rewrite: 1.188e+05 -> 4160 erased bits (7 certificates)
|
|
354
|
+
plan: 30 stages on phal:pb64, T = 10.0 s
|
|
355
|
+
E_pred = 5.7743e-17 J (landauer residue 1.194e-17 J, sigma heat 0.000e+00 J)
|
|
356
|
+
simulated = 5.7743e-17 J (pred error 0.00%)
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
**The physics the planner implements:**
|
|
360
|
+
- Per-op adiabatic energy E(τ) = a/τ + c·τ (RC-ramp dissipation +
|
|
361
|
+
leakage). With leakage, "slower is always better" is false — each op
|
|
362
|
+
has an optimum τ* = √(a/c), and the planner will deliberately *not*
|
|
363
|
+
spend your whole latency budget past it.
|
|
364
|
+
- Optimal allocation (P6): τ_i\* ∝ √a_i, E\* = (Σ√a_i)²/T. The gain over
|
|
365
|
+
uniform allocation is exactly the heterogeneity of the a_i
|
|
366
|
+
(Cauchy–Schwarz), reported as `gain_vs_uniform`.
|
|
367
|
+
- Total prediction: driving dissipation + kT·ln2·(residual erased bits) +
|
|
368
|
+
kT·(Σσ for sampling stages).
|
|
369
|
+
- The same `thermoc.allocate_time` engine will drive the geodesic
|
|
370
|
+
(thermodynamic-length) scheduler: a stage of thermodynamic length L is
|
|
371
|
+
just a_i = kT·L_i², giving constant thermodynamic speed.
|
|
372
|
+
|
|
373
|
+
**Backends.** Builtins: `phal:pb64` (simulated adiabatic p-bit fabric,
|
|
374
|
+
projected constants) and `phal:cmos-ref` (refusal reference). Describe
|
|
375
|
+
real hardware in JSON and pass `BackendCapability.from_json(path)`:
|
|
376
|
+
|
|
377
|
+
```json
|
|
378
|
+
{"name": "my-adiabatic-chip", "adiabatic": true,
|
|
379
|
+
"a_per_unit": {"*": 2e-21}, "leak_per_unit": {"*": 1e-21},
|
|
380
|
+
"tau_min_s": 1e-8, "ramp_granularity_s": 1e-6}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**Refusal path (P4/N1).** Planning onto a non-adiabatic backend raises
|
|
384
|
+
`NonAdiabaticBackendError` with the full physics explanation and emits
|
|
385
|
+
**no plan and no savings claim**:
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
Backend 'phal:cmos-ref' declares adiabatic=false: it dissipates a fixed
|
|
389
|
+
switching energy (~1/2 C V^2) per operation irrespective of logical
|
|
390
|
+
reversibility ... the residual Landauer floor remains a physics reference
|
|
391
|
+
line only.
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Plan format (v1)** reserves the pb64 hardware-integration fields per
|
|
395
|
+
stage (FR7): `ramp_profile`, `erase_sites`, `telemetry.q_channel` — the
|
|
396
|
+
simulated backend fills telemetry; real hardware will.
|
|
397
|
+
|
|
398
|
+
**Simulated backend.** `SimulatedAdiabaticBackend(cap).run(plan,
|
|
399
|
+
jitter=0.05)` is an independent code path (own snapping, own capability
|
|
400
|
+
read); the M3 gate holds predicted-vs-simulated ≤ 2% across the benchmark
|
|
401
|
+
suite, and the reversible-heavy benchmarks achieve **≥ 5× dissipation
|
|
402
|
+
reduction at 2× latency** (rev_chain 6.5×, inplace_accum 20.7×,
|
|
403
|
+
fft_pipeline 11.2×).
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## 9. Extending the taxonomy
|
|
408
|
+
|
|
409
|
+
63+ op specs ship in `src/thermoc/erasure/taxonomy/seed_{rev,irrev,stoch}.py`.
|
|
410
|
+
Inspect them:
|
|
411
|
+
|
|
412
|
+
```sh
|
|
413
|
+
thermoc erasure taxonomy --list
|
|
414
|
+
thermoc erasure taxonomy --show softmax
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
To add an op, register an `OpSpec`:
|
|
418
|
+
|
|
419
|
+
```python
|
|
420
|
+
from thermoc.erasure.taxonomy import default_registry
|
|
421
|
+
from thermoc.erasure.taxonomy.registry import OpSpec
|
|
422
|
+
from thermoc.erasure.ir import OpClass
|
|
423
|
+
|
|
424
|
+
default_registry().register(OpSpec(
|
|
425
|
+
name="my_op", klass=OpClass.IRREV,
|
|
426
|
+
matches=("my_op", "aten.my_op*"), # exact names or globs
|
|
427
|
+
worstcase_bits=lambda node: node.numel_in() * 8.0,
|
|
428
|
+
unif_bits=lambda node: node.numel_in() * 4.0,
|
|
429
|
+
inverse=None, # or "my_op_inv" to enable R2
|
|
430
|
+
reference_impl=lambda x, **a: ..., # numpy semantics (equiv tests)
|
|
431
|
+
notes="what the formula means and why it is sound"))
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Rules of the game:
|
|
435
|
+
- `worstcase_bits` must upper-bound H(X|f(X)) for *every* distribution;
|
|
436
|
+
- `unif_bits` must not exceed the true uniform-ensemble value (floors must
|
|
437
|
+
never overstate); when unsure, use `n·b − log2|image|` or 0;
|
|
438
|
+
- unregistered kinds are safe by construction: UNKNOWN ⇒ full-input
|
|
439
|
+
erasure, logged and surfaced in the report;
|
|
440
|
+
- registering `inverse` + `reference_impl` is what makes an op eligible
|
|
441
|
+
for uncomputation and equivalence testing.
|
|
442
|
+
|
|
443
|
+
Fine-precision helpers you can reuse in formulas
|
|
444
|
+
(`estimators/worstcase.py`): `smooth_monotone_bits` (elasticity formula
|
|
445
|
+
for sigmoid-like saturation), `spectral_erasure_bits`
|
|
446
|
+
(Σ log₂(1/σᵢ) over singular values < 1), `linear_rank_bits`.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## 10. Physics reference card
|
|
451
|
+
|
|
452
|
+
| Law | Statement | Where implemented |
|
|
453
|
+
|---|---|---|
|
|
454
|
+
| Landauer (F1) | Q ≥ kT·ln2·ΔS, ensemble-average | `constants.kT_ln2` |
|
|
455
|
+
| Erased info (F2) | ΔS(p) = H(X\|f(X)); ΔS_wc ≥ ΔS(p) ∀p; wc=0 ⇔ reversible | `estimators/worstcase.py` |
|
|
456
|
+
| Finite precision (F3) | alphabet = dtype; δ(x) ≈ max(0, −log₂\|x f′/f\|) | `smooth_monotone_bits` |
|
|
457
|
+
| Spectral erasure (F4) | ΔS_num = Σ_{σ<1} log₂(1/σ) | `spectral_erasure_bits` |
|
|
458
|
+
| Entropy production (F5) | Δs_env = ln[P(s→s′)/P(s′→s)] = βQ, exact pathwise | `trace.SigmaLedger` |
|
|
459
|
+
| IFT gate (F5) | ⟨e^(−Δs_tot)⟩ = 1 (exact 4×4 ensemble) | `estimators/glauber.py` |
|
|
460
|
+
| Estimator stats (F6) | frozen quantile bins, Miller–Madow, bootstrap CI | `estimators/empirical.py` |
|
|
461
|
+
| Bennett (F7) | N·b → b at time N^ε, ε = ln(2−1/k)/ln k, space n(k−1)+1 | `pebble.py` |
|
|
462
|
+
| Uncompute (F8) | inverse-mode transformation over the taxonomy tape | `rewrite/uncompute.py` |
|
|
463
|
+
| Time allocation (F9) | τ\* ∝ √a; E(τ)=a/τ+cτ, τ_opt=√(a/c); geodesic a=kT·L² | `thermoc/allocate_time.py` |
|
|
464
|
+
| Certificates (F10) | Form A distribution-free; Form B ensemble-bound | `certify.py` |
|
|
465
|
+
| Plan total (F11) | Σa/τ + cτ + kT·ln2·bits + kT·σ; refuse non-adiabatic | `planner.py` |
|
|
466
|
+
| TUR hook (F12) | σ ≥ 2/ε² reserved (`precision_certificate: null`) | report/plan schemas |
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## 11. Honest limits (read before quoting numbers externally)
|
|
471
|
+
|
|
472
|
+
1. **No savings on today's GPUs.** Phase A is measurement/certification;
|
|
473
|
+
Phase B savings are demonstrated in simulation against declared E(τ)
|
|
474
|
+
curves. `phal:pb64` constants are projections.
|
|
475
|
+
2. **Empirical estimates are workload-conditional** and carry binning
|
|
476
|
+
bias (documented per-op in `notes`); they never enter certificates.
|
|
477
|
+
3. **Worstcase attributions can be loose** (that is their job — they are
|
|
478
|
+
upper bounds). Use the uniform column for floors, empirical for
|
|
479
|
+
profiling.
|
|
480
|
+
4. **Certificates bind to the graph, not the task.** A different
|
|
481
|
+
algorithm may have a lower floor. The wording enforces this.
|
|
482
|
+
5. **fx tracing limits:** dynamic control flow won't trace; shapes are
|
|
483
|
+
concretized at the example inputs and recorded in the report; the HF
|
|
484
|
+
GPT-2 tracer is incompatible with this torch/transformers pairing
|
|
485
|
+
(the demo uses a structure-identical hand-written block).
|
|
486
|
+
6. **UNKNOWN ops inflate floors by design** (soundness). Check the
|
|
487
|
+
report's unclassified panel and add specs.
|
|
488
|
+
|
|
489
|
+
## 12. Licensing & the PRO tier
|
|
490
|
+
|
|
491
|
+
thermoc-erasure is OSS-first and **fails open to the free tier**: with no
|
|
492
|
+
license (or an invalid/expired one) everything in §3–§5 keeps working
|
|
493
|
+
except signing. The enterprise surfaces are PRO-gated using the same
|
|
494
|
+
offline license mechanism as the rest of the EnergyIR suite:
|
|
495
|
+
|
|
496
|
+
- **Free:** `profile` (both modes), JSON/HTML reports, headroom,
|
|
497
|
+
taxonomy inspection, certificates *emitted but unsigned*.
|
|
498
|
+
- **PRO:** `rewrite()` (R1/R2/R3), `plan()` (adiabatic planner), and
|
|
499
|
+
signed certificates. Calling a PRO surface without a license raises
|
|
500
|
+
`PermissionError` (CLI exit code 4) with an upgrade hint.
|
|
501
|
+
|
|
502
|
+
**How to activate:** obtain the license token from the EnergyIR portal
|
|
503
|
+
(the same token that activates ThermoIR — one entitlement covers both),
|
|
504
|
+
then either
|
|
505
|
+
|
|
506
|
+
```sh
|
|
507
|
+
export ENERGYIR_LICENSE="<token>" # token literal
|
|
508
|
+
export ENERGYIR_LICENSE="@/path/to/license" # or a file reference
|
|
509
|
+
# or place the token at ~/.energyir/license
|
|
510
|
+
export ENERGYIR_LICENSE_PUBKEY="<publicKeyHex from the portal>" # if instructed
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Verification is offline ed25519 (`cryptography` package — installed with
|
|
514
|
+
`pip install "thermoc-erasure[pro]"`); there is no phone-home. If the
|
|
515
|
+
`energyir` suite is installed, verification delegates to
|
|
516
|
+
`energy.intelligence.licensing` so one license serves the whole suite.
|
|
517
|
+
|
|
518
|
+
## 13. Test map (where each guarantee is enforced)
|
|
519
|
+
|
|
520
|
+
```
|
|
521
|
+
test_constants.py kT ln2 pinned; T scaling
|
|
522
|
+
test_vendor.py vendored ThermoIR ≡ upstream snapshot
|
|
523
|
+
test_ir_frontends.py graph hash, fx/thermoir mapping, in-place detection
|
|
524
|
+
test_taxonomy.py ≥60 specs, normative seeds, UNKNOWN path
|
|
525
|
+
test_worstcase.py every F4 formula; emp ≤ unif ≤ wc; SVD demotion
|
|
526
|
+
test_empirical.py ReLU closed form; frozen bins; CI; determinism
|
|
527
|
+
test_glauber_sigma.py bit-exact mirror; telescoping <1e-9; σ̂ ≤5%; IFT=1
|
|
528
|
+
test_report_certify.py schema; headroom; Form A/B; HMAC tamper detection
|
|
529
|
+
test_acceptance_fr1.py ResNet-50 / GPT-2 / item-2: <5 s, all resolve, <1%
|
|
530
|
+
test_allocate_time.py P6 closed form; Cauchy–Schwarz; leakage √(a/c)
|
|
531
|
+
test_budget.py budgets + liveness baselines
|
|
532
|
+
test_substitutions.py R1a/b/c with certificates
|
|
533
|
+
test_uncompute.py R2 legality, inverse synthesis, equivalence
|
|
534
|
+
test_pebble.py N·b → b property test (hypothesis); Pareto
|
|
535
|
+
test_planner.py plan schema; FR7 fields; refusal wording; σ heat
|
|
536
|
+
test_m3_end_to_end.py ≤2% pred-vs-sim; ≥5× @ 2× latency
|
|
537
|
+
test_licensing.py offline verifier; fail-open OSS; PRO gates; unsigned certs
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
Run any single gate: `/opt/anaconda3/bin/python -m pytest tests/test_glauber_sigma.py -v`
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
*Generated as part of the M0–M3 build of PRD_thermoc_erasure.md
|
|
545
|
+
(physics-deep edition). The compiler's objective function is a physical
|
|
546
|
+
quantity — and the certificate says exactly when that quantity is a law.*
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: thermoc-erasure
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: ThermoC `erasure`: reversibility analysis, Landauer erased-bit accounting, Bennett scheduling, and adiabatic execution planning for computation graphs
|
|
5
|
+
Author-email: David Johnson <sportsmedicineuae@gmail.com>
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Project-URL: Repository, https://github.com/dmjdxb/thermoc-erasure
|
|
8
|
+
Project-URL: Documentation, https://github.com/dmjdxb/thermoc-erasure/blob/main/MANUAL.md
|
|
9
|
+
Keywords: thermodynamic-computing,landauer,reversible-computing,energy,compiler,p-bit,entropy-production
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: Other/Proprietary License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
17
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: numpy>=1.26
|
|
22
|
+
Provides-Extra: torch
|
|
23
|
+
Requires-Dist: torch<2.7,>=2.4; extra == "torch"
|
|
24
|
+
Requires-Dist: transformers<4.60,>=4.50; extra == "torch"
|
|
25
|
+
Provides-Extra: pro
|
|
26
|
+
Requires-Dist: cryptography>=42; extra == "pro"
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
29
|
+
Requires-Dist: hypothesis>=6.100; extra == "dev"
|
|
30
|
+
Requires-Dist: scipy>=1.12; extra == "dev"
|
|
31
|
+
Requires-Dist: cryptography>=42; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# thermoc-erasure
|
|
35
|
+
|
|
36
|
+
**ThermoC `erasure`** — reversibility analysis, Landauer erased-bit
|
|
37
|
+
accounting, erasure-minimizing graph rewrites (uncomputation + Bennett
|
|
38
|
+
pebble scheduling), and adiabatic execution planning for computation
|
|
39
|
+
graphs. Part of the EnergyIR compiler suite.
|
|
40
|
+
|
|
41
|
+
Every logically irreversible operation has a hard physical minimum energy
|
|
42
|
+
cost of k_B·T·ln2 per erased bit (Landauer, 1961). This compiler:
|
|
43
|
+
|
|
44
|
+
- **Phase A — measure & certify:** counts the erased bits of every op in a
|
|
45
|
+
PyTorch or ThermoIR graph, attributes a certified joule floor per op,
|
|
46
|
+
ranks irreversibility hotspots, and emits signed physics certificates
|
|
47
|
+
(distribution-free reversibility claims + ensemble-bound floor claims).
|
|
48
|
+
- **Phase B — restructure & plan:** removes erasures via reversible
|
|
49
|
+
substitutions, autodiff-style uncomputation, and exact Bennett pebble
|
|
50
|
+
scheduling under user memory/latency budgets, then emits adiabatic
|
|
51
|
+
execution plans with provably optimal per-op time allocation
|
|
52
|
+
(τ\* ∝ √a, Sivak–Crooks-compatible shared engine). Non-adiabatic
|
|
53
|
+
backends are refused, with the physics explanation — no false savings
|
|
54
|
+
claims.
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
pip install . # numpy-only core: worstcase mode, ThermoIR, planner
|
|
60
|
+
pip install ".[torch]" # + PyTorch fx frontend (ResNet/GPT-style models)
|
|
61
|
+
pip install ".[dev]" # + pytest, hypothesis, scipy (test suite)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quickstart
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
thermoc erasure profile resnet50 --mode empirical --out out/ # needs [torch]
|
|
68
|
+
thermoc erasure certify out/erasure_report.json
|
|
69
|
+
thermoc erasure plan coupling_mlp --latency 10 --mem 8x # numpy-only
|
|
70
|
+
thermoc erasure taxonomy --list
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from thermoc.erasure import profile, rewrite, plan, Budget
|
|
75
|
+
|
|
76
|
+
rep = profile(model, example_inputs, mode="empirical") # Landauer floor + hotspots
|
|
77
|
+
g2, rw = rewrite(rep.graph, Budget(mem="4x", latency="2x"))
|
|
78
|
+
xp = plan(g2, "phal:pb64", latency_budget_s=1.0) # adiabatic execution plan
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
See **[MANUAL.md](MANUAL.md)** for the complete end-to-end guide and the
|
|
82
|
+
physics reference card (every formula is mapped to the function that
|
|
83
|
+
implements it and the test that pins it).
|
|
84
|
+
|
|
85
|
+
## Guarantees enforced by the test suite (150 tests)
|
|
86
|
+
|
|
87
|
+
- Glauber entropy-production ledger is exact: telescoping identity to
|
|
88
|
+
machine precision, and the **integral fluctuation theorem**
|
|
89
|
+
⟨e^(−Δs_tot)⟩ = 1 verified against an exactly-enumerated 4×4 ensemble.
|
|
90
|
+
- Bennett pebbling drops chain erasure **N·b → b** at the exactly
|
|
91
|
+
predicted time/space cost (property-based).
|
|
92
|
+
- Planner prediction matches an independent simulated adiabatic backend
|
|
93
|
+
within 2%; reversible-heavy benchmarks reach ≥5× dissipation reduction
|
|
94
|
+
at 2× latency.
|
|
95
|
+
- Certificates are only ever marked valid in distribution-sound modes.
|
|
96
|
+
|
|
97
|
+
## Licensing & PRO tier
|
|
98
|
+
|
|
99
|
+
OSS-first, fail-open: **profiling, reports, taxonomy, and unsigned
|
|
100
|
+
certificates are free** and never require a license. The enterprise
|
|
101
|
+
surfaces are PRO-gated with the same offline ed25519 license the EnergyIR
|
|
102
|
+
suite uses (`ENERGYIR_LICENSE` env var or `~/.energyir/license`; no
|
|
103
|
+
network, no phone-home):
|
|
104
|
+
|
|
105
|
+
| Surface | Tier |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `profile` (worstcase + empirical), reports, HTML, headroom | free |
|
|
108
|
+
| certificates (emitted, unsigned) | free |
|
|
109
|
+
| **signed** certificates | PRO |
|
|
110
|
+
| `rewrite()` — R1 substitutions / R2 uncompute / R3 Bennett pebbling | PRO |
|
|
111
|
+
| `plan()` — adiabatic execution planning | PRO |
|
|
112
|
+
|
|
113
|
+
A PRO license minted by the EnergyIR portal for ThermoIR unlocks erasure
|
|
114
|
+
too — same token, same entitlement. When the `energyir` package is
|
|
115
|
+
installed alongside, license verification delegates to it
|
|
116
|
+
(`energy.intelligence.licensing`) so there is exactly one code path.
|
|
117
|
+
See `integration/ENERGYIR_INTEGRATION.md` for the (tiny) suite-side hookup.
|
|
118
|
+
|
|
119
|
+
## Provenance
|
|
120
|
+
|
|
121
|
+
This project is standalone: ThermoIR (the EnergyIR item-4 prototype) is
|
|
122
|
+
vendored as a frozen snapshot under `src/thermoc/_vendor/thermoir/`; no
|
|
123
|
+
production EnergyIR code paths are imported or modified.
|
|
124
|
+
|
|
125
|
+
License: proprietary — see [LICENSE](LICENSE).
|