Qx.Hardware (Qx - Quantum Computing Simulator v0.8.0)

View Source

Execute Qx circuits on real IBM Quantum hardware.

Orchestrates the full pipeline:

circuit    QASM    qxportal transpile    IBM submit    poll
                                                 
                                            IBM results
                                                 
                                       Qx.SimulationResult

Configuration

All entry points require a Qx.Hardware.Config, which carries portal

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 by connect/1
  • {:portal, :listing_backends}
  • {:portal, :transpiling}
  • {:ibm, :authenticating}
  • {:ibm, :fetching_backend}
  • {:ibm, :submitting}
  • {:ibm, :job_started, job_id}job_id is a binary
  • {:ibm, :polling, status}status is 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/me or /api/v1/transpile failed
  • :ibm_auth — IAM exchange or backend lookup failed
  • :ibm_submitPOST /jobs failed
  • :ibm_poll — poll request failed (not the same as terminal Failed/Cancelled)
  • :ibm_poll_timeout — overall poll deadline exceeded
  • :ibm_job_failed — IBM returned terminal Failed / 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

Types

Pipeline options accepted by run/3, submit_qasm/3, etc.

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

error()

@type error() ::
  {:error,
   {stage(), term()}
   | Qx.Hardware.ConfigError.t()
   | Qx.Hardware.NoMeasurementsError.t()}

opts()

@type opts() :: keyword()

Pipeline options accepted by run/3, submit_qasm/3, etc.

  • :on_status(event -> any) callback; defaults to no-op.
  • :shots — override config.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).

stage()

@type stage() ::
  :config
  | :portal
  | :ibm_auth
  | :ibm_submit
  | :ibm_poll
  | :ibm_poll_timeout
  | :ibm_job_failed
  | :ibm_results

Functions

cancel(job_id, config, opts \\ [])

@spec cancel(String.t(), Qx.Hardware.Config.t(), opts()) :: :ok | error()

Cancels a running IBM job. Best-effort, synchronous.

connect(config, opts \\ [])

@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.backend is blank (nil or ""), the backend membership check is skipped and the populated config is returned;
  • if config.backend is set, it is validated against the fetched backends_list and a Qx.Hardware.ConfigError is 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.

list_backends(config, opts \\ [])

@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.

run(circuit, config, opts \\ [])

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.

run!(circuit, config, opts \\ [])

Same as run/3 but raises on failure.

submit_qasm(qasm, config, opts \\ [])

@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.

transpile(input, config, opts \\ [])

@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.