Download src/hamiltonzero/evaluation/statistics.py from Twobombs/HamiltonZero: direct link, hf CLI and curl.
- Browser
- Download file 7.29 kB
-
https://huggingface.co/Twobombs/HamiltonZero/resolve/main/src/hamiltonzero/evaluation/statistics.py
- Command line
-
hf download hf://Twobombs/HamiltonZero/src/hamiltonzero/evaluation/statistics.py
-
curl -L -o statistics.py https://huggingface.co/Twobombs/HamiltonZero/resolve/main/src/hamiltonzero/evaluation/statistics.py
7.29 kB
| # Copyright (c) 2026 Simulacra Research Inc. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| from __future__ import annotations | |
| import math | |
| from dataclasses import dataclass | |
| import numpy as np | |
| P01_TWO_SIDED = 2.576 | |
| def standard_error_from_tailstd( | |
| tailstd: float, | |
| *, | |
| n_systems: int, | |
| batch_size: int, | |
| ) -> float: | |
| if tailstd is None or not math.isfinite(float(tailstd)): | |
| return float("nan") | |
| denominator = max(1, int(n_systems) * int(batch_size)) | |
| return float(tailstd) / math.sqrt(denominator) | |
| def welch_band_walkermean( | |
| tailstd_a: float, | |
| tailstd_b: float, | |
| *, | |
| n_systems_a: int, | |
| batch_size_a: int, | |
| n_systems_b: int, | |
| batch_size_b: int, | |
| z: float = P01_TWO_SIDED, | |
| ) -> float: | |
| se_a = standard_error_from_tailstd( | |
| tailstd_a, | |
| n_systems=n_systems_a, | |
| batch_size=batch_size_a, | |
| ) | |
| se_b = standard_error_from_tailstd( | |
| tailstd_b, | |
| n_systems=n_systems_b, | |
| batch_size=batch_size_b, | |
| ) | |
| if not (math.isfinite(se_a) and math.isfinite(se_b)): | |
| return float("nan") | |
| return float(z) * math.sqrt(se_a * se_a + se_b * se_b) | |
| def select_winner_per_physical( | |
| R, | |
| tailstd, | |
| beam_logp, | |
| batch_per_candidate, | |
| *, | |
| z: float = P01_TWO_SIDED, | |
| ucb_z: float = 2.0, | |
| ): | |
| R = np.asarray(R, dtype=float) | |
| tailstd = np.asarray(tailstd, dtype=float) | |
| beam_logp = np.asarray(beam_logp, dtype=float) | |
| P, K = R.shape | |
| Bp = int(batch_per_candidate) | |
| winner_idx = np.zeros(P, dtype=np.int64) | |
| tie_mask = np.zeros((P, K), dtype=bool) | |
| bands = np.full((P, K), np.nan, dtype=float) | |
| se = np.array( | |
| [ | |
| [ | |
| standard_error_from_tailstd( | |
| tailstd[p, k], | |
| n_systems=1, | |
| batch_size=Bp, | |
| ) | |
| for k in range(K) | |
| ] | |
| for p in range(P) | |
| ], | |
| dtype=float, | |
| ) | |
| reason: list[str] = [] | |
| for p in range(P): | |
| Rp, sp, lp = R[p], tailstd[p], beam_logp[p] | |
| finite = np.isfinite(Rp) | |
| if not finite.any(): | |
| w = int(np.argmax(lp)) | |
| winner_idx[p] = w | |
| tie_mask[p, w] = True | |
| reason.append("energy_unavailable") | |
| continue | |
| istar = int(np.argmin(np.where(finite, Rp, np.inf))) | |
| for k in range(K): | |
| band = welch_band_walkermean( | |
| sp[k], | |
| sp[istar], | |
| n_systems_a=1, | |
| batch_size_a=Bp, | |
| n_systems_b=1, | |
| batch_size_b=Bp, | |
| z=z, | |
| ) | |
| bands[p, k] = band | |
| if k == istar: | |
| tie_mask[p, k] = True | |
| elif finite[k] and math.isfinite(band) and abs(Rp[k] - Rp[istar]) < band: | |
| tie_mask[p, k] = True | |
| tie_idx = np.where(tie_mask[p])[0] | |
| se_tie = se[p, tie_idx] | |
| ucb = Rp[tie_idx] + ucb_z * np.where(np.isfinite(se_tie), se_tie, np.inf) | |
| w = int(tie_idx[int(np.argmin(ucb))]) if np.any(np.isfinite(ucb)) else istar | |
| winner_idx[p] = w | |
| reason.append("argmin_energy" if w == istar else "tie_broken_by_ucb") | |
| return winner_idx, tie_mask, reason, bands, se | |
| class ChannelMetrics: | |
| mean: float | |
| standard_error: float | |
| walker_tail_std: float | |
| local_energy_std: float | |
| lag1_autocorrelation: float | None | |
| def as_dict(self) -> dict[str, float | None]: | |
| return { | |
| "mean": self.mean, | |
| "standard_error": self.standard_error, | |
| "walker_tail_std": self.walker_tail_std, | |
| "local_energy_std": self.local_energy_std, | |
| "lag1_autocorrelation": self.lag1_autocorrelation, | |
| } | |
| class EnergyWindow: | |
| def __init__(self, steps: int, systems: int, batch_size: int): | |
| self.steps = int(steps) | |
| self.systems = int(systems) | |
| self.batch_size = int(batch_size) | |
| shape = (self.steps, self.systems, self.batch_size) | |
| self.values = { | |
| "total": np.empty(shape, dtype=np.float32), | |
| "exchange": np.empty(shape, dtype=np.float32), | |
| "field": np.empty(shape, dtype=np.float32), | |
| } | |
| self.sums = { | |
| "total": np.zeros((self.systems, self.batch_size), dtype=np.float32), | |
| "exchange": np.zeros((self.systems, self.batch_size), dtype=np.float32), | |
| "field": np.zeros((self.systems, self.batch_size), dtype=np.float32), | |
| } | |
| self.count = 0 | |
| def push(self, total, exchange, field) -> None: | |
| if self.count >= self.steps: | |
| raise IndexError("energy window is full") | |
| for name, value in ( | |
| ("total", total), | |
| ("exchange", exchange), | |
| ("field", field), | |
| ): | |
| array = np.asarray(value).real.astype(np.float32, copy=False) | |
| expected = (self.systems, self.batch_size) | |
| if array.shape != expected: | |
| raise ValueError( | |
| f"{name} energy must have shape {expected}, got {array.shape}" | |
| ) | |
| self.values[name][self.count] = array | |
| self.sums[name] += array | |
| self.count += 1 | |
| def tail_means(self, channel: str) -> np.ndarray: | |
| if self.count < 1: | |
| raise RuntimeError("energy window is empty") | |
| return (self.sums[channel] / float(self.count)).astype(np.float32, copy=False) | |
| def tail_mean(self, channel: str, system: int) -> float: | |
| return float(np.mean(self.tail_means(channel)[system])) | |
| def tail_std(self, channel: str, system: int) -> float: | |
| per_walker = np.asarray(self.tail_means(channel)[system]).ravel() | |
| if per_walker.size < 2: | |
| return float("nan") | |
| return float(np.std(per_walker, ddof=1)) | |
| def metrics(self, channel: str) -> ChannelMetrics: | |
| if self.systems != 1: | |
| raise ValueError("bare eval metrics require one physical system") | |
| samples = self.values[channel][: self.count, 0] | |
| per_walker = self.tail_means(channel)[0] | |
| mean = float(np.mean(per_walker)) | |
| tailstd = ( | |
| float(np.std(per_walker, ddof=1)) if per_walker.size >= 2 else float("nan") | |
| ) | |
| se = standard_error_from_tailstd( | |
| tailstd, | |
| n_systems=1, | |
| batch_size=self.batch_size, | |
| ) | |
| step_std = np.std(samples, axis=1) | |
| gap_sq = float(np.nanmean(step_std**2)) | |
| local_std = ( | |
| math.sqrt(gap_sq) | |
| if math.isfinite(gap_sq) and gap_sq >= 0.0 | |
| else float("nan") | |
| ) | |
| step_means = np.mean(samples, axis=1) | |
| finite = step_means[np.isfinite(step_means)] | |
| autocorrelation = None | |
| if len(finite) >= 20: | |
| centered = finite - np.mean(finite) | |
| denominator = float(np.sum(centered * centered)) | |
| if denominator > 0.0: | |
| autocorrelation = float( | |
| np.sum(centered[:-1] * centered[1:]) / denominator | |
| ) | |
| return ChannelMetrics( | |
| mean=mean, | |
| standard_error=se, | |
| walker_tail_std=tailstd, | |
| local_energy_std=local_std, | |
| lag1_autocorrelation=autocorrelation, | |
| ) | |