Skip to main content

qiskit-zksf

CI PyPI Python License: MIT DOI

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

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)

Source distribution for qiskit-zksf 0.2.2
File Size Uploaded
qiskit_zksf-0.2.2.tar.gz 22.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for qiskit-zksf 0.2.2
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

0.3.0

2 release files

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page