qiskit-zksf
Qiskit provider for ZKSF (Zero Kelvin Simulation Foundry). Point circuits you have already written at classical simulators, GPU accelerators, or real quantum processors, and get a documented accuracy statement back with every approximate result.
pip install qiskit-zksf
from qiskit import QuantumCircuit
from qiskit_zksf import ZKSFProvider
qc = QuantumCircuit(40, 40)
qc.h(0)
for i in range(39):
qc.cx(i, i + 1)
qc.measure(range(40), range(40))
backend = ZKSFProvider(token="...").backend("zksf_auto")
job = backend.run(qc, shots=1000)
print(job.result().get_counts())
print(job.error_info()) # how far that answer may be from the truth
The token comes from the console at app.zksf.org, or from the
ZKSF_TOKEN environment variable.
V2 primitives
Current Qiskit code builds a primitive rather than calling backend.run(), so both are
provided. They follow Qiskit's own semantics: one result per PUB, with parameter bindings
carried in the array shape.
from qiskit_zksf import ZKSFProvider
provider = ZKSFProvider()
# Sampler: outcome distributions
sampler = provider.sampler()
result = sampler.run([qc], shots=1000).result()
result[0].data.meas.get_counts()
result[0].metadata["error_info"] # the accuracy statement
# Estimator: expectation values
from qiskit.quantum_info import SparsePauliOp
estimator = provider.estimator()
result = estimator.run([(circuit, SparsePauliOp("ZZ"))]).result()
result[0].data.evs # the value
result[0].data.stds # the bound on it, not a guess
stds is not invented. Where the engine reports a measured bound it is passed through
unchanged, so an EstimatorV2 standard error means the same thing the protocol means.
provider.estimator() defaults to the Pauli propagation engine, which answers with an
expectation value directly and bounds it by the discarded coefficient mass.
Parameter sweeps cost money
A local primitive will evaluate a thousand parameter bindings without comment. Here every binding is a separate billed job, because the service has no batch endpoint yet, so a sweep is refused rather than silently charged:
sampler.run([(circuit, thousand_angles)])
# TooManyJobs: this run would submit 1000 separate billed jobs ...
Raise the limit deliberately when that is what you want:
provider.sampler(max_jobs_per_run=200)
Combining an observable array with a parameter sweep in one PUB is not supported. It raises rather than guessing a broadcast order, since guessing would mislabel every value returned.
Why this exists
Exact statevector simulation stops near 30 to 32 qubits, because state size grows as
2^n. Past that, every practical method is approximate: tensor networks truncate the
bond dimension, Pauli propagation truncates operator weight, real hardware substitutes
device noise for the ideal distribution.
Simulators do not normally tell you how much of the answer that cost you, even though
the error quantities exist inside the simulation. job.error_info() is that number.
{'protocol': 'ZCC-v0.1',
'method': 'MPS (quimb), measured discarded-weight bound',
'truncation_weight': 2.220446049250313e-16,
'error_bound': 2.1073424255447017e-08,
'certified': True,
'converged': True}
Any finished job can be minted into a public certificate that anyone can check without
an account, using zcc-verify. The protocols are
specified in a citable paper: doi.org/10.5281/zenodo.21851381.
Backends
| Backend | Engine | Qubits | Notes |
|---|---|---|---|
zksf_auto |
router picks | 128 | Default. Chooses the cheapest adequate engine |
zksf_exact_cpu |
exact.cpu |
30 | Exact statevector |
zksf_exact_gpu |
exact.gpu |
32 | Exact statevector on GPU, size-routed across two tiers |
zksf_mps |
mps.quimb.cpu |
128 | Tensor network, supports certified=True |
zksf_mps_aer |
mps.aer.cpu |
128 | Tensor network (Aer) |
zksf_clifford |
clifford |
5000 | Stabilizer, exact for Clifford circuits |
zksf_pauli |
pauli.cpu |
1024 | Heisenberg picture, needs an observable |
zksf_noisy |
noisy.cpu |
30 | Device noise model, supports mitigate=True |
zksf_rigetti |
qpu.rigetti |
108 | Rigetti Cepheus-1, real hardware |
zksf_ionq |
qpu.ionq |
36 | IonQ Forte-1, real hardware |
provider = ZKSFProvider()
provider.backends() # all of them
provider.backends(min_num_qubits=100) # only the ones that reach 100 qubits
provider.backends(hardware=True) # only real quantum processors
Qubit counts mirror the limits the service enforces, so a circuit too large for an
engine fails at transpile time instead of after a round trip. The stabilizer backend
advertises only Clifford gates, so the transpiler will not hand it a T gate that Stim
cannot represent.
Estimate before you spend
Qiskit has no equivalent concept, so this lives on the provider. It is free, instant, and the only way to learn that a circuit would be rejected without submitting it.
est = provider.estimate(qc, shots=1000)
print(est["engine"], est["predicted_cost_usd"], est["reason"])
Asking for a measured bound
By default an approximate run is checked by convergence: the circuit is simulated again at double the resource budget and the shift in outcome probabilities is reported. That is evidence of accuracy, not a bound.
certified=True asks the tensor-network engine for a stronger statement. It runs with
state renormalization disabled, so the final state's norm deficit equals the total weight
discarded across every truncation, read directly off the result rather than estimated.
job = provider.backend("zksf_mps").run(qc, shots=1000, certified=True)
job.error_info()["error_bound"]
Rejections are a feature
A simulation whose own error bound would be vacuous is refused rather than returned, and the refusal says what would make the circuit tractable.
from qiskit_zksf import JobRejected
try:
job.result()
except JobRejected as exc:
print(exc) # "intractable classically at this structure: ... Options: ..."
Notes and limits
- Several circuits become several jobs. The service has no batch endpoint yet, so
backend.run([qc1, qc2])submits them individually and each is billed separately. - No gradients. This is a cloud job queue with per-job billing, so parameter-shift differentiation through it would be expensive and slow. Use a local simulator for optimization loops and this for the runs whose accuracy you need to state.
- Hardware costs real money and queues in hours, not seconds. Call
estimate()first.
Links
- Documentation: zksf.org/docs
- Python SDK:
qsim-sdk - Certificate checker:
zcc-verify - Android app: Google Play
- Protocol paper: 10.5281/zenodo.21851381
Licence
MIT.
Release files for qiskit-zksf 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| qiskit_zksf-0.2.2.tar.gz | 22.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qiskit_zksf-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.3 kB
Release files / qiskit_zksf-0.2.2.tar.gz
| Download URL | qiskit_zksf-0.2.2.tar.gz |
|---|---|
| Size | 22.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6b4bf45f31eb6fbaa7490fe805cf4c5be5816d59bf3dd97d3f1aa6f949e789e4
|
|
BLAKE2b-256 checksum How to use checksums |
75fc94bd6770636a3dc813ff16d20014cc77e75a2c720c7875ffef2a4cf31c53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency logRelease files / qiskit_zksf-0.2.2-py3-none-any.whl
| Download URL | qiskit_zksf-0.2.2-py3-none-any.whl |
|---|---|
| Size | 16.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0198d7a6243c58536aa932eb22b9536a51a38acad7edfb9aa877f0f12cc15b1a
|
|
BLAKE2b-256 checksum How to use checksums |
9cfcf0c63f488f1f418ff8a3bc7d2e7b8ffcca758fd4def899b786a5a1fe96fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency log