Getting Started¶
Generate config files¶
make generate-config
Locally run the server¶
uv sync --no-group qubex --no-dev
and then run the server:
make run
Running the server in a container¶
docker compose up device-gateway
Change Device Status¶
Change the device status "active"¶
make change-status-to-active
Change the device status "inactive"¶
make change-status-to-inactive
Change the device status "maintenance"¶
make change-status-to-maintenance
List all services¶
grpcurl -plaintext "[::]:51021" list
List all methods of a service¶
grpcurl -plaintext "[::]:51021" list qpu_interface.v1.QpuService
Get service status¶
grpcurl -plaintext "[::]:51021" qpu_interface.v1.QpuService.GetServiceStatus
Job Request¶
grpcurl -plaintext -d '{ "job_id": "test_job", "shots": 1000, "program": "OPENQASM 3;include \"stdgates.inc\";qubit[2] q;bit[2] c;rz(1.5707963267948932) q[0];sx q[0];rz(1.5707963267948966) q[0];cx q[0], q[1];c[0] = measure q[0];c[1] = measure q[1];" }' "[::]:51021" qpu_interface.v1.QpuService.CallJob
Device info request¶
grpcurl -plaintext "[::]:51021" qpu_interface.v1.QpuService.GetDeviceInfo
Generate device info¶
uv run src/device_gateway/tool/device_info_generator.py -c config/config.yaml
Qubex Integration¶
if you use QDash, please download the Qubex config file and generate the device topology.
Download Qubex Config¶
make download-qubex-config
Generate Device Topology¶
make generate-device-topology
Running the Qubex server in a container¶
docker compose up device-gateway-qubex
Development¶
Format code¶
make format
Run linting¶
make lint
Run tests¶
make test
Run all verification steps¶
make verify
Documentation¶
Lint documentation¶
make docs-lint
Build documentation¶
make docs-build
Serve documentation locally¶
make docs-serve
Backend Plugins¶
Device Gateway executes circuits through pluggable backends. A backend can be any importable Python class,
instantiated by the _target_ fully-qualified class path declared in backend_di_container.registry in
config.yaml. The DI container (from oqtopus-util) simply imports and
constructs whatever class _target_ points to.
A backend is a class that subclasses device_gateway.core.base_backend.BaseBackend and implements a single
required method:
def execute(self, program: str, shots: int = 1024) -> tuple[dict, str]:
...
execute() is fully responsible for parsing the incoming program, compiling it to the backend's native
representation, running it, and returning (counts, message). BaseBackend itself only provides shared,
backend-agnostic functionality (device topology/status loading, qubit label <-> index mapping); it does not
prescribe how a backend parses programs, represents circuits internally, or validates gate names.
Backends included with this repository¶
| Backend | _target_ |
Device type | Notes |
|---|---|---|---|
| Qulacs | device_gateway.plugins.qulacs.backend.QulacsBackend |
simulator |
State-vector simulator. |
| Qubex | device_gateway.plugins.qubex.backend.QubexBackend |
QPU |
Controls real superconducting hardware via the qubex library. |
Configuration¶
Configuration File¶
The configuration file is located at config/config.yaml.
The configuration file is loaded using oqtopus-util, which supports environment variable substitution with optional default values
using the ${VAR, default} syntax. If the environment variable is not set, the default value is used.
Backends are managed by oqtopus-util's DiContainer.
The backend_di_container configuration follows the DiContainer syntax defined by oqtopus-util.
The configuration file contains the following sections:
proto: The gRPC settings.max_workers: The maximum number of workers for the gRPC server.address: The address of the gRPC server.common_backend_settings: Common settings shared across all backends.device_info: The device information.device_id: The ID of the device. If omitted, derived from the device topology file.provider_id: The ID of the provider.max_qubits: The maximum number of qubits supported by the device. If omitted, derived from the device topology file.max_shots: The maximum number of shots supported by the device.
device_status_path: The path to the device status file.device_topology_json_path: The path to the device topology JSON file.default_backend: The backend to use. Available options are"qulacs"and"qubex". Required.backend_di_container: The dependency injection container configuration for backends.registry: The registry of available backends. Each entry has the following fields:_target_: The fully qualified class name of the backend.device_type: The device type ("simulator"or"QPU").config: The backend configuration (reference tocommon_backend_settings).plugin_config: Settings specific to this backend. For Qulacs, this is wheresupported_gatesgoes — the list of OpenQASM3 instruction names its compiler is allowed to execute (e.g.[x, sx, rz, cx, measure, barrier, delay]); optional — comment it out to disable gate-name validation entirely and allow any instruction the compiler recognizes. Qubex has nosupported_gatesentry — its native gate set is fixed in code, since it is dictated by the physical hardware rather than something a config file can turn on or off.plugin_configalso carries whatever else a backend itself needs (e.g. Qubex'schip_id,config_dir,params_dir,calib_note_path).
- Only the backend specified by
default_backendis instantiated. Other entries inregistryare ignored. For example, ifdefault_backend: qulacs, aqubexentry inregistrywill not be loaded.
Simulator Example¶
# gRPC settings
proto:
max_workers: 2
address: "localhost:51021"
# Common backend settings
common_backend_settings: &common_backend_settings
device_info:
# device_id: "qulacs"
provider_id: "oqtopus"
# max_qubits: 16
max_shots: 10000
device_status_path: config/device_status
device_topology_json_path: config/device_topology_sim.json
# Backend configuration
default_backend: qulacs # Available options: "qulacs", "qubex"
# Dependency Injection Container Configuration
backend_di_container:
registry:
# QulacsBackend settings
qulacs:
_target_: device_gateway.plugins.qulacs.backend.QulacsBackend
device_type: simulator
config: *common_backend_settings
plugin_config:
# Comment out supported_gates below to disable gate-name validation entirely.
supported_gates: [x, sx, rz, cx, measure, barrier, delay]
# QubexBackend settings
qubex:
_target_: device_gateway.plugins.qubex.backend.QubexBackend
device_type: QPU
config: *common_backend_settings
plugin_config:
chip_id: ${CHIP_ID, 64Q}
config_dir: ${CONFIG_DIR, "/app/qubex-config/{chip_id}/config"}
params_dir: ${PARAMS_DIR, "/app/qubex-config/{chip_id}/params"}
calib_note_path: ${CALIB_NOTE_PATH, "/app/qubex-config/{chip_id}/calibration/calib_note.json"}
configuration_mode: ${CONFIGURATION_MODE, "ge-cr-cr"} # Options: "ge-cr-cr", "ge-ef-cr"
shot_interval: ${SHOT_INTERVAL, 307200} # Interval between shots in ns
QPU Example¶
# gRPC settings
proto:
max_workers: 2
address: "localhost:51021"
# Common backend settings
common_backend_settings: &common_backend_settings
device_info:
# device_id: "qulacs"
provider_id: "oqtopus"
# max_qubits: 16
max_shots: 10000
device_status_path: config/device_status
device_topology_json_path: config/device_topology_sim.json
# Backend configuration
default_backend: qubex # Available options: "qulacs", "qubex"
# Dependency Injection Container Configuration
backend_di_container:
registry:
# QulacsBackend settings
qulacs:
_target_: device_gateway.plugins.qulacs.backend.QulacsBackend
device_type: simulator
config: *common_backend_settings
plugin_config:
# Comment out supported_gates below to disable gate-name validation entirely.
supported_gates: [x, sx, rz, cx, measure, barrier, delay]
# QubexBackend settings
qubex:
_target_: device_gateway.plugins.qubex.backend.QubexBackend
device_type: QPU
config: *common_backend_settings
plugin_config:
chip_id: ${CHIP_ID, 64Q}
config_dir: ${CONFIG_DIR, "/app/qubex-config/{chip_id}/config"}
params_dir: ${PARAMS_DIR, "/app/qubex-config/{chip_id}/params"}
calib_note_path: ${CALIB_NOTE_PATH, "/app/qubex-config/{chip_id}/calibration/calib_note.json"}
configuration_mode: ${CONFIGURATION_MODE, "ge-cr-cr"} # Options: "ge-cr-cr", "ge-ef-cr"
shot_interval: ${SHOT_INTERVAL, 307200} # Interval between shots in ns
configuration_mode selects the Qubex pulse configuration (ge-cr-cr or
ge-ef-cr). shot_interval sets the interval between shots in nanoseconds.
Both settings can be overridden with the CONFIGURATION_MODE and
SHOT_INTERVAL environment variables.