Qx.Hardware (Qx - Quantum Computing Simulator v0.7.1)
View SourceExecute Qx circuits on real IBM Quantum hardware.
Orchestrates the full pipeline:
circuit → QASM → qxportal transpile → IBM submit → poll
↓
IBM results
↓
Qx.SimulationResultConfiguration
All entry points require a Qx.Hardware.Config, which carries portal
- IBM credentials and execution preferences (backend, shots,
optimization level). See
Qx.Hardware.Configfor details andQx.Hardware.Config.from_env/1for the environment-driven setup used inexamples/hardware/run_on_ibm.exs.
Privacy invariant
The portal token never reaches Qx.Hardware.Ibm, and the IBM API key
/ CRN never reach Qx.Hardware.Portal. The two clients read only
their own fields from the shared Qx.Hardware.Config struct.
Status callback
Pass :on_status in opts to receive pipeline events:
run(circuit, config, on_status: fn event -> Logger.debug(inspect(event)) end)Events (all atoms, allowlisted — Iron Law #1):
{:portal, :connecting}— emitted byconnect/1{:portal, :listing_backends}{:portal, :transpiling}{:ibm, :authenticating}{:ibm, :fetching_backend}{:ibm, :submitting}{:ibm, :job_started, job_id}—job_idis a binary{:ibm, :polling, status}—statusis a binary in["Queued", "Running", "Completed", "Cancelled", ...]{:ibm, :fetching_results}
Error returns
Every failure mode normalises to {:error, {stage, reason}}, where
stage is one of:
:config— config validation or measurement check failed:portal—/api/v1/meor/api/v1/transpilefailed:ibm_auth— IAM exchange or backend lookup failed:ibm_submit—POST /jobsfailed:ibm_poll— poll request failed (not the same as terminalFailed/Cancelled):ibm_poll_timeout— overall poll deadline exceeded:ibm_job_failed— IBM returned terminalFailed/Cancelled/Cancelled - Ran too long:ibm_results— results fetch / parse failed
Synchronous, blocking
run/3 and submit_qasm/3 block until the IBM job reaches a terminal
status. Hardware queues can take hours; callers that need to surface
progress should wire :on_status and/or run the call in a supervised
Task. The Livebook integration in kino_qx wraps this in a monitored
Task with a cancel button — non-Livebook callers must arrange their
own supervision if they need async cancel.
Summary
Functions
Cancels a running IBM job. Best-effort, synchronous.
Establishes a session with qxportal: fetches /api/v1/me, performs
the IBM IAM exchange, and lists the account's backends.
Lists IBM backends available to the configured account, populating
config.backends_list as a side product on the returned config.
Runs a quantum circuit on IBM hardware.
Same as run/3 but raises on failure.
Submits a hand-authored OpenQASM 3.0 program directly. Skips circuit → QASM conversion and the measurement pre-flight check (the caller owns the QASM).
Transpiles QASM or a circuit via qxportal, without submitting.
Types
@type opts() :: keyword()
Pipeline options accepted by run/3, submit_qasm/3, etc.
:on_status—(event -> any)callback; defaults to no-op.:shots— overrideconfig.shots.:timeout_ms— overall poll deadline; default 24h.:seed_transpiler— optional integer seed passed to the portal.:ibm/:portal— module overrides for test/stub injection.:sleep—(non_neg_integer -> any)override for the poll sleep (test hook).
@type stage() ::
:config
| :portal
| :ibm_auth
| :ibm_submit
| :ibm_poll
| :ibm_poll_timeout
| :ibm_job_failed
| :ibm_results
Functions
@spec cancel(String.t(), Qx.Hardware.Config.t(), opts()) :: :ok | error()
Cancels a running IBM job. Best-effort, synchronous.
@spec connect(Qx.Hardware.Config.t(), opts()) :: {:ok, Qx.Hardware.Config.t()} | error()
Establishes a session with qxportal: fetches /api/v1/me, performs
the IBM IAM exchange, and lists the account's backends.
Returns the same config with identity and backends_list
populated.
This is a discovery call — it is meant to be usable before a
backend has been chosen (the caller typically picks from the returned
backends_list). Therefore:
- if
config.backendis blank (nilor""), the backend membership check is skipped and the populated config is returned; - if
config.backendis set, it is validated against the fetchedbackends_listand aQx.Hardware.ConfigErroris returned when it is not available to the account (catches typos early).
Running a circuit still requires a chosen backend — run/3,
run!/3, and submit_qasm/3 reject a blank backend up front.
@spec list_backends(Qx.Hardware.Config.t(), opts()) :: {:ok, [String.t()], Qx.Hardware.Config.t()} | error()
Lists IBM backends available to the configured account, populating
config.backends_list as a side product on the returned config.
@spec run(Qx.QuantumCircuit.t(), Qx.Hardware.Config.t(), opts()) :: {:ok, Qx.SimulationResult.t()} | error()
Runs a quantum circuit on IBM hardware.
Exports the circuit to OpenQASM 3.0, hands it to the qxportal
transpiler, submits to IBM, polls until done, and reconstructs a
%Qx.SimulationResult{} from the returned counts.
The circuit MUST contain at least one measurement instruction; an
unmeasured circuit raises Qx.Hardware.NoMeasurementsError.
@spec run!(Qx.QuantumCircuit.t(), Qx.Hardware.Config.t(), opts()) :: Qx.SimulationResult.t()
Same as run/3 but raises on failure.
@spec submit_qasm(String.t(), Qx.Hardware.Config.t(), opts()) :: {:ok, Qx.SimulationResult.t()} | error()
Submits a hand-authored OpenQASM 3.0 program directly. Skips circuit → QASM conversion and the measurement pre-flight check (the caller owns the QASM).
opts[:num_bits] should be the number of classical bits in the
program; defaults to inferring from length(first sample) returned
by IBM.
@spec transpile(Qx.QuantumCircuit.t() | String.t(), Qx.Hardware.Config.t(), opts()) :: {:ok, String.t()} | error()
Transpiles QASM or a circuit via qxportal, without submitting.
Useful for inspecting the transpiled program before submission.