stringforge quickstart#

This notebook walks through the three main entry points of stringforge:

  1. Catalogue query – inspect the lightweight TDF catalogue (no shard I/O, just the index).

  2. Model loading – pull one model’s geometry shard in mirror convention and obtain a FluxVacuaFinder ready for use.

  3. 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 jax
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.

# 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-side Vulcan write 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) with db.load_model(...) above.