Protocols#
A protocol ties several experiments together to achieve a complete goal that no single one of them can — calibrating a qubit, rather than just finding its frequency. Each experiment is wrapped as an operation: a self-contained unit that measures, analyses, and defines for itself what counts as success, usually to nail down some number, or provides next steps with an attempt to solve its failures. The protocol runs its operations in sequence (more complex protocols can have more complex execution flows), lets each one retry itself with adjusted settings if needed, and records the whole run as a self-contained HTML report. The result is the calibrated system, with a report that shows how you got there.
A protocol is built out of three concepts, one per sub-page:
Parameters — the named handles operations read from and write to
Operations — a single experiment, including its checks and corrections
Protocols — composing operations into a runnable protocol
How protocols are organized#
Every protocol is a tree of branches and operations.
Protocol
└── Branch a named sequence of items
├── Operation a single measurement step
│ ├── Parameters named handles for inputs and outputs
│ ├── Checks pure assessments after analysis
│ └── Corrections strategies applied between retries
└── Condition (optional) routes execution to one of two branches
The simplest shape — and the one most protocols use — is a single root branch with a flat list of operations. See Protocols for super-operations, conditions, and the assembled report.
The lifecycle of an operation#
Every operation runs the same five steps in order, on every attempt:
◀── platform-specific ──▶ ◀───── platform-agnostic ──────▶
measure ──▶ load_data ──▶ analyze ──▶ evaluate ──▶ correct
│ │ │ │ │
write pull and compute check parameter
hardware normalize (fitting, results writes;
/ save shape and statistics) (pure apply any
raw data names assessment) correction
across
platforms
measure— performs the measurement (or generates fake data onDUMMY) and saves the raw data to disk.load_data— reads the raw data back into memory and normalizes its shape and field names so the rest of the lifecycle is platform-agnostic.analyze— runs fits and statistics over the loaded data and attaches the results to the operation.evaluate— returns named check results and an overall status; pure assessment, no side effects.correct— the only place parameters get written: fitted outputs on success, a correction strategy on retry.
See Operations for how each step is implemented and customized.
Run a protocol in 10 lines#
from labcore.protocols import select_platform, ProtocolBase, BranchBase
from labcore.testing.protocol_dummy.gaussian_with_correction import (
GaussianWithCorrectionOperation,
)
select_platform("DUMMY")
class HelloProtocol(ProtocolBase):
def __init__(self):
super().__init__()
self.root_branch = BranchBase("hello")
self.root_branch.extend([GaussianWithCorrectionOperation()])
HelloProtocol().execute()
This protocol has one operation. The operation runs a noisy Gaussian fit and assesses its own signal-to-noise ratio. The first attempt fails, a correction fires that lowers the simulated noise level, and the operation retries. After two corrections the SNR check passes, the fit succeeds, and the protocol writes an HTML report to the current directory.
A few things to notice:
select_platformis required before any protocol can be instantiated. It tells parameters and operations which hardware backend to dispatch to."DUMMY"is the in-memory backend used for testing.The protocol is just a class with a
root_branch. The branch holds a flat list of operations.The correction strategy lives inside the operation. The protocol does not know or care that this particular operation retries itself.
Note
At the moment, protocols only support the DUMMY, QICK, and OPX
platforms. Adding a new platform is a small change — if you need one,
please open an issue on GitHub.
Where to read next#
Read in order: Parameters → Operations → Protocols. Each page builds on the previous one.