stringforge quickstart#
This notebook walks through the three main entry points of
stringforge:
Catalogue query – inspect the lightweight TDF catalogue (no shard I/O, just the index).
Model loading – pull one model’s geometry shard in mirror convention and obtain a
FluxVacuaFinderready for use.Vault round-trip – write a tiny vacuum record to the local vault and read it back.
All three are lazy: only the catalogue is downloaded up-front (~10 MB) and only the shards a query touches are pulled afterwards.
Setup#
import warnings; warnings.filterwarnings("ignore")
import os
import jax
import jax.numpy as jnp
import pandas as pd
jax.config.update("jax_enable_x64", True)
# Point the cache at a sandbox directory for this notebook (the
# default is `${cwd}/.stringforge_cache`). Everything downloaded
# here stays local until you decide otherwise.
import stringforge
stringforge.set_data_dir("./.sf_demo_cache")
1. Catalogue query (no shard I/O)#
The TDF catalogue indexes every Trilayer Double-Favourable toric model
in the cy-database. A query(...) call is a pure-pandas filter on the
in-memory catalogue – no per-shard downloads happen yet.
from stringforge import LCSDatabase
# mirror-convention wrapper: h12 is *jaxvacua* h12 (= catalogue h11)
db = LCSDatabase(dataset="tdf")
df = db.query(h12=2, has_conifolds=True)
print(f"matching rows: {len(df)}")
print()
df[["ks_id", "triang_id", "h11", "h12", "n_conifolds"]].head()
2. Lazy model loading#
Calling db.load_model(...) triggers download (and cache) of just
the shards that one model needs, and returns a JAXVacua
FluxVacuaFinder that you can use immediately.
row = df.iloc[0]
# This is the one call that touches the network the first time round.
# Subsequent calls for the same model are served from the local cache.
model = db.load_model(
ks_id = int(row["ks_id"]),
triang_id = int(row["triang_id"]),
h11 = int(row["h11"]),
h12 = int(row["h12"]),
include_gv = False, # speed
include_conifolds = False,
maximum_degree = 2,
)
print(type(model).__name__, "ready; h12 =", model.h12)
3. Vault round-trip#
The vault persists vacuum solutions in a parquet layout that other ecosystem tools can read. Here we manufacture a one-row toy vacuum record, designate it under a label, query it back, and (for a clean demo) retract it.
import numpy as np
# A toy vacuum record -- in real use this comes out of a vacuum search.
toy_vacua = pd.DataFrame({
"flux" : [[0, 0, -2, 3, 0, 1, 0, 0, 0, 0, 0, 0]],
"moduli_re": [[0.0, 0.0]],
"moduli_im": [[2.5, 3.0]],
"tau_re" : [0.0],
"tau_im" : [4.0],
"is_susy" : [True],
})
# Designate -- write to the local vault under a label
db.designate_vacua(
toy_vacua,
label = "stringjax_demo",
committed_by = "quickstart_notebook",
h11 = int(row["h11"]),
h12 = int(row["h12"]),
ks_id = int(row["ks_id"]),
triang_id = int(row["triang_id"]),
)
# Query the vault catalogue
catalog = db.query_designated(label="stringjax_demo")
print(catalog[["label", "n_vacua", "created"]])
# Clean up the demo entry from the local vault
db.retract_designated(label="stringjax_demo")
What next#
See the stringforge documentation for the full database stack (
TDFDatabase,CICYDatabase,KKLTDatabase), the cluster-sideVulcanwrite tier, and the vault validation tools.Try the jaxvacua quickstart to see how a loaded model is used to find vacua.
Combine the two: use a stringforge model in the jaxvacua quickstart by replacing
FluxVacuaFinder(h12=2, model_ID=1)withdb.load_model(...)above.