Flux-bounding case studies#
What’s in this notebook? This advanced notebook validates the
bounded_fluxesconventions against two literature datasets: the mirror-octic vacua of Plauschinn-Schlechter, arXiv:2310.06040, and Dataset B from arXiv:2501.03984. It is the place to check paper-data conventions and small reproducibility slices, not the place to learn the bounding algorithm from scratch.Runtime note: local data files are included in the repository, so the default checks can run offline. The default path loads both files and verifies small subsets; exhaustive reproductions remain opt-in because full scans can take a long time and may require substantial memory.
Outline#
Setup#
import csv
import gzip
import pickle
import warnings
from pathlib import Path
import numpy as np
from scipy.optimize import root
import jax
import jax.numpy as jnp
jax.config.update("jax_enable_x64", True)
import matplotlib.pyplot as plt
import seaborn as sn
cmap = sn.color_palette("viridis", as_cmap=True)
import jaxvacua as jvc
from jaxvacua.flux_bounding import bounded_fluxes
warnings.filterwarnings("ignore")
RUN_FULL_OCTIC_REPRODUCTION = False
RUN_FULL_DATASET_B_SCAN = False
RUN_DATASET_B_TEST_SCAN = False
DATA_CANDIDATES = [
Path("."),
Path("../02_vacuum_finding"),
Path("02_vacuum_finding"),
Path("documentation/source/notebooks/02_vacuum_finding"),
]
def first_existing(filename):
for base in DATA_CANDIDATES:
candidate = base / filename
if candidate.exists():
return candidate
raise FileNotFoundError(f"Could not locate {filename!r}; checked {DATA_CANDIDATES}")
OCTIC_PS_CSV = first_existing("data_mirror_octic.csv")
DATASET_B_PATH = first_existing("dataset_B.p")
print("OCTIC_PS_CSV =", OCTIC_PS_CSV)
print("DATASET_B_PATH =", DATASET_B_PATH)
print("RUN_FULL_OCTIC_REPRODUCTION =", RUN_FULL_OCTIC_REPRODUCTION)
print("RUN_FULL_DATASET_B_SCAN =", RUN_FULL_DATASET_B_SCAN)
Data files#
The case-study files are stored next to the vacuum-finding notebooks:
data_mirror_octic.csv— ancillary mirror-octic vacuum data from Plauschinn-Schlechter, arXiv:2310.06040.dataset_B.p— Dataset B from arXiv:2501.03984, encoded as[z1_re, z1_im, z2_re, z2_im, tau_re, tau_im, f(6), h(6)]rows.
The loader above accepts notebook-relative execution from 05_advanced/ and repo-root execution from the source tree. If these files are moved later, update the DATA_CANDIDATES list rather than hard-coding paths inside individual cells.
Mirror-octic case study#
The mirror-octic dataset uses a period/basis convention different from JAXVacua. We first define the integer map from the Plauschinn-Schlechter (H, F) columns to the JAXVacua [f | h] vector, then Newton-refine a laptop-safe subset in the LCS region. This checks the convention map and local refinement behaviour. Set RUN_FULL_OCTIC_REPRODUCTION = True only when you want to check all available rows.
m_oct = jvc.FluxVacuaFinder(h12=1, model_ID=1)
sampler_oct = jvc.data_sampler(
m_oct,
moduli_bounds=(1.5, 7.0),
axion_bounds=(-0.5, 0.5),
dilaton_bounds=(1.0, 10.0),
use_jax=True,
seed=0,
)
bf_oct = bounded_fluxes(m_oct, sampler=sampler_oct, Nmax=10)
_P = np.array([[0, 0, 1, 0], [0, 0, 0, 1], [1, 0, 0, 0], [0, 1, 0, 0]])
_B = np.array([[-1, 0, 0, 0], [0, -1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]])
_PB = _B @ _P
def paper_to_jaxvacua_octic(H_paper, F_paper):
"""Map a Plauschinn-Schlechter (H, F) pair to JAXVacua [f | h]."""
return np.concatenate([_PB @ np.asarray(F_paper), _PB @ np.asarray(H_paper)]).astype(float)
def load_octic_rows(path):
rows = []
with open(path) as f:
for r in csv.reader(f):
try:
c, s = float(r[14]), float(r[15])
t = float(r[9]) + 1j * float(r[10])
except (ValueError, IndexError):
continue
rows.append(dict(
flux=paper_to_jaxvacua_octic([int(r[i]) for i in range(4)], [int(r[i]) for i in range(4, 8)]),
t=t,
patch=r[11],
tau=c + 1j * s,
))
return rows
octic_rows = load_octic_rows(OCTIC_PS_CSV)
print(f"Loaded {len(octic_rows)} mirror-octic rows from {OCTIC_PS_CSV}.")
octic_lcs = [r for r in octic_rows if r["t"].imag >= 1.8 and r.get("patch", "0") in ("0", "Infinity")]
if not RUN_FULL_OCTIC_REPRODUCTION:
octic_lcs = octic_lcs[:50]
mod_oct = jnp.array([[r["t"]] for r in octic_lcs], dtype=complex)
tau_oct = jnp.array([r["tau"] for r in octic_lcs], dtype=complex)
flux_oct = jnp.array([r["flux"] for r in octic_lcs], dtype=float)
mod_ref, tau_ref, res_oct = bf_oct.newton_refine_batch(
mod_oct, tau_oct, flux_oct,
step_size=1.0, tol=1e-12, max_iters=50,
)
res_oct = np.asarray(res_oct)
print(f"Checked {len(res_oct)} mirror-octic vacua.")
print(f"Converged below 1e-8: {int((res_oct < 1e-8).sum())}/{len(res_oct)}")
print(f"Median residual: {np.median(res_oct):.2e}")
fig, ax = plt.subplots(figsize=(5.5, 3.2), dpi=130)
ax.hist(np.log10(res_oct + 1e-16), bins=30, color="steelblue", edgecolor="white")
ax.axvline(-8, color="red", linestyle="--", label="1e-8")
ax.set_xlabel(r"$\log_{10}(\sum |D_I W|)$")
ax.set_ylabel("count")
ax.set_title("Mirror-octic Newton residuals")
ax.legend()
plt.tight_layout()
plt.show()
Dataset B case study#
Dataset B is two-modulus and larger than the mirror-octic check. The default path loads the local pickle, checks summary statistics, and Newton-refines a small subset of stored vacua. This confirms that the checked-in data are readable and compatible with the current model conventions. The full end-to-end bounded scan is available below, but disabled by default.
def load_pickle(path):
try:
with gzip.open(path, "rb") as f:
return pickle.load(f)
except OSError:
with open(path, "rb") as f:
return pickle.load(f)
def decode_dataset_B(arr):
arr = np.asarray(arr, dtype=float)
z1 = arr[:, 0] + 1j * arr[:, 1]
z2 = arr[:, 2] + 1j * arr[:, 3]
tau = arr[:, 4] + 1j * arr[:, 5]
flux = arr[:, 6:18]
return z1, z2, tau, flux[:, :6], flux[:, 6:12], flux
datsB = load_pickle(DATASET_B_PATH)
z1_B, z2_B, tau_B, f_B, h_B, flux_B = decode_dataset_B(datsB)
sigma_np = np.array([
[0,0,0,1,0,0], [0,0,0,0,1,0], [0,0,0,0,0,1],
[-1,0,0,0,0,0], [0,-1,0,0,0,0], [0,0,-1,0,0,0],
], float)
Nflux_B = np.einsum('ki,ij,kj->k', f_B, sigma_np, h_B)
flux_B_set = {np.round(v).astype(int).tobytes() for v in flux_B}
print(f"Loaded {len(flux_B)} Dataset B rows from {DATASET_B_PATH}.")
print(f"N_flux range: {int(Nflux_B.min())} - {int(Nflux_B.max())}")
print(f"Im(tau) range: {np.imag(tau_B).min():.3f} - {np.imag(tau_B).max():.3f}")
print(f"Im(z1) range: {np.imag(z1_B).min():.3f} - {np.imag(z1_B).max():.3f}")
print(f"Im(z2) range: {np.imag(z2_B).min():.3f} - {np.imag(z2_B).max():.3f}")
model_B = jvc.FluxVacuaFinder(h12=2, model_ID=1)
# Paper calibration for Dataset B.
model_B.lcs_tree.a_matrix = jnp.array([[4.5, 1.5], [1.5, 0.]])
sampler_B = jvc.data_sampler(
model_B,
moduli_bounds=(2., 5.),
dilaton_bounds=(np.sqrt(3.) / 2., 10.),
axion_bounds=(-0.5, 0.5),
seed=42,
)
bf_B = bounded_fluxes(model_B, sampler=sampler_B, Nmax=10)
n_verify = min(100, len(flux_B))
moduli_0 = jnp.array(np.column_stack([z1_B[:n_verify], z2_B[:n_verify]]), dtype=complex)
tau_0 = jnp.array(tau_B[:n_verify], dtype=complex)
flux_0 = jnp.array(flux_B[:n_verify], dtype=float)
moduli_ref_B, tau_ref_B, res_B = bf_B.newton_refine_batch(
moduli_0, tau_0, flux_0,
step_size=1.0, tol=1e-12, max_iters=10,
)
res_B = np.asarray(res_B)
print(f"Verified {n_verify} stored Dataset B solutions.")
print(f"Converged below 1e-10: {int((res_B < 1e-10).sum())}/{n_verify}")
print(f"Max residual: {res_B.max():.2e}")
fig, axes = plt.subplots(1, 3, figsize=(12, 3.2), dpi=130)
axes[0].hist(np.log10(res_B + 1e-16), bins=30, color="steelblue", edgecolor="white")
axes[0].axvline(-10, color="red", linestyle="--", label="1e-10")
axes[0].set_xlabel(r"$\log_{10}(\sum |D_I W|)$")
axes[0].set_title("Stored-solution residuals")
axes[0].legend()
axes[1].hist(np.imag(tau_B), bins=50, color="coral", edgecolor="white")
axes[1].set_yscale("log")
axes[1].set_xlabel(r"$s=\mathrm{Im}(\tau)$")
axes[1].set_title("Dataset B dilaton")
axes[2].hist(Nflux_B, bins=np.arange(0.5, 11.5, 1), color="mediumseagreen", edgecolor="white")
axes[2].set_yscale("log")
axes[2].set_xlabel(r"$N_{\rm flux}$")
axes[2].set_title("Dataset B tadpole")
plt.tight_layout()
plt.show()
Optional full scans#
The following cells document the expensive paths. They are disabled by default because they can take hours on CPU and may require careful batch-size tuning. For local experiments, reduce n_sample, n_isd_per_h, max_h_candidates, chunk_size, and the number of moduli_regions first. Treat successful subset validation and successful full reproduction as different levels of evidence.
if RUN_DATASET_B_TEST_SCAN:
bf_test = bounded_fluxes(model_B, sampler=sampler_B, Nmax=4)
bf_test.compute_eigenvalue_bounds(n_sample=500)
enum_results_test = bf_test.enumerate_fluxes(
n_sample=500,
n_isd_per_h=30,
max_h_candidates=5_000_000,
refine=True,
return_moduli=True,
newton_tol=1e-10,
newton_max_iters=10,
confirm_streaming=False,
moduli_regions=[(2., 3.)],
use_linearised_shifts=True,
chunk_size=20_000,
n_isd_iters=8,
n_moduli_batches=30,
verbose=True,
)
print(f"Found {len(enum_results_test)} converged SUSY vacua in the Dataset B test region.")
else:
print("RUN_DATASET_B_TEST_SCAN = False — skipping bounded Dataset B test scan.")
if RUN_FULL_DATASET_B_SCAN:
full_results = bf_B.enumerate_fluxes(
n_sample=1000,
n_isd_per_h=10,
max_h_candidates=10_000_000,
refine=True,
return_moduli=True,
newton_tol=1e-10,
newton_max_iters=100,
confirm_streaming=False,
moduli_regions=[(2., 3.), (3., 4.), (4., 5.)],
use_linearised_shifts=True,
n_isd_iters=5,
verbose=True,
)
print(f"Full Dataset B scan: found {len(full_results)} vacua (reference size: {len(flux_B)} rows).")
else:
print("RUN_FULL_DATASET_B_SCAN = False — skipping full Dataset B scan.")
Take-aways#
The local
data_mirror_octic.csvanddataset_B.pfiles let the case-study checks run without network access.The default notebook path verifies conventions and refines small subsets; full enumeration remains opt-in.
NB08 teaches the bounded-search method, while NB17 validates it against published datasets.
If a full scan is slow, reduce batch sizes and samples before increasing
Nmaxor moduli-region coverage.
Further reading#
Plauschinn-Schlechter, Flux vacua of the mirror octic, arXiv:2310.06040
Deep observations of the Type IIB flux landscape, arXiv:2501.03984