igneum/sim/horizon/new-pow/chip_rows.py
igneum-labs a664af6fc9 Horizon: lane 8 (new-proof-of-work) lands: three schemes, two prototypes measured on rented 4090s
docs/analysis/horizon/new-pow.md sections 0 to 9: scheme A (mining is proving) never, on bytes,
the verifier and sampleability; scheme B (the tensor-shaped integer shadow) prototyped as
proto-newpow/mma-shadow and measured, never as class content on the energy reading, with the R8
two-output correction; scheme C (proof of stored state, sd1: the daily dataset derived from the
execution state) prototyped as proto-newpow/state-dataset, measured on the GPU and the box's
CPU, and put forward as the class v5 candidate with its spec items and the Devnet 2 gate. The
lane's standing rule: a shadow lever only works through joules the honest card is forced to
spend, so shadow work goes where the GPU is least efficient per op. Chip rows in
sim/horizon/new-pow/chip_rows.py by the chip-model-v3 method. Rented box addresses replaced by
placeholders in the READMEs and the run script.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 20:18:39 +00:00

36 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""Chip rows for the Horizon new-pow lane (scheme B, the tensor-shaped shadow), by the chip-model-v3 section 5 method.
Usage:
python3 chip_rows.py --card-uj <microjoules per hash of the honest card at R=0> \
--card-uj-r <microjoules per hash at the measured R> --r <R> \
[--mem-uj 0.466] [--k 1.0 0.5 0.3]
Model (docs/analysis/chip-model-v3.md 5.4 and docs/analysis/latency-shadow-2026-10-06.md 6):
chip energy per hash = memory system energy (f = 1 chip: 0.466 uJ GDDR7, 0.321 uJ one HBM3 stack)
+ block energy on the chip = (card block energy) x k
card block energy = card_uj_r - card_uj (the measured marginal of the block on the honest card)
gain per joule = card_uj_r / chip_uj
Every chip figure is arithmetic on cited figures and approximate; the card figures are measured and named in the lane file.
"""
import argparse
p = argparse.ArgumentParser()
p.add_argument("--card-uj", type=float, required=True, help="honest card microjoules per hash at R = 0 (measured)")
p.add_argument("--card-uj-r", type=float, required=True, help="honest card microjoules per hash at the measured R")
p.add_argument("--r", type=int, required=True, help="mm8 steps per iteration (8 R per hash)")
p.add_argument("--mem-uj", type=float, nargs="+", default=[0.466, 0.321], help="f = 1 chip memory energy per hash, uJ (GDDR7, HBM3 one stack)")
p.add_argument("--k", type=float, nargs="+", default=[1.0, 0.5, 0.3], help="chip block energy per op over the card's")
a = p.parse_args()
block = a.card_uj_r - a.card_uj
macs = 8 * a.r * 1024
print(f"R = {a.r}: {8*a.r} mm8 per hash, {macs} multiply-adds per hash")
print(f"card: {a.card_uj:.3f} uJ at R = 0, {a.card_uj_r:.3f} uJ at R = {a.r}; block {block:.3f} uJ = {block*1e6/macs if macs else 0:.3f} pJ per multiply-add")
print("| memory | k | chip uJ per hash | gain per joule (card over chip) | gain at R = 0 for comparison |")
print("|---|---|---|---|---|")
names = ["GDDR7 (16 devices)", "HBM3 (one stack)", "HBM3 (eight stacks)"]
for i, m in enumerate(a.mem_uj):
for k in a.k:
chip = m + block * k
print(f"| {names[i] if i < len(names) else m} | {k} | {chip:.3f} | {a.card_uj_r/chip:.2f}x | {a.card_uj/m:.2f}x |")