noise-emulate
Skill9 starsChanged 58 days agoApache-2.0View on GitHub
Emulate a neutral-atom Pulser sequence's time evolution under the target Rydberg device's live noise model, producing noiseless and noisy trajectory curves with a quantile envelope. Asks where to run — this machine, a GPU cluster, or Pasqal Cloud emulators. Use this to study how noise shapes a signal over time; use validate-emu to decide whether an experiment is worth submitting. Triggered by phrases like "run a noise emulation of this sequence", "emu-mps with noise", "noise envelope".
- Reads credentials
- Installs packages
In this repository11 other files it gives its agents.
- AGENTS.mdAGENTS.md
- application-to-ideaSkill
- apply-genci-tgcc-ceaSkill
- choose-access-methodSkill
- create-pasqal-cloud-accountSkill
- harvest-and-analyzeSkill
- idea-to-specSkill
- qpu-submitSkill
- spec-to-sequenceSkill
- submit-to-ceaSkill
- validate-emuSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 34
Not even under "just run the noise study".
- Distinctive: line 42
After about three failed attempts at the same obstacle — a builder that will not import, jobs that keep erroring, an out-of-memory at every …
- Very specific: line 186
If a suitable venv already exists, point the skill at it with export PULSER_VENV=<path>.
- Very specific: line 195
Write seq_builder.py with this signature (fully built, not parametric):
- Very specific: line 209
Use AnalogDevice for emulation.
- Very specific: line 374
If --cal-offsets was used and the calibration band is much wider than the stochastic band, flag that calibration precision matters more …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
noise-emulate
Emulate a Pulser sequence's time evolution with the target device's noise model (fetched live from the Pasqal Cloud — includes SPAM, amplitude, dephasing, detuning, Doppler, relaxation).
Choosing the device — all modes accept --device-name (default FRESNEL_CAN1):
- FRESNEL_CAN1 (default): no extra setup.
- SA1: pass
--device-name SA1and setPASQAL_REGION=sa(SA1 lives in thesacloud region and is invisible without it); your project must have SA1 access. Verify the exact device key withsdk.get_device_specs_dict().keys(). - Devices not on the cloud SDK (an on-premise QPU reached through a cluster,
for instance): no live noise model is available. Build against
AnalogDeviceconstraints instead, and submit throughsubmit-to-cea.
The user never needs to touch the Python scripts: this skill reads their sequence, writes the builder, runs everything, and shows the result.
Decisions that are not yours
Not even under "just run the noise study". Ask, recommend, and wait:
- where it runs — this machine, the cluster, or the cloud (Step 0), and for the cloud, which project pays
- the budget — N, the bond dimension χ, the number of trajectories, the number of time points (Step 0's budget question)
- whose noise model runs, if the spec carries one of its own (
--noise-source)
After about three failed attempts at the same obstacle — a builder that will not import, jobs that keep erroring, an out-of-memory at every χ — stop. Report what was tried, what failed and what is known, then offer a smaller system, a different mode, or abandoning the study. It is a diagnostic, not a gate: "we could not run this affordably" is an acceptable outcome, and a better one than a week of GPU time.
Where the outputs land
Beside the experiment they belong to, as they are produced:
experiments/<name>/results/noise/ .npz or .json data, logs, run figures
experiments/<name>/figures/ figures made for the report
experiments/<name>/analysis/ any script you write to read these files
experiments/<name>/NOTEBOOK.md one appended block per runEach script prints where it runs as its first line (RUNS ON: …) — say the same
to the user before starting, because "the envelope is ±0.03" means one thing
from 40 GPU trajectories and another from 5 cloud batches.
Support scripts
Paths like support/… below are relative to this skill's directory —
expand them to the skill's absolute location when running commands from your
project directory (keep outputs like --out-dir in your project, not the plugin).
support/
run_noise_emu.py ← MPS trajectory runner (local + cluster modes)
plot_noise_emu.py ← trajectory envelope figure
submit_slurm.sh ← turnkey SLURM launcher (one GPU job per trajectory)
run_noise_emu_cloud.py ← Pasqal Cloud EMU_MPS runner (cloud mode)
plot_noise_emu_cloud.py ← cloud results figure
requirements.txt ← Python dependencies (local/cluster modes)
spec_noise.py ← the source's own noise model, if it has one (shared)
batch_tags.py ← the labels every batch carries (shared, do not edit here)
pasqal_auth.py ← credentials, projects and credits (shared, do not edit here)Step 0 — Ask the user how to run
Always ask this first. Present the three options as a choice — use your harness's interactive question mechanism if it has one, plain text otherwise — with the recommended option marked:
Where should the emulation run?
- Locally — on this machine. Fine for small systems / quick tests; a CUDA GPU helps a lot. Trajectories run sequentially in one process.
- On a GPU cluster (recommended) — one GPU job per trajectory, all trajectories in parallel. By far the fastest for full 40-trajectory envelopes. Requires
sbatchon the current machine.- Via Pasqal Cloud — runs on the Pasqal Cloud EMU_MPS emulator fleet. No GPU or cluster needed, only Pasqal Cloud credentials. Best when you have no local compute; queue times apply and quality degrades for large registers (N ≳ 60–100).
Quick heuristics if the user has no preference: which sbatch succeeds → cluster;
otherwise a CUDA GPU present (nvidia-smi) → local; otherwise → cloud.
The budget question — N, χ and trajectories
Users arrive with a register size and expect the emulator to either handle it or
refuse. It does neither: it runs whatever it is given, and how much of the answer
is real depends on --max-chi. Explain the three knobs before agreeing to a run,
because they trade against each other:
| Knob | What it costs | What too little looks like |
N (atoms) | bond dimension needed grows with entanglement, not with N alone | nothing — the failure shows up as χ being too small |
--max-chi (χ) | memory and time, steeply | a smooth, plausible, wrong curve |
--n-traj | linear; each trajectory is an independent GPU job on SLURM | a noise band too jagged to read |
χ is an accuracy knob, not a size knob. Lowering it to fit 60 atoms on one GPU does not trade size for a coarser answer, it trades size for an answer whose error is invisible: MPS truncation does not warn, it just returns a state that cannot hold the entanglement the dynamics generated. An adiabatic sweep through a transition is the worst case, since that is where entanglement peaks.
Do not go hunting for the right χ. It is the most tempting way to burn a week here, and it does not converge on an answer: at a size where χ matters, no χ this GPU can hold is ever large enough, and each attempt costs more than the last. The decision has two branches and no search:
- Inside the calibrated envelope → run once, no convergence study. The
--max-chidefault of 128 was validated against χ=200 for S(π,π), local and two-point observables on systems up to 6×6, agreeing to ~0.05% (t_fall sweep, 2026-06). That class of observable, at that size, needs nothing further. - Outside it → change the register, not χ. Take a sub-system: a smaller register with the same geometry motif, the same R_b/a and the same protocol, small enough to sit inside the envelope, and check that it reproduces something approaching the expected signal. That validates the approach. The full-size number is then the QPU's job, not the emulator's.
One step up in χ, if the user asks for it, is fine. A sweep over χ is not: it answers a question the QPU is going to answer anyway, and a curve defended by "we tried several χ and picked the one that looked stable" is not defensible.
Which observable is asked for decides which branch you are in: ⟨n⟩, S(K) and correlators need far less χ than entanglement entropy, full bitstring distributions or higher moments — those leave the calibrated envelope immediately, whatever N is.
--n-traj 5 --max-chi 64 stays useful as a smoke test, whose curve nobody
should quote.
Then read the user's sequence carefully:
- Register layout? (N×N square, chain, custom)
- Channel? (EOM or standard rydberg_global)
- Parametric variable? (hx, T, R, …)
First-time setup (all modes)
Pasqal Cloud credentials (needed in every mode — the noise model is fetched live).
Each field is resolved independently: environment variables first, then the
system keyring (password only), then ~/.pasqal_credentials.json.
export PASQAL_USERNAME=... PASQAL_PASSWORD=... PASQAL_PROJECT_ID=...On a shared machine or in a cluster job script, prefer the environment variables —
they are the only option that keeps the password off disk. Alternatively run
any of the scripts below in a terminal with nothing configured: it offers a
one-time setup that puts the password in the OS keyring and only the username
and project ID in ~/.pasqal_credentials.json (chmod 600). Storing the
password in that file works too, and the scripts will warn you that it is
plaintext.
Python environment (local and cluster modes):
python3 -m venv ~/pulser-venv
source ~/pulser-venv/bin/activate
pip install -r support/requirements.txtCI pins pulser 1.9.0 and checks that sequences build and observables are correct
against it. The full local stack — emu-mps 2.7.5, torch 2.9.0, pasqal-cloud
0.22.0 — was last exercised end-to-end in 2026-06 against pulser 1.8.0, and has
not been re-run since; treat a failure on a newer pulser as a version problem
before assuming your sequence is wrong.
For GPU, install PyTorch for your CUDA version from pytorch.org first.
If a suitable venv already exists, point the skill at it with export PULSER_VENV=<path>.
Cloud mode only needs pulser, pulser-pasqal and pasqal-cloud (no emu-mps/torch).
Step 1 — Write the sequence builder
Local / cluster modes
Write seq_builder.py with this signature (fully built, not parametric):
def build_sequence(
N: int = 6,
hx: float = 4.0,
t: int = 4000, # pulse duration in ns
omega_offset: float = 1.0, # multiplicative Ω scale
delta_offset: float = 0.0, # additive δ in MHz
R_offset: float = 1.0, # multiplicative lattice spacing scale
**kwargs,
) -> pulser.Sequence: ...Use AnalogDevice for emulation; call with_automatic_layout(AnalogDevice) if
spacing < 10 µm. For EOM/quench sequences use the mean-field detuning at the
central site:
import numpy as np, pulser
from pulser import Sequence
from pulser.devices import AnalogDevice
from pulser.register.special_layouts import SquareLatticeLayout
def build_sequence(N=6, hx=4.0, t=4000,
omega_offset=1.0, delta_offset=0.0, R_offset=1.0, **kwargs):
omega = 2 * np.pi * 2.0
C6 = AnalogDevice.interaction_coeff
R = (hx * 2 * C6 / (4 * omega)) ** (1/6)
coords = SquareLatticeLayout(N, N, R * R_offset).coords
register = pulser.Register.from_coordinates(coords, prefix="q")
if R * R_offset < 10:
register = register.with_automatic_layout(AnalogDevice)
ci = (N//2)*N + N//2
dist = np.linalg.norm(coords - coords[ci], axis=-1); dist[ci] = np.inf
delta = C6 * np.sum(1.0 / dist**6) + 2 * np.pi * delta_offset
seq = Sequence(register, AnalogDevice)
seq.declare_channel("ising", "rydberg_global")
seq.enable_eom_mode("ising", amp_on=omega*omega_offset, detuning_on=delta)
seq.add_eom_pulse("ising", duration=t, phase=0.0)
seq.disable_eom_mode("ising")
return seqCloud mode
The cloud runner follows the spec-to-sequence contract instead: the file must
export build_sequence(device=None, **params) (observation time in ns as a
kwarg, default name t) and compute_observable(counts) -> float. If the
user brings a raw sequence, wrap it into this contract; default to mean Rydberg
density if no observable is specified, and say so.
Step 2 — Run
Mode 1 — Local
source "${PULSER_VENV:-$HOME/pulser-venv}/bin/activate"
python support/run_noise_emu.py \
--seq-file experiments/<name>/<name>_sequence.py \
--fn-name build_sequence \
--seq-kwargs '{"N": 6, "hx": 4.0, "t": 4000}' \
--n-traj 40 \
--max-chi 128 \
--n-times 75 \
--out-dir experiments/<name>/results/noise/ \
--cal-offsets '{"omega_offset": 0.03, "delta_offset": 0.2, "R_offset": 0.01}' \
[--spec experiments/<name>/<name>_spec.json --noise-source device|paper]Free and local: no batch is submitted and nothing is billed — the one cloud call
reads the device's noise model. Pass --spec if the source described its own
noise model: the script prints the difference against the device's field by
field, and --noise-source paper runs the source's instead. It never
substitutes it silently.
--cal-offsets adds a sensitivity band: ±3% on ω, ±0.2 MHz on δ, ±1% on R
(6 extra noiseless runs). If a QPU manifest from qpu-submit exists, ask the
user whether to add --qpu-manifest <path> — this runs the noisy trajectories
at the measured calibrated parameters for a fair comparison with QPU data.
Typical runtime on one A100: 3–8 min per noisy trajectory, so a full 40+1 run is
hours — run it with nohup/background for large systems, or use --n-traj 5
--max-chi 64 for quick tests. The last printed line is the output .npz path.
Mode 2 — cluster (recommended)
SEQFILE=experiments/<name>/<name>_sequence.py \
SEQKWARGS='{"N":6,"hx":4.0,"t":4000}' \
OUTDIR=experiments/<name>/results/noise \
NTRAJ=40 CHI=128 \
PARTITION=<your_partition> GRES=gpu:a100:1 ACCOUNT=<your_account> \
bash support/submit_slurm.shThe launcher (1) fetches the noise model once on the login node (compute nodes
are usually offline) → OUTDIR/noise_model.json, (2) submits a SLURM array
0..NTRAJ — one GPU per trajectory, id 0 = noiseless — and (3) submits a
dependent merge+plot job. Set PARTITION/GRES/ACCOUNT/TIME to your
site's values; on a shared cluster cap concurrency with ARRAY_MAX=10.
Watch with squeue -u $USER | grep nemu; figure appears at OUTDIR/noise_plot.png.
Wall time per trajectory (N=6, χ=128, dt=10): ~8–14 min on A100; the whole array
finishes in roughly one trajectory's wall time when GPUs are free. For larger N
or entanglement/full-distribution observables, raise CHI (200+) and re-validate
convergence at the longest evolution time.
Mode 3 — Pasqal Cloud
python support/pasqal_auth.py --whoami # free, read-only: account, projects, credits
python support/run_noise_emu_cloud.py \
--seq-file experiments/<name>/<name>_sequence.py \
--spec experiments/<name>/<name>_spec.json \
--seq-kwargs '{"N": 5, "hx": 6.0}' \
--t-max 4000 \
--n-times 15 \
--shots 500 \
--project-id <the project the user picked> \
--out-dir experiments/<name>/results/noise/ \
[--tag "envelope run 2"] [--noise-source device|paper]Emulator time is billed to a project, so the user picks it. --whoami is
free and read-only: it prints which account was found, where each credential came
from, and the QPU and EMU credits each of their projects has left — no password,
no token. Show it, ask which project pays, and pass --project-id. The script
refuses without it: the id in PASQAL_PROJECT_ID is the last one somebody
exported, not a decision.
--spec is optional but worth passing: it supplies the batch labels
(exp:<name>, stage:noise-emulate, backend:…, t:…, noise:…, plus your
--tags) and, if the source described its own noise model, it is what
--noise-source paper switches to. Without it the labels fall back to the
sequence file's name and only the device's model is available.
The cloud can't sample mid-evolution states, so this builds one sequence per
observation time (what the real QPU does) and submits noiseless + noisy
EMU_MPS batches per point. Batch budget = n_times × (2 + n_envelope); warn the
user beyond ~100 batches. --n-envelope K adds K independent noisy batches per
point for a client-side quantile band. Batch IDs are saved immediately; if the
session dies mid-poll, re-run with --resume and the same --out-dir; a
re-run without --resume into a directory that already records batches is
refused.
Step 3 — Plot
NOISE=experiments/<name>/results/noise
# local / cluster (.npz):
python support/plot_noise_emu.py \
--result $NOISE/FCAN1_*.npz --out $NOISE/noise_plot.png --coverage 0.75
# cloud (.json):
python support/plot_noise_emu_cloud.py \
--results $NOISE/noise_emu_cloud.json \
--out $NOISE/noise_emu_cloud.pngSave figures as .png only, next to the data they came from. A figure you make
for the report — annotated, or comparing two runs — goes in
experiments/<name>/figures/, never in the working directory's root.
Step 4 — Report to the user
- The noise model values printed during the run (copy the table) — these come as-shipped from the live device spec.
- Key observations: how wide is the noise band, does the noiseless curve lie within it, signal retention at the peak.
- If
--cal-offsetswas used and the calibration band is much wider than the stochastic band, flag that calibration precision matters more than noise. - Paths to the saved data file and figure, and where the numbers you are quoting came from.
- Where it ran and what that limits — 40 GPU trajectories and 5 cloud batches do not license the same sentence about the envelope.
- Which χ produced it, and whether the register was inside the calibrated envelope. If it was not, say so in the same sentence as the result — an unqualified curve from a possibly truncated run is the one output of this skill that can mislead silently.
- Which noise model produced it, and if the spec carried another one, that it exists and how it differs.
- Next step. This skill diagnoses; it does not authorise anything. If the
user came from a
validate-emuNO-GO, the next step is the protocol change the envelope suggests, then re-runningvalidate-emu— its cloud verdict is still the only thing that gates a QPU submission. - The appended
NOTEBOOK.mdblock.
Troubleshooting
| Issue | Fix |
Pasqal Cloud credentials incomplete | See First-time setup above; the message names the missing fields |
<device> not in available devices | Cloud SDK connection failed or device hidden from the project (for SA1: is PASQAL_REGION=sa set?); retry / check project |
build_sequence not found | Pass --fn-name <name> |
| Builder returned a parametric sequence | Call .build(...) inside the builder |
| GPU OOM (local/cluster) | Reduce N, not χ. Lowering --max-chi to make it fit buys a curve whose truncation error is invisible, and no χ that fits will settle it — emulate a sub-system that stays inside the calibrated envelope instead |
emu_mps not found | Wrong virtualenv; install from requirements.txt |
partial_*.npz missing after SLURM job | Check the .err log: time limit, OOM, or missing venv |
| Cloud batches stuck PENDING | Queue congestion — normal; re-poll later with --resume |
| Cloud batch ERROR on large N | Cloud EMU_MPS degrades for N ≳ 60–100; reduce N or use the cluster or local mode |
Output files
experiments/<name>/results/noise/
# local / cluster
FCAN1_<kwargs>_ntraj40_chi128_<timestamp>.npz ← raw data (self-documenting:
noise_plot.png embeds noise model + kwargs)
# cloud
batch_ids.json ← submitted batches, their labels (for --resume)
noise_emu_cloud.json ← per-time records
noise_emu_cloud.pngThen append the block to experiments/<name>/NOTEBOOK.md: where it ran, the
budget actually used (N, χ, trajectories, time points), which noise model, the
files written, and what the envelope says. A .npz whose provenance lives only
in a chat log is a file nobody will trust in a month.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

